def build_table(x,
                perceiver,
                cache,
                cache_emb,
                topk,
                return_images=False,
                index_dir=None):
    """
    Maps each image to a linearized row in a table. Each entry in a row
    is delimited by "|". Each entry comes from the topk results in the cache
    as determined by cosine similarity in CLIP space.
    """
    table = []
    x = perceiver.encode_image(x).float()
    x /= x.norm(dim=-1, keepdim=True)
    if index_dir:
        indices = cache_emb.search(x.cpu().numpy(), topk)[1]
        for idx in range(len(x)):
            row = ''
            results = [cache[i] for i in indices[idx]]
            for r in results:
                row += r + ' | '
            table.append(row)
    else:
        #print(x.shape)
        #print(cache_emb.shape)
        ipt = 100.0 * x.float() @ cache_emb.T.float()
        similarity = (ipt).softmax(dim=-1)
        for idx in range(len(x)):
            row = ''
            values, indices = similarity[idx].topk(topk)
            for _, index in zip(values, indices):
                row += cache[index] + ' | '
            table.append(row)
    if return_images:
        return table, x
    return table