# Array

Inheritance Diagram

Methods

 `Array.__init__`(legcharges[, dtype, qtotal, ...]) see help(self) `Array.add_charge`(add_legs[, chinfo, qtotal]) Add charges. `Array.add_leg`(leg, i[, axis, label]) Add a leg to self, setting the current array as slice for a given index. `Array.add_trivial_leg`([axis, label, qconj]) Add a trivial leg (with just one entry) to self. Gives a version of self which is completely blocked by charges. `Array.astype`(dtype[, copy]) Return copy with new dtype, upcasting all blocks in `_data`. `Array.binary_blockwise`(func, other, *args, ...) Roughly `return func(self, other)`, block-wise. `Array.change_charge`(charge, new_qmod[, ...]) Change the qmod of one charge in chinfo. `Array.combine_legs`(combine_legs[, new_axes, ...]) Reshape: combine multiple legs into multiple pipes. Return copy which is complex conjugated without conjugating the charge data. `Array.conj`([complex_conj, inplace]) Conjugate: complex conjugate data, conjugate charge data. `Array.copy`([deep]) Return a (deep or shallow) copy of self. `Array.drop_charge`([charge, chinfo]) Drop (one of) the charges. `Array.extend`(axis, extra) Increase the dimension of a given axis, filling the values with zeros. `Array.from_func`(func, legcharges[, dtype, ...]) Create an Array from a numpy func. `Array.from_func_square`(func, leg[, dtype, ...]) Create an Array from a (numpy) function. `Array.from_hdf5`(hdf5_loader, h5gr, subpath) Load instance from a HDF5 file. `Array.from_ndarray`(data_flat, legcharges[, ...]) convert a flat (numpy) ndarray to an Array. `Array.from_ndarray_trivial`(data_flat[, ...]) convert a flat numpy ndarray to an Array with trivial charge conservation. `Array.gauge_total_charge`(axis[, newqtotal, ...]) Changes the total charge by adjusting the charge on a certain leg. `Array.get_block`(qindices[, insert]) Return the ndarray in `_data` representing the block corresponding to qindices. `Array.get_leg`(label) Return `self.legs[self.get_leg_index(label)]`. translate a leg-index or leg-label to a leg-index. `Array.get_leg_indices`(labels) Translate a list of leg-indices or leg-labels to leg indices. Return list of the leg labels, with None for anonymous legs. `Array.has_label`(label) Check whether a given label exists. `Array.iadd_prefactor_other`(prefactor, other) `self += prefactor * other` for scalar prefactor and `Array` other. `Array.ibinary_blockwise`(func, other, *args, ...) Roughly `self = func(self, other)`, block-wise; in place. `Array.iconj`([complex_conj]) Wrapper around `self.conj()` with `inplace=True`. `Array.idrop_labels`([old_labels]) Remove leg labels from self; in place. `Array.iproject`(mask, axes) Applying masks to one or multiple axes; in place. `Array.ipurge_zeros`([cutoff, norm_order]) Removes `self._data` blocks with norm less than cutoff; in place. `Array.ireplace_label`(old_label, new_label) Replace the leg label old_label with new_label; in place. `Array.ireplace_labels`(old_labels, new_labels) Replace leg label `old_labels[i]` with `new_labels[i]`; in place. Return bool whether all legs are blocked by charge. `Array.iscale_axis`(s[, axis]) Scale with varying values along an axis; in place. `Array.iscale_prefactor`(prefactor) `self *= prefactor` for scalar prefactor. `Array.iset_leg_labels`(labels) Set labels for the different axes/legs; in place. (Lexicographically) sort `self._qdata`; in place. `Array.iswapaxes`(axis1, axis2) Similar as `np.swapaxes`; in place. `Array.itranspose`([axes]) Transpose axes like np.transpose; in place. `Array.iunary_blockwise`(func, *args, **kwargs) Roughly `self = f(self)`, block-wise; in place. `Array.make_pipe`(axes, **kwargs) Generates a `LegPipe` for specified axes. `Array.matvec`(other) This function is used by the Lanczos algorithm needed for DMRG. `Array.norm`([ord, convert_to_float]) Norm of flattened data. `Array.permute`(perm, axis) Apply a permutation in the indices of an axis. `Array.replace_label`(old_label, new_label) Return a shallow copy with the leg label old_label replaced by new_label. `Array.replace_labels`(old_labels, new_labels) Return a shallow copy with `old_labels[i]` replaced by `new_labels[i]`. `Array.save_hdf5`(hdf5_saver, h5gr, subpath) Export self into a HDF5 file. `Array.scale_axis`(s[, axis]) Same as `iscale_axis()`, but return a (deep) copy. `Array.sort_legcharge`([sort, bunch]) Return a copy with one or all legs sorted by charges. Returns a string detailing the sparse statistics. `Array.split_legs`([axes, cutoff]) Reshape: opposite of combine_legs: split (some) legs which are LegPipes. `Array.squeeze`([axes]) Remove single-dimensional legs, like `np.squeeze()`. `Array.take_slice`(indices, axes) Return a copy of self fixing indices along one or multiple axes. Sanity check. Convert self to a dense numpy ndarray. `Array.transpose`([axes]) Like `itranspose()`, but on a deep copy. `Array.unary_blockwise`(func, *args, **kwargs) Roughly `return func(self)`, block-wise. Return a copy of self with only zeros as entries, containing no _data.

