Skip to content

Commit 52f4104

Browse files
committed
Fix reverse key lookup
In the "match_gene_segment" function in _clonotype_neighbors, a "keys array" is created to map from indicies in the reverse lookup table (these refer to rows in the clonotype table) to numeric indices of the reverse lookup table. The size of this keys array was defined as the size of the clonotype table. Instead it should have been the size of the distance matrix. For real-world cases, this hardly was an issue, since the number of clonotypes is typically larger than the number of columns in the distance matrix.
1 parent a5e3730 commit 52f4104

2 files changed

Lines changed: 18 additions & 5 deletions

File tree

src/scirpy/ir_dist/_clonotype_neighbors.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ def AND_max(a, b):
329329
if distance_matrix_name != distance_matrix_name_reverse:
330330
raise ValueError("Forward and reverse lookup tablese must be defined on the same distance matrices.")
331331
reverse_lookup_values = np.vstack(list(reverse.lookup.values()))
332-
reverse_lookup_keys = np.zeros(reverse.size, dtype=np.int64)
332+
reverse_lookup_keys = np.zeros(reverse.dist_mat_size, dtype=np.int64)
333333
reverse_lookup_keys[list(reverse.lookup.keys())] = np.arange(len(list(reverse.lookup.keys())))
334334
match_column_mask = sp.csr_matrix(
335335
(np.empty(len(has_distance_mask.indices)), has_distance_mask.indices, has_distance_mask.indptr),
@@ -419,8 +419,8 @@ def match_gene_segment(
419419
raise ValueError("Forward and reverse lookup tablese must be defined on the same distance matrices.")
420420
empty_row = np.array([np.zeros(reverse.size, dtype=bool)])
421421
reverse_lookup_values = np.vstack((*reverse.lookup.values(), empty_row))
422-
reverse_lookup_keys = np.full(id_len, -1, dtype=np.int32)
423422
keys_array = np.fromiter(reverse.lookup.keys(), dtype=int, count=len(reverse.lookup))
423+
reverse_lookup_keys = np.full(reverse.dist_mat_size, -1, dtype=np.int32)
424424
reverse_lookup_keys[keys_array] = np.arange(len(keys_array))
425425
gene_segment_mask = sp.csr_matrix(
426426
(np.empty(len(has_distance_mask.indices)), has_distance_mask.indices, has_distance_mask.indptr),

src/scirpy/ir_dist/_util.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def reduce_and(*args, chain_count):
9393

9494

9595
class ReverseLookupTable:
96-
def __init__(self, dist_type: Literal["boolean", "numeric"], size: int):
96+
def __init__(self, dist_type: Literal["boolean", "numeric"], size: int, dist_mat: np.ndarray | sp.csr_matrix):
9797
"""Reverse lookup table holds a mask that indicates which objects
9898
are neighbors of an object with a given index `i`.
9999
@@ -113,18 +113,29 @@ def __init__(self, dist_type: Literal["boolean", "numeric"], size: int):
113113
Either `boolean` or `numeric`
114114
size
115115
The size of the masks.
116+
dist_mat
117+
A pointer to the associated distance matrix. This makes it easier to find the
118+
corresponding distance matrix from an instance of the ReverseLookupTable
116119
"""
117120
if dist_type not in ["boolean", "numeric"]:
118121
raise ValueError("invalid dist_type")
119122
self.dist_type = dist_type
120123
self.size = size
121124
self.lookup: dict[Hashable, sp.coo_matrix] = {}
125+
self.dist_mat = dist_mat
126+
127+
@property
128+
def dist_mat_size(self) -> int:
129+
assert self.dist_mat.shape is not None
130+
assert self.dist_mat.shape[0] == self.dist_mat.shape[1]
131+
return self.dist_mat.shape[0]
122132

123133
@staticmethod
124134
def from_dict_of_indices(
125135
dict_of_indices: Mapping,
126136
dist_type: Literal["boolean", "numeric"],
127137
size: int,
138+
dist_mat: np.ndarray | sp.csr_matrix,
128139
):
129140
"""Convert a dict of indices to a ReverseLookupTable of row masks.
130141
@@ -137,7 +148,7 @@ def from_dict_of_indices(
137148
size
138149
The size of the masks
139150
"""
140-
rlt = ReverseLookupTable(dist_type, size)
151+
rlt = ReverseLookupTable(dist_type, size, dist_mat)
141152

142153
# convert into coo matrices (numeric distances) or numpy boolean arrays.
143154
for k, v in dict_of_indices.items():
@@ -414,4 +425,6 @@ def _build_reverse_lookup_table(
414425
except KeyError:
415426
tmp_reverse_lookup[tmp_key] = [i]
416427

417-
return ReverseLookupTable.from_dict_of_indices(tmp_reverse_lookup, dist_type, self.n_cols)
428+
return ReverseLookupTable.from_dict_of_indices(
429+
tmp_reverse_lookup, dist_type, self.n_cols, self.distance_matrices[distance_matrix]
430+
)

0 commit comments

Comments
 (0)