symmray.array_common ==================== .. py:module:: symmray.array_common .. autoapi-nested-parse:: Methods that apply to all Abelian symmetric arrays, regardless of backend. Classes ------- .. autoapisummary:: symmray.array_common.ArrayCommon Functions --------- .. autoapisummary:: symmray.array_common._is_squeeze_entry symmray.array_common._is_matched_axis_entry symmray.array_common._match_reshape_forward symmray.array_common._match_reshape_reverse symmray.array_common._absorb_squeeze_entries symmray.array_common._entries_to_reshape_args symmray.array_common.calc_reshape_args symmray.array_common.without symmray.array_common.parse_tensordot_axes symmray.array_common.maybe_keep_label Module Contents --------------- .. py:function:: _is_squeeze_entry(entry) .. py:function:: _is_matched_axis_entry(entry) .. py:function:: _match_reshape_forward(shape, subshapes, newshape, i_start, i_stop, j_start, j_stop) Match ``shape[i_start:i_stop]`` to ``newshape[j_start:j_stop]`` from left to right, returning target entries and the first unconsumed input axis. .. py:function:: _match_reshape_reverse(shape, subshapes, newshape, i_start, i_stop, j_start, j_stop) Match ``shape[i_start:i_stop]`` to ``newshape[j_start:j_stop]`` from right to left, returning target entries and the first consumed input axis. .. py:function:: _absorb_squeeze_entries(entries) Attach squeezed singleton axes to a neighbouring kept dimension. .. py:function:: _entries_to_reshape_args(entries, ndim_old) Convert target entries to unfuse/fuse/expand operation arguments. .. py:function:: calc_reshape_args(shape, newshape, subshapes) Given a current block sparse shape ``shape`` a target shape ``newshape`` and current sub index sizes ``subshapes`` (i.e. previously fused dimensions) compute the sequence of axes to unfuse, fuse and expand to reshape the array. A single ``-1`` entry in ``newshape`` is interpreted structurally: it consumes whichever input axes are not matched by the rest of the target shape (fusing them if there is more than one). This avoids the division-by-size resolution which can be ambiguous for sparse arrays whose fused-axis sizes do not equal the product of their subshape. :param shape: The current shape of the array. :type shape: tuple[int] :param newshape: The target shape of the array. May contain at most one ``-1``. :type newshape: tuple[int] :param subshapes: The sizes of the subindices that were previously fused. :type subshapes: tuple[None or tuple[int]] :returns: * **axs_unfuse** (*tuple[int]*) -- The axes to unfuse. * **axs_fuse** (*tuple[tuple[tuple[int]]]*) -- The axes (after unfusing) to fuse, grouped by contiguous groups. * **axs_expand** (*tuple[int]*) -- The axes (after unfusing and fusing) to expand. .. py:class:: ArrayCommon Common base class for all abelian arrays with symmetry, fermionic or not, sparse or flat etc. .. py:property:: symmetry :type: symmray.symmetries.Symmetry The symmetry object of the array. .. py:property:: indices :type: tuple[symmray.index_common.Index, Ellipsis] The indices of the array. .. py:method:: is_fused(ax: int) -> bool Does axis `ax` carry subindex information, i.e., is it a fused index? .. py:property:: duals :type: tuple[bool, Ellipsis] The dual-ness of each index. .. py:method:: get_class_symmetry(symmetry=None) -> symmray.symmetries.Symmetry :classmethod: .. py:property:: signature :type: str .. py:method:: __add__(other, inplace=False) .. py:method:: __iadd__(other) .. py:method:: __sub__(other, inplace=False) .. py:method:: __isub__(other) .. py:method:: __truediv__(other, inplace=False) .. py:method:: __itruediv__(other) .. py:method:: __pow__(other, inplace=False) .. py:property:: T :type: ArrayCommon The transpose of the block array. .. py:method:: _dagger_abelian(inplace=False) -> ArrayCommon Conjugate transpose or adjoint, implements the .H property. .. py:property:: H :type: ArrayCommon .. py:method:: fuse(*axes_groups, expand_empty=True, inplace=False, **kwargs) -> ArrayCommon Fuse the given group or groups of axes. The new fused axes will be inserted at the minimum index of any fused axis (even if it is not in the first group). For example, ``x.fuse([5, 3], [7, 2, 6])`` will produce an array with axes like:: groups inserted at axis 2, removed beyond that. ......<-- (0, 1, g0, g1, 4, 8, ...) | | | g1=(7, 2, 6) g0=(5, 3) The fused axes will carry subindex information, which can be used to automatically unfuse them back into their original components. Depending on `expand_empty`, any empty groups can be expanded to new singlet dimensions, or simply ignored. :param axes_groups: The axes to fuse. Each group of axes will be fused into a single axis. :type axes_groups: Sequence[Sequence[int]] :param expand_empty: Whether to expand empty groups into new axes. :type expand_empty: bool, optional :param mode: The method to use for fusing. `"insert"` creates the new fused blocks and insert the subblocks inplace. `"concat"` recursively concatenates the subblocks, which can be slightly slower but is more compatible with e.g. autodiff. `"auto"` will use `"insert"` if the backend is numpy, otherwise `"concat"`. :type mode: "auto", "insert", "concat", optional :param inplace: Whether to perform the operation inplace or return a new array. :type inplace: bool, optional :param kwargs: Additional keyword arguments to pass to the core fusing method. :type kwargs: dict, optional :rtype: ArrayCommon .. py:method:: unfuse_all(inplace=False) -> ArrayCommon Unfuse all indices that carry subindex information, likely from a fusing operation. :param inplace: Whether to perform the operation inplace or return a new array. :type inplace: bool, optional :rtype: ArrayCommon .. py:method:: reshape(newshape, inplace=False) -> ArrayCommon Reshape this abelian array to ``newshape``, assuming it can be done by any mix of fusing, unfusing, and expanding new axes. Restrictions and complications vs normal array reshaping arise from the fact that A) only previously fused axes can be unfused, and their total size may not be the product of the individual sizes due to sparsity. B) the indices carry information beyond size and how they are grouped potentially matters, relevant for singleton dimensions. Accordingly the approach here is as follows: 1. Unfuse any axes that match the new shape. 2. If there are singleton dimensions that don't appear in the new shape, (i.e. are being 'squeezed') these are grouped with the axis to the their left to then be fused. If they are already left-most, they are grouped with the right. 3. Fuse any groups of axes required to match the new shape. Adjacent groups are fused simultaneously for efficiency. 4. Expand new axes required to match singlet dimensions in the new shape. By default these will have zero charge and dual-ness iherited from whichever axis is to their left, or right if they are the left-most axis already. To avoid the effective grouping of 'squeezed' axes you can explicitly squeeze them before reshaping. Similarly use ``expand_dims`` to add new axes with specific charges and dual-ness. ``newshape`` may contain at most one ``-1`` entry, which is resolved structurally: it absorbs whichever input axes are not matched by the rest of the target shape (fusing them if there is more than one). This differs from numpy's division-based resolution and avoids ambiguity when fused-index sizes do not equal the product of their subshape due to sparsity. :param newshape: The new shape to reshape to. May contain at most one ``-1``. :type newshape: tuple[int] :param inplace: Whether to perform the operation inplace or return a new array. :type inplace: bool, optional :rtype: ArrayCommon .. seealso:: :py:obj:`fuse`, :py:obj:`unfuse`, :py:obj:`squeeze`, :py:obj:`expand_dims` .. py:method:: __getitem__(item) .. py:method:: take(indices, axis, inplace=False) .. py:method:: eigh_truncated(cutoff=-1.0, cutoff_mode='rsum2', max_bond=-1, absorb=0, renorm=False, positive=False, **kwargs) -> tuple[ArrayCommon, symmray.vector_common.VectorCommon, ArrayCommon] Truncated hermitian eigen-decomposition of this assumed hermitian array. :param cutoff: Absolute eigenvalue cutoff threshold. :type cutoff: float, optional :param cutoff_mode: How to perform the truncation: - 1 or 'abs': trim values below ``cutoff`` - 2 or 'rel': trim values below ``s[0] * cutoff`` - 3 or 'sum2': trim s.t. ``sum(s_trim**2) < cutoff``. - 4 or 'rsum2': trim s.t. ``sum(s_trim**2) < sum(s**2) * cutoff``. - 5 or 'sum1': trim s.t. ``sum(s_trim**1) < cutoff``. - 6 or 'rsum1': trim s.t. ``sum(s_trim**1) < sum(s**1) * cutoff``. :type cutoff_mode: int or str, optional :param max_bond: An explicit maximum bond dimension, use -1 for none. :type max_bond: int :param absorb: How to absorb the eigenvalues. - -1 or 'left': absorb into the left factor (U). - 0 or 'both': absorb the square root into both factors. - 1 or 'right': absorb into the right factor (VH). - None: do not absorb, return eigenvalues as a `VectorCommon`. :type absorb: {-1, 0, 1, None} :param renorm: Whether to renormalize the eigenvalues (depends on ``cutoff_mode``). :type renorm: {0, 1} :param positive: If True, assume all eigenvalues are positive for a faster sort. By default False. :type positive: bool, optional :returns: * **u** (*ArrayCommon*) -- The array of left eigenvectors. * **w** (*VectorCommon or None*) -- The vector of eigenvalues, or None if absorbed. * **uh** (*ArrayCommon*) -- The array of right eigenvectors. .. py:method:: svd(**kwargs) -> tuple[ArrayCommon, symmray.vector_common.VectorCommon, ArrayCommon] Singular value decomposition of this array. :returns: * **u** (*ArrayCommon*) -- The left singular vectors. * **s** (*VectorCommon*) -- The singular values. * **vh** (*ArrayCommon*) -- The right singular vectors (hermitian transposed). .. py:method:: svd_truncated(cutoff=0.0, cutoff_mode='rsum2', max_bond=None, absorb='both', renorm=False, **kwargs) -> tuple[ArrayCommon, symmray.vector_common.VectorCommon, ArrayCommon] Truncated singular value decomposition of this array. :param cutoff: Singular value cutoff threshold. :type cutoff: float, optional :param cutoff_mode: How to perform the truncation: - 1 or 'abs': trim values below ``cutoff`` - 2 or 'rel': trim values below ``s[0] * cutoff`` - 3 or 'sum2': trim s.t. ``sum(s_trim**2) < cutoff``. - 4 or 'rsum2': trim s.t. ``sum(s_trim**2) < sum(s**2) * cutoff``. - 5 or 'sum1': trim s.t. ``sum(s_trim**1) < cutoff``. - 6 or 'rsum1': trim s.t. ``sum(s_trim**1) < sum(s**1) * cutoff``. :type cutoff_mode: int or str, optional :param max_bond: An explicit maximum bond dimension, use -1 for none. :type max_bond: int :param absorb: How to absorb the singular values. - -1 or 'left': absorb into the left factor (U). - 0 or 'both': absorb the square root into both factors. - 1 or 'right': absorb into the right factor (VH). - None: do not absorb, return singular values as a `VectorCommon`. :type absorb: {-1, 0, 1, None} :param renorm: Whether to renormalize the singular values (depends on `cutoff_mode`). :type renorm: {0, 1} :returns: * **u** (*ArrayCommon or None*) -- The abelian array of left singular vectors. * **s** (*VectorCommon or None*) -- The vector of singular values, or None if absorbed. * **vh** (*ArrayCommon or None*) -- The abelian array of right singular vectors. .. py:method:: svd_via_eig(**kwargs) Singular value decomposition of this array, using eigen-decomposition of the Gram matrix (xdag @ x or x @ xdag). This can be faster, but also incur a loss of precision due to the squaring. .. py:method:: svd_via_eig_truncated(cutoff=0.0, cutoff_mode='rsum2', max_bond=None, absorb='both', renorm=False, **kwargs) Truncated singular value decomposition of this array, using eigen-decomposition of the gram matrix (xdag @ x or x @ xdag). This can be faster, but also incur a loss of precision due to the squaring. :param cutoff: Singular value cutoff threshold. :type cutoff: float, optional :param cutoff_mode: How to perform the truncation: - 1 or 'abs': trim values below ``cutoff`` - 2 or 'rel': trim values below ``s[0] * cutoff`` - 3 or 'sum2': trim s.t. ``sum(s_trim**2) < cutoff``. - 4 or 'rsum2': trim s.t. ``sum(s_trim**2) < sum(s**2) * cutoff``. - 5 or 'sum1': trim s.t. ``sum(s_trim**1) < cutoff``. - 6 or 'rsum1': trim s.t. ``sum(s_trim**1) < sum(s**1) * cutoff``. :type cutoff_mode: int or str, optional :param max_bond: An explicit maximum bond dimension, use -1 for none. :type max_bond: int :param absorb: How to absorb the singular values. - -1 or 'left': absorb into the left factor (U). - 0 or 'both': absorb the square root into both factors. - 1 or 'right': absorb into the right factor (VH). - None: do not absorb, return singular values as a `VectorCommon`. :type absorb: {-1, 0, 1, None} :param renorm: Whether to renormalize singular values (depends on `cutoff_mode`). :type renorm: {0, 1} :returns: * **u** (*ArrayCommon or None*) -- The abelian array of left singular vectors. * **s** (*VectorCommon or None*) -- The vector of singular values, or None if absorbed. * **vh** (*ArrayCommon or None*) -- The abelian array of right singular vectors. .. py:method:: svd_rand_truncated(max_bond, absorb=0, oversample=10, num_iterations=2, seed=None, **kwargs) -> tuple[ArrayCommon, symmray.vector_common.VectorCommon, ArrayCommon] Truncated singular value decomposition of this array, using randomized projection. This is efficient for low-rank approximations when a target ``max_bond`` is known. :param max_bond: Target rank / maximum bond dimension. :type max_bond: int :param absorb: How to absorb the singular values. - -1 or 'left': absorb into the left factor (U). - 0 or 'both': absorb the square root into both. - 1 or 'right': absorb into the right factor (VH). - None: do not absorb, return singular values. :type absorb: {-1, 0, 1, None} :param oversample: Extra sketch dimensions for accuracy. Default is 10. :type oversample: int, optional :param num_iterations: Number of power iterations for accuracy. Default is 2. :type num_iterations: int, optional :param seed: Random seed or generator for reproducibility. :type seed: int, Generator or None, optional :returns: * **u** (*ArrayCommon or None*) -- The abelian array of left singular vectors. * **s** (*VectorCommon or None*) -- The singular values, or None if absorbed. * **vh** (*ArrayCommon or None*) -- The abelian array of right singular vectors. .. py:method:: qr(absorb='right', stabilized=False, **kwargs) -> tuple[ArrayCommon, ArrayCommon] QR decomposition. :param x: The array to decompose. :type x: ArrayCommon :param absorb: Absorption mode: - ``Absorb.U_sVH`` (1, 'right'): return ``(Q, None, R)``. - ``Absorb.sVH`` (11, 'rfactor'): return ``(None, None, R)``. - ``Absorb.U`` (10, 'lorthog'): return ``(Q, None, None)``. :type absorb: int or str, optional :param stabilized: Whether to use a stabilized QR decomposition, that is, ensure positive diagonal elements in the R factor. Default is False. :type stabilized: bool, optional :returns: * **q** (*ArrayCommon*) -- The orthogonal matrix. * **r** (*ArrayCommon*) -- The right factor matrix. .. py:method:: qr_via_cholesky(absorb='right', shift=True, solve_triangular=True, **kwargs) -> tuple[ArrayCommon, None, ArrayCommon] QR decomposition of a this array via Cholesky factorization. By default (absorb="right") computes ``x = Q @ R`` where ``Q`` is isometric and ``R`` is upper triangular. LQ-like decompositions can be obtained with absorb="left" for example. :param absorb: Absorption mode: - ``Absorb.U_sVH`` (1, 'right'): return ``(Q, None, R)``. - ``Absorb.sVH`` (11, 'rfactor'): return ``(None, None, R)``. - ``Absorb.U`` (10, 'lorthog'): return ``(Q, None, None)``. :type absorb: int or str, optional :param shift: Diagonal regularization shift. If True or negative, auto-compute from dtype machine epsilon. The shift is always applied as a relative shift scaled by the trace of each block. Default is True. :type shift: float, optional :param solve_triangular: Whether to use triangular solve (faster) or general solve. Default is True. :type solve_triangular: bool, optional :returns: * **Q** (*ArrayCommon or None*) -- The isometric factor. * **s** (*None*) -- Always None. * **R** (*ArrayCommon or None*) -- The upper triangular factor. .. py:method:: lq(absorb='left', stabilized=False, **kwargs) -> tuple[ArrayCommon, ArrayCommon] LQ decomposition. :param stabilized: Whether to use a stabilized LQ decomposition, that is, with positive diagonal elements in the L factor. Default is False. :type stabilized: bool, optional :param absorb: Which factors to return in the output, by default 'Us_VH' (both). Options are: - "left" or "Us_VH": return (L, Q) - "lfactor" or "Us": return (L, None) - "rorthog" or "VH": return (None, Q) :type absorb: str or int, optional :returns: * **l** (*ArrayCommon*) -- The lower triangular matrix. * **q** (*ArrayCommon*) -- The orthogonal matrix. .. py:method:: lq_via_cholesky(absorb='left', shift=True, solve_triangular=True, **kwargs) -> tuple[ArrayCommon, None, ArrayCommon] LQ decomposition of a this array via Cholesky factorization of the Gram matrix ``x @ x^H``. By default (absorb="left") computes ``x = L @ Q`` where ``L`` is lower triangular and ``Q`` is isometric. :param absorb: Absorption mode: - ``Absorb.Us_VH`` (-1, 'left'): return ``(L, None, Q)``. - ``Absorb.Us`` (-10, 'lfactor'): return ``(L, None, None)``. - ``Absorb.VH`` (-11, 'rorthog'): return ``(None, None, Q)``. :type absorb: int or str, optional :param shift: Diagonal regularization shift. If True or negative, auto-compute from dtype machine epsilon. The shift is always applied as a relative shift scaled by the trace of each block. Default is True. :type shift: float, optional :param solve_triangular: Whether to use triangular solve (faster) or general solve to compute Q. Default is True. :type solve_triangular: bool, optional :returns: * **L** (*ArrayCommon or None*) -- The lower triangular factor. * **s** (*None*) -- Always None. * **Q** (*ArrayCommon or None*) -- The isometric factor. .. py:method:: __str__() .. py:method:: __repr__() .. py:function:: without(it, remove) Return a tuple of the elements in ``it`` with those at positions ``remove`` removed. .. py:function:: parse_tensordot_axes(axes, ndim_a, ndim_b) Parse the axes argument for single integer and also negative indices. Returning the 4 axes groups that can be used for fusing. .. py:function:: maybe_keep_label(label_a, label_b) Decide whether to keep labels from operands when combining two arrays. If both labels are the same, keep that. If only one is set, keep that. Otherwise return None.