symmray.flat.flat_array_common ============================== .. py:module:: symmray.flat.flat_array_common .. autoapi-nested-parse:: Methods that apply to abelian arrays with flat backend, both fermionic and simply abelian (bosonic). Classes ------- .. autoapisummary:: symmray.flat.flat_array_common.FlatArrayCommon Functions --------- .. autoapisummary:: symmray.flat.flat_array_common.einops_rearrange symmray.flat.flat_array_common.lexsort_sectors symmray.flat.flat_array_common.zn_combine symmray.flat.flat_array_common._calc_fused_sectors_subkeys_slice symmray.flat.flat_array_common._calc_fused_sectors_subkeys_create symmray.flat.flat_array_common._calc_fuse_rearrange_pattern symmray.flat.flat_array_common.truncate_svd_result_flat symmray.flat.flat_array_common.tensordot_flat_fused symmray.flat.flat_array_common.tensordot_flat_direct symmray.flat.flat_array_common.tensordot_abelian_flat symmray.flat.flat_array_common.print_charge_fusions symmray.flat.flat_array_common.build_cyclic_keys_all symmray.flat.flat_array_common.build_cyclic_keys_conserve symmray.flat.flat_array_common.build_cyclic_keys_by_charge Module Contents --------------- .. py:function:: einops_rearrange(tensor, *args, **kwargs) .. py:function:: lexsort_sectors(sectors, order=None, stable=True) Given a sequence of columns of positive integers, or equivalently a matrix of shape (num_sectors, num_charges), find the indices that sort them lexicographically, such that the first column is the most significant, then the second, and so forth. :param sectors: The sectors to sort, each column should be a 1D array of positive integer charges. Either supplied as a 2D array, or a sequence of 1D arrays (columns of charges), in which case they will be stacked along a second axis. :type sectors: array_like or sequence[array_like] :param order: The order of the symmetry group, which specifies the largest possible charge. Default is None, in which case no symmetry-based optimization is applied. :type order: int, optional :param stable: Whether to use a stable sort. Default is True, which uses the `argsort` function with the `stable` parameter set to True. If False, it will use the default sorting behavior which may not be stable. :type stable: bool, optional :returns: The indices that would sort the stack of sectors lexicographically. :rtype: array_like .. rubric:: Examples >>> sectors = np.array([[4, 1, 0], [3, 2, 1], [3, 1, 0], [2, 0, 1]]) >>> k = lexsort_sectors(sectors) >>> sectors[k] array([[2, 0, 1], [3, 1, 0], [3, 2, 1], [4, 1, 0]]) .. py:function:: zn_combine(order, sectors, duals=None, like=None) Implement vectorized addition modulo group order, with signature. :param order: The order of the symmetry group, i.e., the number of distinct charges in each axis. E.g. 2 corresponds to Z2 symmetry. :type order: int :param sectors: The stack of sectors, with shape (num_blocks, num_charges). Each row represents a subsector. :type sectors: array_like :param duals: The dualness of each index, i.e., whether the charge contributes positively or negatively. If not given, it will be assumed that all charges are positive. :type duals: sequence[bool] | None, optional :param like: The array-like object to use as a reference for the output type and backend. If not given, will be inferred.. :type like: str or array_like, optional .. py:function:: _calc_fused_sectors_subkeys_slice(num_groups, axes_groups, new_sectors, old_sectors, pos, ndim, new_ndim, order, group_singlets, backend) Calculate new sectors and group subkeys, by slicing the existing sectors. .. py:function:: _calc_fused_sectors_subkeys_create(unmerged_batch_sizes, num_groups, axes_groups, new_sectors, old_sectors, group_duals, ndim, order, duals, like) Calculate new sectors and group subkeys, by explicit generation. .. py:function:: _calc_fuse_rearrange_pattern(num_groups, axes_groups, axes_before, axes_after, axes_ncharges, ndim) .. py:class:: FlatArrayCommon .. py:method:: _init_abelian(sectors, blocks, indices, symmetry=None, label=None) .. py:method:: _check_abelian() .. py:method:: _new_with_abelian(sectors, blocks, indices, label=None) .. py:method:: _copy_abelian(deep=False) -> FlatArrayCommon Create a copy of the array. .. py:method:: _copy_with_abelian(sectors=None, blocks=None, indices=None) -> FlatArrayCommon A copy of this flat array with some attributes replaced. Note that checks are not performed on the new properties, this is intended for internal use. .. py:method:: _modify_abelian(sectors=None, blocks=None, indices=None) -> FlatArrayCommon Modify this flat array in place with some attributes replaced. Note that checks are not performed on the new properties, this is intended for internal use. .. py:method:: _set_params_abelian(params) Set the underlying array blocks. .. py:method:: _to_pytree_abelian() .. py:property:: order :type: int Get the order of the symmetry group. .. py:property:: label The label of the array, possibly used for ordering odd parity fermionic modes. .. py:property:: charge Compute the overall charge of the array. .. py:property:: shape :type: tuple[int, Ellipsis] Get the effective shape of the array. .. py:property:: size :type: int Get the total size of the array, i.e., the product of all dimensions in the effective shape. .. py:method:: from_scalar(x, symmetry=None) -> FlatArrayCommon :classmethod: Create a flat abelian array from a scalar. .. py:method:: _to_blocksparse_abelian(**kwargs) -> symmray.sparse.sparse_abelian_array.AbelianArray Create a blocksparse abelian array from this flat abelian array. .. py:method:: _to_dense_abelian() .. py:method:: _map_blocks_abelian(fn_sector=None, fn_block=None) .. py:method:: get_sorting_indices(axes=None, all_axes=None) Get the indices that would lexicgraphically sort the stack of sectors according to the values of charges in the specified axes, optionally filling in the rest of the axes with the remaining axes in the order they appear. :param axes: The axes to sort by. If a single integer is given, it will be interpreted as the axis to sort by. If a tuple of integers is given, it will be interpreted as the axes to sort by in order. Default is None, if all_axes is also None or True, this will sort all axes in their current order. :type axes: int | tuple[int, ...], optional :param all_axes: Whether to include all non-specified axes as tie-breakers, after the specified axes. If ``None``, the default, this will be True if `axes` is not supplied explicitly, and False otherwise. :type all_axes: bool, optional .. py:method:: _transpose_abelian(axes=None, inplace=False) -> FlatArrayCommon Transpose this flat abelian array. :param axes: A permutation of the axes to transpose the array by. If None, the axes will be reversed. :type axes: tuple[int, ...] | None, optional :param inplace: Whether to perform the operation inplace or return a new array. :type inplace: bool, optional :rtype: FlatArrayCommon .. py:method:: _conj_abelian(inplace=False) -> FlatArrayCommon Return the complex conjugate of this block array, including the indices and any subindex fusing information. :param inplace: Whether to perform the operation inplace or return a new array. :type inplace: bool, optional :rtype: FlatArrayCommon .. py:method:: expand_dims(axis, c=None, dual=None, inplace=False) -> FlatArrayCommon Expand the shape of an abelian array. :param axis: The position along which to expand. :type axis: int :param c: The charge to insert at the new axis. If not given, a zero charge will be inserted. :type c: hashable, optional :param dual: The dual-ness of the new index. If not given, it will be inherited from the axis before or after, if any. If there is no axis before or after, it will default to `False`. :type dual: bool, optional :param inplace: Whether to perform the operation inplace. :type inplace: bool, optional :rtype: FlatArrayCommon .. py:method:: _fuse_core_abelian(*axes_groups, mode='auto', inplace=False) -> FlatArrayCommon The core implementation of the fuse operation, which fuses multiple axes into a single group, and returns a new array with the new sectors and blocks. The new axes are inserted at the minimum axis of any of the groups. .. py:method:: _unfuse_abelian(axis, inplace=False) .. py:method:: select_charge(axis, charge, subselect=None, inplace=False) Drop all but the specified charge along the specified axis. Note the axis is not removed, it is simply restricted to a single charge. :param axis: The axis along which to select the charge. :type axis: int :param charge: The charge to select along the specified axis. :type charge: int :param subselect: If provided, a range of indices within the selected charge block to keep. If not provided, the entire block is kept. :type subselect: slice or array_like, optional :param inplace: Whether to perform the operation inplace or return a new array. :type inplace: bool, optional :rtype: FlatArrayCommon .. py:method:: _squeeze_abelian(axis=None, inplace=False) Squeeze the flat array, removing axes of size 1. :param axis: The axes to squeeze. If not given, all axes of size 1 will be removed. :type axis: int or sequence of int, optional :param inplace: Whether to perform the operation inplace. :type inplace: bool, optional :rtype: FlatArrayCommon .. py:method:: isel(axis, idx, inplace=False) Select a single (linear) index along the specified axis. The linear index is first converted to the corresponding charge and offset within that charge sector. :param axis: The axis to select along. :type axis: int :param idx: The linear index to select. :type idx: int :param inplace: Whether to perform the operation inplace or return a new array. :type inplace: bool, optional .. py:method:: align_axes(other: FlatArrayCommon, axes: tuple[tuple[int, Ellipsis], tuple[int, Ellipsis]], inplace=False) -> tuple[FlatArrayCommon, FlatArrayCommon] Align the axes of two arrays for contraction. .. py:method:: _tensordot_inner_abelian(other, axes_a, axes_b, preserve_array=False) Perform the tensor inner product of two flat abelian arrays along the specified axes. :param other: The other array to contract with. :type other: FlatArrayCommon :param axes_a: The axes of this array to contract along. :type axes_a: tuple[int, ...] :param axes_b: The axes of the other array to contract along. :type axes_b: tuple[int, ...] :param preserve_array: Whether to always return an array, even if the result is a scalar. :type preserve_array: bool, optional :returns: The result of the contraction, either as a scalar if `preserve_array=False` or else a new flat abelian array. :rtype: array_like | FlatArrayCommon .. py:method:: _tensordot_outer_abelian(other: FlatArrayCommon) -> FlatArrayCommon Perform the tensor outer product of two flat abelian arrays. :param other: The other array to contract with. :type other: FlatArrayCommon :rtype: FlatArrayCommon .. py:method:: _trace_abelian() Compute the trace of the flat array, assuming it is a square matrix. .. py:method:: _einsum_abelian(eq, preserve_array=False) :abstractmethod: .. py:method:: _tensordot_abelian(other, axes=2, mode='auto', preserve_array=False) .. py:method:: _matmul_abelian(other: FlatArrayCommon, preserve_array=False) .. py:method:: multiply_diagonal(v: symmray.flat.flat_vector.FlatVector, axis, power=1, inplace=False) Multiply this flat array by a vector as if contracting a diagonal matrix along the given axis. :param v: The vector to contract with. :type v: FlatVector :param axis: The axis along which to contract. :type axis: int :param inplace: Whether to perform the operation inplace. :type inplace: bool, optional :rtype: FlatArrayCommon .. py:method:: ldmul(v, inplace=False) .. py:method:: rdmul(v, inplace=False) .. py:method:: lddiv(v, inplace=False) .. py:method:: rddiv(v, inplace=False) .. py:method:: _allclose_abelian(other: FlatArrayCommon, **allclose_opts) -> bool Check if two flat abelian arrays are equal to within some tolerance, including their sectors and signature. .. py:method:: _test_allclose_abelian(other: FlatArrayCommon, **allclose_opts) Assert that this ``FlatArayCommon`` is close to another, that is, has all the same sectors, and the corresponding arrays are close. Unlike `allclose`, this raises an AssertionError with details if not. :param other: The other array to compare to. :type other: FlatArayCommon :param allclose_opts: Keyword arguments to pass to `allclose`. :raises AssertionError: If the arrays are not close. .. py:method:: _split_abelian(*, fn=None, charge_side='auto', **kwargs) Main driver method for decomposing flat abelian arrays. This handles mapping the split function over the blocks, and then wrapping the output blocks back into new FlatArray objects. :param fn: A custom function to perform the split on each block, which should take a stack of matrices and return a tuple of (left_stack, s_stack, right_stack) arrays. If not given, :func:`quimb.tensor.array_split` will be used. :type fn: callable, optional :param charge_side: Which side the array charge and label should be associated with. If "auto", it will be chosen based on the value of `absorb` to be the isometric side (e.g. "right" for LQ-like absorb="left") else "left" by default. :type charge_side: {"left", "right", "auto"}, optional :param kwargs: Additional keyword arguments to pass to the split function. :returns: * **left** (*FlatArrayCommon or None*) -- The left factor, if any. * **s** (*FlatVector or None*) -- The singular (or possibly eigen) values, if any. * **right** (*FlatArrayCommon or None*) -- The right factor, if any. .. py:method:: _cholesky_abelian(upper=False, shift=True, **kwargs) -> FlatArrayCommon Cholesky decomposition of a 2D flat abelian array. :param upper: Whether to return the upper triangular Cholesky factor. Default is False, returning the lower triangular factor. :type upper: bool, 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 :returns: **l_or_r** -- The Cholesky factor. :rtype: FlatArrayCommon .. py:method:: _eigh_abelian() -> tuple[FlatArrayCommon, symmray.flat.flat_vector.FlatVector] .. py:function:: truncate_svd_result_flat(U: FlatArrayCommon, s: symmray.flat.flat_vector.FlatVector, VH: FlatArrayCommon, cutoff: float, cutoff_mode: int, max_bond: int, absorb: int, renorm: int) .. py:function:: tensordot_flat_fused(a: FlatArrayCommon, b: FlatArrayCommon, left_axes: tuple[int, Ellipsis], axes_a: tuple[int, Ellipsis], axes_b: tuple[int, Ellipsis], right_axes: tuple[int, Ellipsis], preserve_array=False) .. py:function:: tensordot_flat_direct(a: FlatArrayCommon, b: FlatArrayCommon, left_axes: tuple[int, Ellipsis], axes_a: tuple[int, Ellipsis], axes_b: tuple[int, Ellipsis], right_axes: tuple[int, Ellipsis], preserve_array=False) Contract two flat abelian arrays without fusing. .. py:function:: tensordot_abelian_flat(a: FlatArrayCommon, b: FlatArrayCommon, axes=2, mode='auto', preserve_array=False) Contract two flat abelian arrays along the specified axes. .. py:function:: print_charge_fusions(keys, duals, axes_groups) .. py:function:: build_cyclic_keys_all(ndim, order=2, flat=False, like=None) For cyclic group of order `order`, build all possible subkeys of length `ndim`, in lexicographic order. :param ndim: The number of sub charges to build keys for. :type ndim: int :param order: The order of the cyclic group, i.e., the number of distinct charges. Default is 2, which corresponds to the Z2 group. :type order: int, optional :param flat: Whether to flatten the keys into a 2D array. If True, the output will be a 2D array of shape (order ** ndim, ndim). If False, the output will be a multi-dimensional array of shape `(order,) * ndim + (ndim,)`. Default is False. :type flat: bool, optional :param like: If provided, the output will be created with the same backend as this array. If None, the output will be created with the default backend, which is usually `numpy`. :type like: array_like, optional :returns: An array of shape (order ** ndim, ndim) or (order, order, ..., order, ndim) depending on the `flat` parameter. :rtype: array_like .. py:function:: build_cyclic_keys_conserve(ndim, order=2, charge=0, duals=None, flat=False, like=None) For cyclic group of order `order`, build all possible subkeys of length `ndim` with overall charge `charge`, in lexicographic order. :param ndim: The number of sub charges to build keys for. :type ndim: int :param order: The order of the cyclic group, i.e., the number of distinct charges. Default is 2, which corresponds to the Z2 group. :type order: int, optional :param flat: Whether to flatten the keys into a 2D array. If True, the output will be a 2D array of shape (order ** (ndim - 1), ndim). If False, the output will be a multi-dimensional array of shape `(order,) * (ndim - 1) + (ndim,)`.. Default is False. :type flat: bool, optional :param like: If provided, the output will be created with the same backend as this array. If None, the output will be created with the default backend, which is usually `numpy`. :type like: array_like, optional :returns: An array of shape (order ** (ndim - 1), ndim) or (order,) * (ndim - 1) + (ndim,) depending on the `flat` parameter. :rtype: array_like .. py:function:: build_cyclic_keys_by_charge(ndim, order=2, duals=None, like=None) For cyclic group of order `order`, build all possible subkeys of length `ndim`, grouped (via the first axis) by their overall charge, then lexicographically ordered within each charge. :param ndim: The number of sub charges to build keys for. :type ndim: int :param order: The order of the cyclic group, i.e., the number of distinct charges. Default is 2, which corresponds to the Z2 group. :type order: int, optional :param like: If provided, the output will be created with the same backend as this array. If None, the output will be created with the default backend, which is usually `numpy`. :type like: array_like, optional :returns: An array of shape (order, order ** (ndim - 1), ndim). :rtype: array_like