Class Attributes and Properties

 `Array.ndim` Alias for `rank` or `len(self.shape)`. `Array.size` The number of dtype-objects stored. `Array.stored_blocks` The number of (non-zero) blocks stored in `_data`.
class tenpy.linalg.np_conserved.Array(legcharges, dtype=<class 'numpy.float64'>, qtotal=None, labels=None)[source]

Bases: `object`

A multidimensional array (=tensor) for using charge conservation.

An Array represents a multi-dimensional tensor, together with the charge structure of its legs (for abelian charges). Further information can be found in Charge conservation with np_conserved.

The default `__init__()` (i.e. `Array(...)`) does not insert any data, and thus yields an Array ‘full’ of zeros, equivalent to `zeros()`. Further, new arrays can be created with one of `from_ndarray_trivial()`, `from_ndarray()`, or `from_func()`, and of course by copying/tensordot/svd etc.

In-place methods are indicated by a name starting with `i`. (But is_completely_blocked is not inplace…)

Parameters:
• legcharges (list of `LegCharge`) – The leg charges for each of the legs. The `ChargeInfo` is read out from it.

• dtype (type or string) – The data type of the array entries. Defaults to np.float64.

• qtotal (1D array of QTYPE) – The total charge of the array. Defaults to 0.

• labels (list of {str | None}) – Labels associated to each leg, `None` for non-named labels.

rank

The rank or “number of dimensions”, equivalent to `len(shape)`.

Type:

int

shape

The number of indices for each of the legs.

Type:

tuple(int)

dtype

The data type of the entries.

Type:

np.dtype

chinfo

The nature of the charge.

Type:

`ChargeInfo`

qtotal

The total charge of the tensor.

Type:

1D array

legs

The leg charges for each of the legs.

Type:

list of `LegCharge`

_labels

Labels for the different legs, None for non-labeled legs.

Type:

list of { str | None }

_data

The actual entries of the tensor.

Type:

list of arrays

_qdata

For each of the _data entries the qindices of the different legs.

Type:

2D array (len(_data), rank), dtype np.intp

_qdata_sorted

Whether self._qdata is lexsorted. Defaults to True, but must be set to False by algorithms changing _qdata.

Type:

Bool

test_sanity()[source]

Sanity check.

Raises ValueErrors, if something is wrong.

copy(deep=True)[source]

Return a (deep or shallow) copy of self.

Both deep and shallow copies will share `chinfo` and the LegCharges in `legs`.

In contrast to a deep copy, the shallow copy will also share the tensor entries, namely the same instances of `_qdata` and `_data` and `labels` (and other ‘immutable’ properties like the shape or dtype).

Note

Shallow copies are not recommended unless you know the consequences! See the following examples illustrating some of the pitfalls.

Examples

Be very careful when making non-deep copies: In the following example, the original a is changed if and only if the corresponding block existed in a before.

```>>> a = npc.Array.from_ndarray_trivial(np.arange(6.).reshape(2, 3))
>>> print(a.to_ndarray())
[[0. 1. 2.]
[3. 4. 5.]]
>>> b = a.copy(deep=False)  # shallow copy
>>> b[1, 2] = 8.
>>> a[1, 2]  # changed!
8.0
```

Other inplace operations might* have no effect at all (although we don’t guarantee that):

```>>> a *= 2  # has no effect on `b`
>>> b.iconj()  # nor does this change `a`
```
save_hdf5(hdf5_saver, h5gr, subpath)[source]

Export self into a HDF5 file.

This method saves all the data it needs to reconstruct self with `from_hdf5()`.

