diff --git a/docs/changelog.md b/docs/changelog.md index 8d689321..f1607372 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -9,6 +9,9 @@ Release notes for `quimb`. - expose [`qtn.edge_coloring`](quimb.tensor.tensor_arbgeom_tebd.edge_coloring) as top level function and allow layers to be returned grouped. - add docstring for [`tn.contract_compressed`](quimb.tensor.tensor_core.TensorNetwork.contract_compressed) +- add [`Tensor.rand_reduce`](quimb.tensor.tensor_core.Tensor.rand_reduce) for randomly removing a tensor index by contracting a random vector into it. One can also supply the value `"r"` to `isel` selectors to use this. + +--- (whats-new-1-8-4)= @@ -19,6 +22,8 @@ Release notes for `quimb`. - fix for MPS sampling with fixed seed ({issue}`247` and {pull}`248`) - fix for `mps_gate_with_mpo_lazy` ({issue}`246`). +--- + (whats-new-1-8-3)= ## v1.8.3 (2024-07-10) @@ -31,6 +36,8 @@ Release notes for `quimb`. - add [`edges_1d_chain`](quimb.tensor.geometry.edges_1d_chain) for generating 1D chain edges - [operatorbuilder](quimb.experimental.operatorbuilder): better coefficient placement for long range MPO building +--- + (whats-new-1-8-2)= ## v1.8.2 (2024-06-12) @@ -48,6 +55,9 @@ Release notes for `quimb`. - [`approx_spectral_function`](quimb.linalg.approx_spectral.approx_spectral_function) add plotting and tracking - add dispatching to various tensor primitives to allow overriding +--- + + (whats-new-1-8-1)= ## v1.8.1 (2024-05-06) @@ -76,6 +86,9 @@ Release notes for `quimb`. - fix for retrieving `opt_einsum.PathInfo` for single scalar contraction ({issue}`231`) +--- + + (whats-new-1-8-0)= ## v1.8.0 (2024-04-10) @@ -160,6 +173,9 @@ Release notes for `quimb`. - fix autoblock bug where connected sectors were not being merged ({issue}`223`) +--- + + (whats-new-1-7-3)= ## v1.7.3 (2024-02-08) @@ -173,6 +189,9 @@ Release notes for `quimb`. - restore fallback (to `scipy.linalg.svd` with driver='gesvd') behavior for truncated SVD with numpy backend. +--- + + (whats-new-1-7-2)= ## v1.7.2 (2024-01-30) @@ -186,6 +205,9 @@ Release notes for `quimb`. - removed import of deprecated `numba.generated_jit` decorator. +--- + + (whats-new-1-7-1)= ## v1.7.1 (2024-01-30) @@ -219,6 +241,9 @@ Release notes for `quimb`. - fix bug in quantum discord computation when the state was diagonal ({issue}`217`) +--- + + (whats-new-1-7-0)= ## v1.7.0 (2023-12-08) @@ -269,6 +294,9 @@ Release notes for `quimb`. performing tensor network simplifications. +--- + + (whats-new-1-6-0)= ## v1.6.0 (2023-09-10) @@ -293,6 +321,9 @@ Release notes for `quimb`. - fix gauge size check for some backends +--- + + (whats-new-1-5-1)= ## v1.5.1 (2023-07-28) @@ -313,6 +344,9 @@ Release notes for `quimb`. - fix for {meth}`gate_with_auto_swap` for `i > j`. - fix bug where calling `tn.norm()` would mangle indices. +--- + + (whats-new-1-5-0)= ## v1.5.0 (2023-05-03) @@ -377,6 +411,9 @@ Release notes for `quimb`. - fix {func}`~quimb.tensor.decomp.qr_stabilized` bug for strictly upper triangular R factors. +--- + + (whats-new-1-4-2)= ## v1.4.2 (2022-11-28) @@ -385,6 +422,9 @@ Release notes for `quimb`. - move from versioneer to to [setuptools_scm](https://pypi.org/project/setuptools-scm/) for versioning +--- + + (whats-new-1-4-1)= ## v1.4.1 (2022-11-28) @@ -418,6 +458,9 @@ Release notes for `quimb`. > - fix force atlas 2 and `weight_attr` bug ({issue}`126`) > - allow unpickling of `PTensor` objects ({issue}`128`, {pull}`131`) +--- + + (whats-new-1-4-0)= ## v1.4.0 (2022-06-14) @@ -437,6 +480,9 @@ Release notes for `quimb`. - Various memory and performance improvements - Various graph generators and TN builders +--- + + (whats-new-1-3-0)= ## v1.3.0 (2020-02-18) @@ -473,6 +519,9 @@ Release notes for `quimb`. - Add environment variable `QUIMB_NUMBA_PAR` to set whether numba should use automatic parallelization - mainly to fix travis segfaults. - Make cache import and initilization of `petsc4py` and `slepc4py` more robust. +--- + + (whats-new-1-2-0)= ## v1.2.0 (2019-06-06) diff --git a/quimb/tensor/tensor_core.py b/quimb/tensor/tensor_core.py index e3bcf8ef..982d7ab2 100644 --- a/quimb/tensor/tensor_core.py +++ b/quimb/tensor/tensor_core.py @@ -1626,8 +1626,15 @@ def isel(self, selectors, inplace=False): Parameters ---------- - selectors : dict[str, int], dict[str, slice] - Mapping of index(es) to which value to take. + selectors : dict[str, int or slice or "r"] + Mapping of index(es) to which value to take. The values can be: + + - int: select a specific value for that index. + - slice: select a range of values for that index. + - "r": contract a random vector in. + + The mapping can contain indices that don't appear on this tensor, + in which case they are ignored. inplace : bool, optional Whether to select inplace or not. @@ -1643,18 +1650,29 @@ def isel(self, selectors, inplace=False): See Also -------- - TensorNetwork.isel + TensorNetwork.isel, Tensor.rand_reduce """ T = self if inplace else self.copy() - new_inds = tuple( - ix - for ix in self.inds - if (ix not in selectors) or isinstance(selectors[ix], slice) - ) + new_inds = [] + data_loc = [] - data_loc = tuple(selectors.get(ix, slice(None)) for ix in self.inds) - T.modify(apply=lambda x: x[data_loc], inds=new_inds, left_inds=None) + for ix in T.inds: + sel = selectors.get(ix, slice(None)) + if isinstance(sel, slice): + # index will be kept (including a partial slice of entries) + new_inds.append(ix) + data_loc.append(sel) + elif sel == "r": + # eagerly remove any 'random' selections + T.rand_reduce_(ix) + else: + # index will be removed by selecting a specific index + data_loc.append(sel) + + T.modify( + apply=lambda x: x[tuple(data_loc)], inds=new_inds, left_inds=None + ) return T isel_ = functools.partialmethod(isel, inplace=True) @@ -2200,6 +2218,22 @@ def vector_reduce(self, ind, v, inplace=False): vector_reduce_ = functools.partialmethod(vector_reduce, inplace=True) + def rand_reduce(self, ind, dtype=None, inplace=False, **kwargs): + """Contract the index ``ind`` of this tensor with a random vector, + removing it. + + Parameters + ---------- + """ + if dtype is None: + dtype = self.dtype + + v = randn(self.ind_size(ind), dtype=self.dtype, **kwargs) + + return self.vector_reduce(ind, v, inplace=inplace) + + rand_reduce_ = functools.partialmethod(rand_reduce, inplace=True) + def collapse_repeated(self, inplace=False): """Take the diagonals of any repeated indices, such that each index only appears once. @@ -7983,8 +8017,13 @@ def isel(self, selectors, inplace=False): Parameters ---------- - selectors : dict[str, int] - Mapping of index(es) to which value to take. + selectors : dict[str, int or slice or "r"] + Mapping of index(es) to which value to take. The values can be: + + - int: select a specific value for that index. + - slice: select a range of values for that index. + - "r": contract a random vector in. + inplace : bool, optional Whether to select inplace or not. diff --git a/tests/test_tensor/test_tensor_core.py b/tests/test_tensor/test_tensor_core.py index f9877e74..bf6950cb 100644 --- a/tests/test_tensor/test_tensor_core.py +++ b/tests/test_tensor/test_tensor_core.py @@ -1909,6 +1909,15 @@ def test_gen_inds_connected(self): patches = tuple(tn.gen_inds_connected(2)) assert len(patches) == 34 + def test_tn_isel_rand(self): + mps = qtn.MPS_rand_state(6, 7) + ramp = mps.isel({mps.site_ind(i): "r" for i in mps.sites}) + assert ramp.outer_inds() == () + # check we haven't selected an computation basis amplitude + rx = ramp.contract() + xs = mps.to_dense().ravel() + assert not any(np.allclose(rx, x) for x in xs) + class TestTensorNetworkSimplifications: def test_rank_simplify(self):