Skip to content
This repository was archived by the owner on Nov 7, 2024. It is now read-only.

Commit 1a82d4c

Browse files
mganahlChase Roberts
andauthored
add fromdense to BlockSparseTensor (#595)
* add fromdense * test added * *** empty log message *** Co-authored-by: Chase Roberts <chaseriley@google.com>
1 parent 6b02b0c commit 1a82d4c

2 files changed

Lines changed: 78 additions & 1 deletion

File tree

tensornetwork/block_sparse/blocksparsetensor.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import numpy as np
1919
from tensornetwork.block_sparse.index import Index
2020
# pylint: disable=line-too-long
21-
from tensornetwork.block_sparse.utils import _find_transposed_diagonal_sparse_blocks, _find_diagonal_sparse_blocks, flatten, get_flat_meta_data, compute_num_nonzero, _find_best_partition
21+
from tensornetwork.block_sparse.utils import _find_transposed_diagonal_sparse_blocks, _find_diagonal_sparse_blocks, flatten, get_flat_meta_data, compute_num_nonzero, _find_best_partition, reduce_charges
2222
from tensornetwork.block_sparse.charge import fuse_charges, BaseCharge, intersect, charge_equal
2323
import copy
2424
# pylint: disable=line-too-long
@@ -452,6 +452,48 @@ def copy(self) -> "BlockSparseTensor":
452452
self._flows.copy(), copy.deepcopy(self._order),
453453
False)
454454

455+
@classmethod
456+
def fromdense(cls, indices: List[Index],
457+
array: np.ndarray) -> "BlockSparseTensor":
458+
"""
459+
Initialize a BlockSparseTensor from a dense array.
460+
Args:
461+
indices: A list of `Index` objects.
462+
array: A numpy array.
463+
Returns:
464+
BlockSparseTensors: A Tensor initialized from the elements
465+
of `array` at the positions where `indices` fuse to
466+
the identity charge.
467+
"""
468+
shape = [i.dim for i in indices]
469+
if not np.array_equal(shape, array.shape):
470+
raise ValueError(
471+
f"Cannot initialize an BlockSparseTensor of shape {shape}"
472+
f" from an array of shape {array.shape}")
473+
tmp = np.append(0, np.cumsum([len(i.flat_charges) for i in indices]))
474+
order = [list(np.arange(tmp[n], tmp[n + 1])) for n in range(len(tmp) - 1)]
475+
476+
charges = []
477+
flows = []
478+
for i in indices:
479+
charges.extend(i.flat_charges)
480+
flows.extend(i.flat_flows)
481+
482+
_, locs = reduce_charges(
483+
charges=charges,
484+
flows=flows,
485+
target_charges=charges[0].identity_charges.unique_charges,
486+
return_locations=True)
487+
488+
ar = np.ravel(array)
489+
data = ar[locs]
490+
return cls(
491+
data=data,
492+
charges=charges,
493+
flows=flows,
494+
order=order,
495+
check_consistency=False)
496+
455497
def todense(self) -> np.ndarray:
456498
"""
457499
Map the sparse tensor to dense storage.

tensornetwork/block_sparse/blocksparsetensor_test.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,41 @@ def test_todense(num_charges, chargetype):
399399
np.testing.assert_allclose(dense[inds2], 0)
400400

401401

402+
@pytest.mark.parametrize('chargetype', ["U1", "Z2", "mixed"])
403+
@pytest.mark.parametrize('num_charges', [1, 2, 3])
404+
def test_fromdense(num_charges, chargetype):
405+
np.random.seed(10)
406+
Ds = [8, 9, 10, 11]
407+
rank = 4
408+
flows = np.random.choice([True, False], size=rank, replace=True)
409+
charges = [get_charge(chargetype, num_charges, Ds[n]) for n in range(rank)]
410+
fused = fuse_charges(charges, flows)
411+
mask = fused == np.zeros((num_charges, 1))
412+
inds = np.nonzero(mask)[0]
413+
inds2 = np.nonzero(np.logical_not(mask))[0]
414+
indices = [Index(charges[n], flows[n]) for n in range(rank)]
415+
416+
dense = np.random.random_sample(Ds)
417+
arr = BlockSparseTensor.fromdense(indices, dense)
418+
dense_arr = arr.todense()
419+
420+
np.testing.assert_allclose(np.ravel(dense)[inds], arr.data)
421+
np.testing.assert_allclose(np.ravel(dense_arr)[inds2], 0)
422+
423+
424+
def test_fromdense_raises():
425+
np.random.seed(10)
426+
Ds = [8, 9, 10, 11]
427+
rank = len(Ds)
428+
flows = np.random.choice([True, False], size=rank, replace=True)
429+
charges = [U1Charge.random(Ds[n], -5, 5) for n in range(rank)]
430+
indices = [Index(charges[n], flows[n]) for n in range(rank)]
431+
432+
dense = np.random.random_sample([8, 9, 9, 11])
433+
with pytest.raises(ValueError):
434+
_ = BlockSparseTensor.fromdense(indices, dense)
435+
436+
402437
@pytest.mark.parametrize('chargetype', ["U1", "Z2", "mixed"])
403438
@pytest.mark.parametrize('num_charges', [1, 2, 3])
404439
@pytest.mark.parametrize('op', [np.add, np.subtract])

0 commit comments

Comments
 (0)