Specifically, it saves `chinfo`, `legs`, `dtype` under these names, `qtotal` as `"total_charge"`, `_data` as `"blocks"`, `_qdata` as `:block_inds"`, the `labels` in the list-form (as returned by `get_leg_labels()`). Moreover, it saves `rank`, `shape` and `_qdata_sorted` (under the name `"block_inds_sorted"`) as HDF5 attributes.

Parameters:
• hdf5_saver (`Hdf5Saver`) – Instance of the saving engine.

• h5gr (:class`Group`) – HDF5 group which is supposed to represent self.

• subpath (str) – The name of h5gr with a `'/'` in the end.

Load instance from a HDF5 file.

This method reconstructs a class instance from the data saved with `save_hdf5()`.

Parameters:
• hdf5_loader (`Hdf5Loader`) – Instance of the loading engine.

• h5gr (`Group`) – HDF5 group which is represent the object to be constructed.

• subpath (str) – The name of h5gr with a `'/'` in the end.

Returns:

obj – Newly generated class instance containing the required data.

Return type:

cls

classmethod from_ndarray_trivial(data_flat, dtype=None, labels=None)[source]

convert a flat numpy ndarray to an Array with trivial charge conservation.

Parameters:
• data_flat (array_like) – The data to be converted to a Array.

• dtype (`np.dtype`) – The data type of the array entries. Defaults to dtype of data_flat.

• labels (list of {str | None}) – Labels associated to each leg, `None` for non-named labels.

Returns:

res – An Array with data of data_flat.

Return type:

`Array`

classmethod from_ndarray(data_flat, legcharges, dtype=None, qtotal=None, cutoff=None, labels=None, raise_wrong_sector=True, warn_wrong_sector=True)[source]

convert a flat (numpy) ndarray to an Array.

Parameters:
• data_flat (array_like) – The flat ndarray which should be converted to a npc Array. The shape has to be compatible with legcharges.

• legcharges (list of `LegCharge`) – The leg charges for each of the legs. The `ChargeInfo` is read out from it.

• dtype (`np.dtype`) – The data type of the array entries. Defaults to dtype of data_flat.

• qtotal (None | charges) – The total charge of the new array.

• cutoff (float) – Blocks with `np.max(np.abs(block)) > cutoff` are considered as zero. Defaults to `QCUTOFF`.

• labels (list of {str | None}) – Labels associated to each leg, `None` for non-named labels.

• raise_wrong_sector (bool) – If True, raise a ValueError in case of non-zero entries (larger than cutoff) in the wrong blocks of data_flat. If False, just raise a warning.

Returns:

res – An Array with data of data_flat.

Return type:

`Array`

`detect_qtotal`

used to detect `qtotal` if not given.

classmethod from_func(func, legcharges, dtype=None, qtotal=None, func_args=(), func_kwargs={}, shape_kw=None, labels=None)[source]

Create an Array from a numpy func.

This function creates an array and fills the blocks compatible with the charges using func, where func is a function returning a array_like when given a shape, e.g. one of `np.ones` or `np.random.standard_normal`.

Parameters:
• func (callable) – A function-like object which is called to generate the data blocks. We expect that func returns a flat array of the given shape convertible to dtype. If no shape_kw is given, it is called as `func(shape, *func_args, **func_kwargs)`, otherwise as `func(*func_args, shape_kw=shape, **func_kwargs)`. shape is a tuple of int.

• legcharges (list of `LegCharge`) – The leg charges for each of the legs. The `ChargeInfo` is read out from it.

• dtype (None | type | string) – The data type of the output entries. Defaults to np.float64. Defaults to None: obtain it from the return value of the function. Note that this argument is not given to func, but rather a type conversion is performed afterwards. You might want to set a dtype in func_kwargs as well.

• qtotal (None | charges) – The total charge of the new array. Defaults to charge 0.

• func_args (iterable) – Additional arguments given to func.

• func_kwargs (dict) – Additional keyword arguments given to func.

• shape_kw (None | str) – If given, the keyword with which shape is given to func.

• labels (list of {str | None}) – Labels associated to each leg, `None` for non-named labels.

Returns:

res – An Array with blocks filled using func.

Return type:

`Array`

classmethod from_func_square(func, leg, dtype=None, func_args=(), func_kwargs={}, shape_kw=None, labels=None)[source]

Create an Array from a (numpy) function.

This function creates an array and fills the blocks compatible with the charges using func, where func is a function returning a array_like when given a shape, e.g. one of `np.ones` or `np.random.standard_normal` or the functions defined in `random_matrix`.

