Skip to content

Commit a5c8cbf

Browse files
committed
Add get_full_source
1 parent 5cbab08 commit a5c8cbf

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

src/torchjd/sparse/_structured_sparse_tensor.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,43 @@ def unwrap_to_dense(t: Tensor):
243243
return t
244244

245245

246+
def get_full_source(source: list[int], destination: list[int], ndim: int) -> list[int]:
247+
"""
248+
Doing a movedim with source and destination is always equivalent to doing a movedim with
249+
[0, 1, ..., ndim-1] (aka "full_destination") as destination, and the "full_source" as source.
250+
251+
This function computes the full_source based on a source and destination.
252+
253+
Example:
254+
source=[2, 4]
255+
destination=[0, 3]
256+
ndim=5
257+
258+
full_source = [2, 0, 1, 4, 3]
259+
full_destination = [0, 1, 2, 3, 4]
260+
"""
261+
262+
idx = torch.full((ndim,), -1, dtype=torch.int64)
263+
idx[destination] = tensor(source)
264+
source_set = set(source)
265+
idx[idx.eq(-1)] = tensor([i for i in range(ndim) if i not in source_set])
266+
267+
# source_mask = torch.zeros(ndim, dtype=torch.bool)
268+
# destination_mask = torch.zeros(ndim, dtype=torch.bool)
269+
# source_mask[source] = True
270+
# destination_mask[destination] = True
271+
#
272+
# destination_cumsum = torch.cumsum(destination_mask, dim=0)
273+
# source_cumsum = torch.cumsum(source_mask, dim=0)
274+
# base = arange(ndim, dtype=torch.int64)
275+
#
276+
# idx = torch.empty((ndim,), dtype=torch.int64)
277+
# idx[destination_mask] = tensor(source)
278+
# idx[~destination_mask] = base[~destination_mask] - destination_cumsum[~destination_mask] + source_cumsum[:ndim - len(source)]
279+
280+
return idx.tolist()
281+
282+
246283
def fix_dim_of_size_1(physical: Tensor, strides: Tensor) -> tuple[Tensor, Tensor]:
247284
is_of_size_1 = torch.tensor([s == 1 for s in physical.shape])
248285
return physical.squeeze(), strides[:, ~is_of_size_1]

tests/unit/sparse/test_structured_sparse_tensor.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
StructuredSparseTensor,
1616
fix_ungrouped_dims,
1717
fix_zero_stride_columns,
18+
get_full_source,
1819
get_groupings,
1920
)
2021

@@ -349,6 +350,26 @@ def test_unsquash_pdim(
349350
assert torch.equal(new_strides, expected_strides)
350351

351352

353+
@mark.parametrize(
354+
[
355+
"source",
356+
"destination",
357+
"ndim",
358+
],
359+
[
360+
([2, 4], [0, 3], 5),
361+
([5, 3, 6], [2, 0, 5], 8),
362+
],
363+
)
364+
def test_get_column_indices(source: list[int], destination: list[int], ndim: int):
365+
# TODO: this test should be improved / removed. It creates quite big tensors for nothing.
366+
367+
t = randn_(list(torch.randint(3, 8, size=(ndim,))))
368+
full_destination = list(range(ndim))
369+
full_source = get_full_source(source, destination, ndim)
370+
assert torch.equal(t.movedim(full_source, full_destination), t.movedim(source, destination))
371+
372+
352373
@mark.parametrize(
353374
["sst_args", "dim"],
354375
[

0 commit comments

Comments
 (0)