Source code for ibl_bwb_eval.entity_ids

"""The ids a submission is aligned by, and how they reach a ``.safetensors`` file.

Ids travel as a uint8 matrix, one row per id, because safetensors holds tensors and not
strings. The row width is the tensor's own second dimension, so a file describes itself and
ids of any length round-trip: what a suite means by an entity (a unit today, a channel
later) never reaches this module. Shorter ids are padded with NUL, which ASCII ids cannot
contain, so a fixed-width batch pads to nothing and the padding is unambiguous.
"""

import numpy as np
import torch

__api_ref__ = {
    "description": None,
    "sections": [
        {"title": "Submission format", "autosummary": ["encode_entity_ids", "decode_entity_ids"]}
    ],
}

_PAD = b"\x00"


[docs] def encode_entity_ids(ids: np.ndarray) -> torch.Tensor: """Pack string ids into an (n, width) uint8 tensor, width being the longest id.""" rows = [s.encode("ascii") for s in np.asarray(ids).astype(str)] if not rows: raise ValueError("no ids to encode") if not all(rows): raise ValueError("ids must not be empty") out = np.zeros((len(rows), max(map(len, rows))), dtype=np.uint8) for i, row in enumerate(rows): out[i, : len(row)] = np.frombuffer(row, dtype=np.uint8) return torch.from_numpy(out)
[docs] def decode_entity_ids(tensor: torch.Tensor) -> np.ndarray: """Unpack what :func:`encode_entity_ids` wrote, dropping the padding.""" return np.array([row.tobytes().rstrip(_PAD).decode("ascii") for row in tensor.numpy()])