Parameters:
• func (callable) – A function-like object which is called to generate the data blocks. We expect that func returns a flat array of the given shape convertible to dtype. If no shape_kw is given, it is called like `func(shape, *fargs, **fkwargs)`, otherwise as `func(*fargs, `shape_kw`=shape, **fkwargs)`. shape is a tuple of int.

• leg (`LegCharge`) – The leg charges for the first leg; the second leg is set to `leg.conj()`. The `ChargeInfo` is read out from it.

• dtype (None | type | string) – The data type of the output entries. Defaults to None: obtain it from the return value of the function. Note that this argument is not given to func, but rather a type conversion is performed afterwards. You might want to set a dtype in func_kwargs as well.

• func_args (iterable) – Additional arguments given to func.

• func_kwargs (dict) – Additional keyword arguments given to func.

• shape_kw (None | str) – If given, the keyword with which shape is given to func.

• labels (list of {str | None}) – Labels associated to each leg, `None` for non-named labels.

Returns:

res – An Array with blocks filled using func.

Return type:

`Array`

zeros_like()[source]

Return a copy of self with only zeros as entries, containing no _data.

property size

The number of dtype-objects stored.

property stored_blocks

The number of (non-zero) blocks stored in `_data`.

property ndim

Alias for `rank` or `len(self.shape)`.

get_leg_index(label)[source]

translate a leg-index or leg-label to a leg-index.

Parameters:

label (int | string) – The leg-index directly or a label (string) set before.

Returns:

leg_index – The index of the label.

Return type:

int

`get_leg_indices`

calls get_leg_index for a list of labels.

`iset_leg_labels`

set the labels of different legs.

get_leg_indices(labels)[source]

Translate a list of leg-indices or leg-labels to leg indices.

Parameters:

labels (iterable of string/int) – The leg-labels (or directly indices) to be translated in leg-indices.

Returns:

leg_indices – The translated labels.

Return type:

list of int

`get_leg_index`

used to translate each of the single entries.

`iset_leg_labels`

set the labels of different legs.

iset_leg_labels(labels)[source]

Set labels for the different axes/legs; in place.

Introduction to leg labeling can be found in Charge conservation with np_conserved.

Parameters:

labels (iterable (strings | None), len=self.rank) – One label for each of the legs. An entry can be None for an anonymous leg.

`get_leg`

translate the labels to indices.

get_leg_labels()[source]

Return list of the leg labels, with None for anonymous legs.

has_label(label)[source]

Check whether a given label exists.

get_leg(label)[source]

Return `self.legs[self.get_leg_index(label)]`.

Convenient function returning the leg corresponding to a leg label/index.

ireplace_label(old_label, new_label)[source]

Replace the leg label old_label with new_label; in place.

replace_label(old_label, new_label)[source]

Return a shallow copy with the leg label old_label replaced by new_label.

ireplace_labels(old_labels, new_labels)[source]

Replace leg label `old_labels[i]` with `new_labels[i]`; in place.

replace_labels(old_labels, new_labels)[source]

Return a shallow copy with `old_labels[i]` replaced by `new_labels[i]`.

idrop_labels(old_labels=None)[source]

Remove leg labels from self; in place.

Parameters:

old_labels (list of str|int) – The leg labels/indices for which the label should be removed. By default (None), remove all labels.

sparse_stats()[source]

Returns a string detailing the sparse statistics.

to_ndarray()[source]

Convert self to a dense numpy ndarray.

get_block(qindices, insert=False)[source]

Return the ndarray in `_data` representing the block corresponding to qindices.

Parameters:
• qindices (1D array of np.intp) – The qindices, for which we need to look in _qdata.

• insert (bool) – If True, insert a new (zero) block, if qindices is not existent in `self._data`. Otherwise just return `None`.

Returns:

block – The block in `_data` corresponding to qindices. If insert`=False and there is not block with qindices, return ``None`.

Return type:

ndarray | `None`

Raises:

IndexError – If qindices are incompatible with charge and raise_incomp_q.

take_slice(indices, axes)[source]

Return a copy of self fixing indices along one or multiple axes.

For a rank-4 Array `A.take_slice([i, j], [1,2])` is equivalent to `A[:, i, j, :]`.

Parameters:
• indices ((iterable of) int) – The (flat) index for each of the legs specified by axes.

• axes ((iterable of) str/int) – Leg labels or indices to specify the legs for which the indices are given.

Returns:

sliced_self – A copy of self, equivalent to taking slices with indices inserted in axes.

Return type:

`Array`

`add_leg`

opposite action of inserting a new leg.

Add a trivial leg (with just one entry) to self.

Parameters:
• axis (int) – The new leg is inserted before index axis.

• label (str | `None`) – If not `None`, use it as label for the new leg.

• qconj (+1 | -1) – The direction of the new leg.

Returns:

extended – A (possibly) shallow copy of self with an additional leg of ind_len 1 and charge 0.

Return type:

`Array`

Add a leg to self, setting the current array as slice for a given index.

Parameters:
• leg (`LegCharge`) – The charge data of the leg to be added.

• i (int) – Index within the leg for which the data of self should be set.

• axis (axis) – The new leg is inserted before this current axis.

• label (str | `None`) – If not `None`, use it as label for the new leg.

Returns:

extended – A copy of self with the new leg at axis axis , such that `extended.take_slice(i, axis)` returns a copy of self.

Return type:

`Array`

`take_slice`

opposite action reducing the number of legs.

extend(axis, extra)[source]

Increase the dimension of a given axis, filling the values with zeros.

Parameters:
• axis (int | str) – The axis (or axis-label) to be extended.

• extra (`LegCharge` | int) – By what to extend, i.e. the charges to be appended to the leg of axis. An int stands for extending the length of the array by a single new block of that size with zero charges.

Returns:

extended – A copy of self with the specified axis increased.

Return type:

`Array`

gauge_total_charge(axis, newqtotal=None, new_qconj=None)[source]

Changes the total charge by adjusting the charge on a certain leg.

The total charge is given by finding a nonzero entry [i1, i2, …] and calculating:

```qtotal = self.chinfo.make_valid(
np.sum([l.get_charge(l.get_qindex(qi)[0])
for i, l in zip([i1,i2,...], self.legs)], axis=0))
```

Thus, the total charge can be changed by redefining (= shifting) the LegCharge of a single given leg. This is exactly what this function does.

Parameters:
• axis (int or string) – The new leg (index or label), for which the charge is changed.

• newqtotal (charge values, defaults to 0) – The new total charge.

• new_qconj ({+1, -1, None}) – Whether the new LegCharge points inward (+1) or outward (-1) afterwards. By default (None) use the previous `self.legs[leg].qconj`.

Returns:

copy – A shallow copy of self with `copy.qtotal == newqtotal` and new `copy.legs[leg]`. The new leg will be a :class`LegCharge`, even if the old leg was a `LegPipe`.

Return type:

`Array`

Parameters:
• add_legs (iterable of `LegCharge`) – One LegCharge for each axis of self, to be added to the one in `legs`.

• chargeinfo (`ChargeInfo`) – The ChargeInfo for all charges; create new if `None`.

• qtotal (None | charges) – The total charge with respect to add_legs. If `None`, derive it from non-zero entries of `self`.

Returns:

charges_added – A copy of self, where the LegCharges add_legs where added to self.legs. Note that the LegCharges are neither bunched or sorted; you might want to use `sort_legcharge()`.

Return type:

`Array`

drop_charge(charge=None, chinfo=None)[source]

Drop (one of) the charges.

Parameters:
• charge (int | str) – Number or name of the charge (within chinfo) which is to be dropped. `None` means dropping all charges.

• chinfo (`ChargeInfo`) – The `ChargeInfo` with charge dropped; create a new one if `None`.

Returns:

dropped – A copy of self, where the specified charge has been removed. Note that the LegCharges are neither bunched or sorted; you might want to use `sort_legcharge()`.

Return type:

`Array`

change_charge(charge, new_qmod, new_name='', chinfo=None)[source]

Change the qmod of one charge in chinfo.

Parameters:
• charge (int | str) – Number or name of the charge (within chinfo) which is to be changed. `None` means dropping all charges.

• new_qmod (int) – The new qmod to be set.

• new_name (str) – The new name of the charge.

• chinfo (`ChargeInfo`) – The `ChargeInfo` with qmod of charge changed; create a new one if `None`.

Returns:

changed – A copy of self, where the qmod of the specified charge has been changed. Note that the LegCharges are neither bunched or sorted; you might want to use `sort_legcharge()`.

Return type:

`Array`

is_completely_blocked()[source]

Return bool whether all legs are blocked by charge.

sort_legcharge(sort=True, bunch=True)[source]

Return a copy with one or all legs sorted by charges.

Sort/bunch one or multiple of the LegCharges. Legs which are sorted and bunched are guaranteed to be blocked by charge.

Parameters:
• sort (True | False | list of {True, False, perm}) – A single bool holds for all legs, default=True. Else, sort should contain one entry for each leg, with a bool for sort/don’t sort, or a 1D array perm for a given permutation to apply to a leg.

• bunch (True | False | list of {True, False}) – A single bool holds for all legs, default=True. Whether or not to bunch at each leg, i.e. combine contiguous blocks with equal charges.

Returns:

• perm (tuple of 1D arrays) – The permutation applied to each of the legs, such that `cp.to_ndarray() = self.to_ndarray()[np.ix_(*perm)]`.

• result (Array) – A shallow copy of self, with legs sorted/bunched.

isort_qdata()[source]

(Lexicographically) sort `self._qdata`; in place.

Lexsort `self._qdata` and `self._data` and set `self._qdata_sorted = True`.

make_pipe(axes, **kwargs)[source]

Generates a `LegPipe` for specified axes.

Parameters:
• axes (iterable of str|int) – The leg labels for the axes which should be combined. Order matters!

• **kwargs – Additional keyword arguments given to `LegPipe`.

Returns:

pipe – A pipe of the legs specified by axes.

Return type:

`LegPipe`

combine_legs(combine_legs, new_axes=None, pipes=None, qconj=None)[source]

Reshape: combine multiple legs into multiple pipes. If necessary, transpose before.

Changed in version 1.0: Make qconj default to the qconj of the first leg to be combine rather than just +1.

Parameters:
• combine_legs ((iterable of) iterable of {str|int}) – Bundles of leg indices or labels, which should be combined into a new output pipes. If multiple pipes should be created, use a list fore each new pipe.

• new_axes (None | (iterable of) int) – The leg-indices, at which the combined legs should appear in the resulting array. Default: for each pipe the position of its first pipe in the original array, (taking into account that some axes are ‘removed’ by combining). Thus no transposition is performed if combine_legs contains only contiguous ranges.

• pipes (None | (iterable of) {`LegPipes` | None}) – Optional: provide one or multiple of the resulting LegPipes to avoid overhead of computing new leg pipes for the same legs multiple times. The LegPipes are conjugated, if that is necessary for compatibility with the legs.

• qconj ((iterable of) {+1, -1}) – Specify whether new created pipes point inward or outward. Defaults to the same value as the first of the legs to be combined. E.g. for a single combine, the default qconj is self.get_leg(combine_legs[0]).qconj. Ignored for given pipes, which are not newly calculated.

Returns:

reshaped – A copy of self, with some legs combined into pipes as specified by the arguments.

Return type:

`Array`

`split_legs`

inverse reshaping splitting LegPipes.

Notes

Labels are inherited from self. New pipe labels are generated as `'(' + '.'.join(*leglabels) + ')'`. For these new labels, previously unlabeled legs are replaced by `'?#'`, where `#` is the leg-index in the original tensor self.

Examples

```>>> orig_array = npc.Array.from_ndarray_trivial(np.arange(60).reshape([2, 3, 2, 1, 5]),
...                                             labels=['a', 'b', 'c', 'd', 'e'])
>>> c1 = orig_array.combine_legs([1, 2], qconj=-1)  # only single output pipe
>>> c1.get_leg_labels()
['a', '(b.c)', 'd', 'e']
>>> c1.shape
(2, 6, 1, 5)
```

Indices of combine_legs refer to the original array. If transposing is necessary, it is performed automatically:

```>>> c2 = orig_array.combine_legs([[0, 3], [4, 1]], qconj=[+1, -1]) # two output pipes
>>> c2.get_leg_labels()
['(a.d)', 'c', '(e.b)']
>>> c2.shape
(2, 2, 15)
>>> c3 = orig_array.combine_legs([['a', 'd'], ['e', 'b']], new_axes=[2, 1],
...                            pipes=[c2.legs[0], c2.legs[2]])
>>> c3.get_leg_labels()
['c', '(e.b)', '(a.d)']
```
split_legs(axes=None, cutoff=0.0)[source]

Reshape: opposite of combine_legs: split (some) legs which are LegPipes.

Reverts `combine_legs()` (except a possibly performed transpose). The split legs are replacing the LegPipes at their position, see the examples below. Labels are split reverting what was done in `combine_legs()`. ‘?#’ labels are replaced with `None`.

Parameters:
• axes ((iterable of) int|str) – Leg labels or indices determining the axes to split. The corresponding entries in self.legs must be `LegPipe` instances. Defaults to all legs, which are `LegPipe` instances.

• cutoff (float) – Splitted data blocks with `np.max(np.abs(block)) > cutoff` are considered as zero. Defaults to 0.

Returns:

reshaped – A copy of self where the specified legs are splitted.

Return type:

`Array`

`combine_legs`

this is reversed by split_legs.

Examples

Given a rank-5 Array orig_array, you can combine it and split it again:

```>>> orig_array = npc.Array.from_ndarray_trivial(np.arange(60).reshape([2, 3, 2, 1, 5]),
...                                           labels=['a', 'b', 'c', 'd', 'e'])
>>> orig_array.shape
(2, 3, 2, 1, 5)
>>> comb_array = orig_array.combine_legs([['a', 'd'], ['c', 'e']] )
>>> comb_array.get_leg_labels()
['(a.d)', 'b', '(c.e)']
>>> comb_array.shape
(2, 3, 10)
>>> split_array = comb_array.split_legs()
>>> split_array.get_leg_labels()
['a', 'd', 'b', 'c', 'e']
>>> npc.norm(split_array.transpose(orig_array.get_leg_labels()) - orig_array)
0.0
```
as_completely_blocked()[source]

Gives a version of self which is completely blocked by charges.

Functions like `svd()` or `eigh()` require a complete blocking by charges. This can be achieved by encapsulating each leg which is not completely blocked into a `LegPipe` (containing only that single leg). The LegPipe will then contain all necessary information to revert the blocking.

Returns:

• encapsulated_axes (list of int) – The leg indices which have been encapsulated into Pipes.

• blocked_self (`Array`) – Self (if `len(encapsulated_axes) = 0`) or a copy of self, which is completely blocked.

squeeze(axes=None)[source]

Remove single-dimensional legs, like `np.squeeze()`.

If a squeezed leg has non-zero charge, this charge is added to `qtotal`.

Parameters:

axes (None | (iterable of) {int|str}) – Labels or indices of the legs which should be ‘squeezed’, i.e. the legs removed. The corresponding legs must be trivial, i.e., have ind_len 1.

Returns:

squeezed – A scalar of `self.dtype`, if all axes were squeezed. Else a copy of `self` with reduced `rank` as specified by axes.

Return type:

:class:Array | scalar

astype(dtype, copy=True)[source]

Return copy with new dtype, upcasting all blocks in `_data`.

Parameters:
• dtype (convertible to a np.dtype) – The new data type. If None, deduce the new dtype as common type of `self._data`.

• copy (bool) – Whether to make a copy of the blocks even if the type didn’t change.

Returns:

copy – Deep copy of self with new dtype.

Return type:

`Array`

ipurge_zeros(cutoff=np.float64(2.220446049250313e-15), norm_order=None)[source]

Removes `self._data` blocks with norm less than cutoff; in place.

Parameters:
• cutoff (float) – Blocks with norm <= cutoff are removed. defaults to `QCUTOFF`.

• norm_order – A valid ord argument for np.linalg.norm. Default `None` gives the Frobenius norm/2-norm for matrices/everything else. Note that this differs from other methods, e.g. `from_ndarray()`, which use the maximum norm.

Applying masks to one or multiple axes; in place.

This function is similar as np.compress with boolean arrays For each specified axis, a boolean 1D array mask can be given, which chooses the indices to keep.

Warning

Although it is possible to use an 1D int array as a mask, the order is ignored! If you need to permute an axis, use `permute()` or `sort_legcharge()`.

Parameters:
• mask ((list of) 1D array(bool|int)) – For each axis specified by axes a mask, which indices of the axes should be kept. If mask is a bool array, keep the indices where mask is True. If mask is an int array, keep the indices listed in the mask, ignoring the order or multiplicity.

• axes ((list of) int | string) – The i`th entry in this list specifies the axis for the `i`th entry of `mask, either as an int, or with a leg label. If axes is just a single int/string, specify just a single mask.

Returns:

• map_qind (list of 1D arrays) – The mapping of qindices for each of the specified axes.

• block_masks (list of lists of 1D bool arrays) – `block_masks[a][qind]` is a boolean mask which indices to keep in block `qindex` of `axes[a]`.

permute(perm, axis)[source]

Apply a permutation in the indices of an axis.

Similar as np.take with a 1D array. Roughly equivalent to `res[:, ...] = self[perm, ...]` for the corresponding axis. Note: This function is quite slow, and usually not needed!

Parameters:
• perm (array_like 1D int) – The permutation which should be applied to the leg given by axis.

• axis (str | int) – A leg label or index specifying on which leg to take the permutation.

Returns:

res – A copy of self with leg axis permuted, such that `res[i, ...] = self[perm[i], ...]` for `i` along axis.

Return type:

`Array`

`sort_legcharge`

can also be used to perform a general permutation. Preferable, since it is faster for permutations which don’t mix charge blocks.

itranspose(axes=None)[source]

Transpose axes like np.transpose; in place.

Parameters:

axes (iterable (int|string), len `rank` | None) – The new order of the axes. By default (None), reverse axes.

transpose(axes=None)[source]

Like `itranspose()`, but on a deep copy.

iswapaxes(axis1, axis2)[source]

Similar as `np.swapaxes`; in place.

iscale_axis(s, axis=-1)[source]

Scale with varying values along an axis; in place.

Rescale to `new_self[i1, ..., i_axis, ...] = s[i_axis] * self[i1, ..., i_axis, ...]`.

Parameters:
• s (1D array, len=self.shape[axis]) – The vector with which the axis should be scaled.

• axis (str|int) – The leg label or index for the axis which should be scaled.

`iproject`

can be used to discard indices for which s is zero.

scale_axis(s, axis=-1)[source]

Same as `iscale_axis()`, but return a (deep) copy.

iunary_blockwise(func, *args, **kwargs)[source]

Roughly `self = f(self)`, block-wise; in place.

Applies an unary function func to the non-zero blocks in `self._data`.

Note

Assumes implicitly that `func(np.zeros(...), *args, **kwargs)` gives 0, since we don’t let func act on zero blocks!

Parameters:
• func (function) – A function acting on flat arrays, returning flat arrays. It is called like `new_block = func(block, *args, **kwargs)`.

• *args – Additional arguments given to function after the block.

• **kwargs – Keyword arguments given to the function.

Examples

```>>> a = npc.Array.from_ndarray_trivial([1., 2.j])
>>> a.iunary_blockwise(np.conj).to_ndarray()  # same data as a.iconj(), but doesn't charge conjugate.
array([1.-0.j, 0.-2.j])
>>> a.iunary_blockwise(np.real).to_ndarray()  # get real part
array([1., 0.])
```
unary_blockwise(func, *args, **kwargs)[source]

Roughly `return func(self)`, block-wise. Copies.

Same as `iunary_blockwise()`, but makes a shallow copy first.

iconj(complex_conj=True)[source]

Wrapper around `self.conj()` with `inplace=True`.

conj(complex_conj=True, inplace=False)[source]

Conjugate: complex conjugate data, conjugate charge data.

Conjugate all legs, set negative qtotal.

Labeling: takes ‘a’ -> ‘a*’, ‘a*’-> ‘a’ and ‘(a,(b*,c))’ -> ‘(a*, (b, c*))’

Parameters:
• complex_conj (bool) – Whether the data should be complex conjugated.

• inplace (bool) – Whether to apply changes to self, or to return a deep copy.

complex_conj()[source]

Return copy which is complex conjugated without conjugating the charge data.

norm(ord=None, convert_to_float=True)[source]

Norm of flattened data.

See `norm()` for details.

ibinary_blockwise(func, other, *args, **kwargs)[source]

Roughly `self = func(self, other)`, block-wise; in place.

Applies a binary function ‘block-wise’ to the non-zero blocks of `self._data` and `other._data`, storing result in place. Assumes that other is an `Array` as well, with the same shape and compatible legs. If leg labels of other and self are same up to permutations, other gets transposed accordingly before the action.

Note

Assumes implicitly that `func(np.zeros(...), np.zeros(...), *args, **kwargs)` gives 0, since we don’t let func act on zero blocks!

Parameters:
• func (function) – Binary function, called as `new_block = func(block_self, block_other, *args, **kwargs)` for blocks (=Numpy arrays) of equal shape.

• other (`Array`) – Other Array from which to take blocks. Should have the same leg structure as self.

• *args – Extra arguments given to func.

• **kwargs – Extra keyword arguments given to func.

Examples

```>>> a = npc.Array.from_ndarray_trivial([1., 3.])
>>> b = npc.Array.from_ndarray_trivial([4., 2.])
>>> a.ibinary_blockwise(np.maximum, b).to_ndarray()  # a = max(a, b)
array([4., 3.])
>>> a.ibinary_blockwise(np.add, b).to_ndarray()  # roughly ``a += b``
array([8., 5.])
```
binary_blockwise(func, other, *args, **kwargs)[source]

Roughly `return func(self, other)`, block-wise. Copies.

Same as `ibinary_blockwise()`, but makes a shallow copy first.

matvec(other)[source]

This function is used by the Lanczos algorithm needed for DMRG.

It is supposed to calculate the matrix - vector - product for a rank-2 matrix `self` and a rank-1 vector other.

`self += prefactor * other` for scalar prefactor and `Array` other.
`self *= prefactor` for scalar prefactor.