# LegPipe¶

Inheritance Diagram

Methods

 LegPipe.__init__(legs[, qconj, sort, bunch]) Initialize self. LegPipe.bunch(*args, **kwargs) Convert to LegCharge and call LegCharge.bunch(). Return unique rows of self.charges. Return a shallow copy with opposite self.qconj. Return a (shallow) copy of self. LegPipe.extend(extra) Return a new LegCharge, which extends self with futher charges. Return a copy with both negative qconj and charges. LegPipe.from_add_charge(legs[, chargeinfo]) Add the (independent) charges of two or more legs to get larger qnumber. LegPipe.from_change_charge(leg, charge, new_qmod) Remove a charge from a LegCharge. LegPipe.from_drop_charge(leg[, charge, …]) Remove a charge from a LegCharge. LegPipe.from_hdf5(hdf5_loader, h5gr, subpath) Load instance from a HDF5 file. LegPipe.from_qdict(chargeinfo, qdict[, qconj]) Create a LegCharge from qdict form. LegPipe.from_qflat(chargeinfo, qflat[, qconj]) Create a LegCharge from qflat form. LegPipe.from_qind(chargeinfo, slices, charges) Just a wrapper around self.__init__(), see class doc-string for parameters. LegPipe.from_trivial(ind_len[, chargeinfo, …]) Create trivial (qnumber=0) LegCharge for given len of indices ind_len. Return the sizes of the individual blocks. LegPipe.get_charge(qindex) Return charge self.charges[qindex] * self.qconj for a given qindex. LegPipe.get_qindex(flat_index) Find qindex containing a flat index. Return the slice selecting the block for given charge values. LegPipe.get_slice(qindex) Return slice selecting the block for a given qindex. Returns whether self is blocked, i.e. qindex map 1:1 to charge values. Checks whether bunch() would change something. Returns whether self.charges is sorted lexiographically. LegPipe.map_incoming_flat(incoming_indices) Map (flat) incoming indices to an index in the outgoing pipe. Like conj(), but don’t change qconj for incoming legs. LegPipe.perm_flat_from_perm_qind(perm_qind) Convert a permutation of qind (acting on self) into a flat permutation. LegPipe.perm_qind_from_perm_flat(perm_flat) Convert flat permutation into qind permutation. LegPipe.project(*args, **kwargs) Convert self to LegCharge and call LegCharge.project(). LegPipe.save_hdf5(hdf5_saver, h5gr, subpath) Export self into a HDF5 file. LegPipe.sort(*args, **kwargs) Convert to LegCharge and call LegCharge.sort(). Raises a ValueError if charges are incompatible for contraction with other. LegPipe.test_equal(other) Test if charges are equal including qconj. Sanity check, raises ValueErrors, if something is wrong. Convert self to a LegCharge, discarding the information how to split the legs. Return charges in qdict form. Return charges in qflat form.
class tenpy.linalg.charges.LegPipe(legs, qconj=1, sort=True, bunch=True)[source]

A LegPipe combines multiple legs of a tensor to one.

Often, it is necessary to “combine” multiple legs into one: for example to perfom a SVD, the tensor needs to be viewed as a matrix.

This class does exactly this job: it combines multiple LegCharges (‘incoming legs’) into one ‘pipe’ (the ‘outgoing leg’). The pipe itself is a LegCharge, with indices running from 0 to the product of the individual legs’ ind_len, corresponding to all possible combinations of input leg indices.

(This class is implemented in tenpy.linalg.charges but also imported in tenpy.linalg.np_conserved for convenience.)

Parameters
• legs (list of LegCharge) – The legs which are to be combined.

• qconj ({+1, -1}) – A flag telling whether the charge of the resulting pipe points inwards (+1, default) or outwards (-1).

• sort (bool) – Whether the outgoing pipe should be sorted. Default True; recommended. Note: calling sort() after initialization converts to a LegCharge.

• bunch (bool) – Whether the outgoing pipe should be bunched. Default True; recommended. Note: calling bunch() after initialization converts to a LegCharge.

nlegs

The number of legs.

Type

int

legs

The original legs, which were combined in the pipe.

Type

tuple of LegCharge

subshape

ind_len for each of the incoming legs.

Type

tuple of int

subqshape

block_number for each of the incoming legs.

Type

tuple of int

q_map

Shape (block_number, 3 + nlegs). Rows: [ b_j, b_{j+1}, I_s, i_1, ..., i_{nlegs}], See Notes below for details.

Type

array[np.intp, ndim=2]

q_map_slices

Defined such that the row indices of in range(q_map_slices[I_s], q_map_slices[I_s+1]) have q_map[:, 2] == I_s.

Type

array[np.intp, ndim=1]

_perm

A permutation such that q_map[_perm, 3:] is sorted by i_l.

Type

1D array

_strides

Strides for mapping incoming qindices i_l to the index of q_map[_perm, :].

Type

1D array

Notes

For np.reshape, taking, for example, $$i,j,... \rightarrow k$$ amounted to $$k = s_1*i + s_2*j + ...$$ for appropriate strides $$s_1,s_2$$.

In the charged case, however, we want to block $$k$$ by charge, so we must implicitly permute as well. This reordering is encoded in q_map.

Each qindex combination of the nlegs input legs $$(i_1, ..., i_{nlegs})$$, will end up getting placed in some slice $$a_j:a_{j+1}$$ of the outgoing pipe. Within this slice, the data is simply reshaped in usual row-major fashion (‘C’-order), i.e., with strides $$s_1 > s_2 > ...$$.

It will be a subslice of a new total block labeled by qindex $$I_s$$. Because many charge combinations fuse to the same total charge, in general there will be many tuples $$(i_1, ..., i_{nlegs})$$ belonging to the same $$I_s$$. The rows of q_map are precisely the collections of [b_j, b_{j+1}, I_s, i_1, . . . , i_{nlegs}]. Here, $$b_j:b_{j+1}$$ denotes the slice of this qindex combination within the total block I_s, i.e., b_j = a_j - self.slices[I_s].

The rows of q_map are lex-sorted first by I_s, then the i. Each I_s will have multiple rows, and the order in which they are stored in q_map is the order the data is stored in the actual tensor, i.e., it might look like

[ ...,
[ b_j,     b_{j+1},  I_s,     i_1,    ..., i_{nlegs}   ],
[ b_{j+1}, b_{j+2},  I_s,     i'_1,   ..., i'_{nlegs}  ],
[ 0,       b_{j+3},  I_s + 1, i''_1,  ..., i''_{nlegs} ],
[ b_{j+3}, b_{j+4},  I_s + 1, i'''_1, ..., i'''_{nlegs}],
...]


The charge fusion rule is:

self.charges[Qi]*self.qconj == sum([l.charges[qi_l]*l.qconj for l in self.legs])  mod qmod


Here the qindex Qi of the pipe corresponds to qindices qi_l on the individual legs.

copy()[source]

Return a (shallow) copy of self.

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().

In addition to the data saved for the LegCharge, it just saves the legs as subgroup.

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

• h5gr (:classGroup) – HDF5 group which is supposed to represent self.

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

classmethod from_hdf5(hdf5_loader, h5gr, subpath)[source]

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

test_sanity()[source]

Sanity check, raises ValueErrors, if something is wrong.

to_LegCharge()[source]

Convert self to a LegCharge, discarding the information how to split the legs.

Usually not needed, but called by functions, which are not implemented for a LegPipe.

conj()[source]

Return a shallow copy with opposite self.qconj.

Returns

conjugated – Shallow copy of self with flipped qconj. Whenever we contract two legs, they need to be conjugated to each other. The incoming legs of the pipe are also conjugated.

Return type

LegCharge

outer_conj()[source]

Like conj(), but don’t change qconj for incoming legs.

sort(*args, **kwargs)[source]

Convert to LegCharge and call LegCharge.sort().

bunch(*args, **kwargs)[source]

Convert to LegCharge and call LegCharge.bunch().

project(*args, **kwargs)[source]

Convert self to LegCharge and call LegCharge.project().

In general, this could be implemented for a LegPipe, but would make split_legs() more complicated, thus we keep it simple. If you really want to project and split afterwards, use the following work-around, which is for example used in exact_diagonalization:

1. Create the full pipe and save it separetely.

2. Convert the Pipe to a Leg & project the array with it.

3. [… do calculations …]

4. To split the ‘projected pipe’ of A, create and empty array B with the legs of A, but replace the projected leg by the full pipe. Set A as a slice of B. Finally split the pipe.

map_incoming_flat(incoming_indices)[source]

Map (flat) incoming indices to an index in the outgoing pipe.

Parameters

incoming_indices (iterable of int) – One (flat) index on each of the incoming legs.

Returns

outgoing_index – The index in the outgoing leg.

Return type

int

charge_sectors()[source]

Return unique rows of self.charges.

Returns

charges – Rows are the rows of self.charges lexsorted and without duplicates.

Return type

array[QTYPE, ndim=2]

extend(extra)[source]

Return a new LegCharge, which extends self with futher charges.

This is needed to formally increase the dimension of an Array.

Parameters

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

Returns

extended_leg – Copy of self extended by the charge blocks of the extra leg.

Return type

LegCharge

flip_charges_qconj()[source]

Return a copy with both negative qconj and charges.

Returns

conj_charges – (Shallow) copy of self with negative qconj and charges, thus representing the very same charges. test_equal() of self with conj_charges will not raise an error.

Return type

LegCharge

classmethod from_add_charge(legs, chargeinfo=None)[source]

Add the (independent) charges of two or more legs to get larger qnumber.

Parameters
Returns

combined – A LegCharge with the charges of both legs. Is neither sorted nor bunched!

Return type

LegCharge

classmethod from_change_charge(leg, charge, new_qmod, new_name='', chargeinfo=None)[source]

Remove a charge from a LegCharge.

Parameters
• leg (LegCharge) – The leg from which to drop/remove a charge.

• charge (int | str) – Number or name of the charge (within chinfo) for which mod is to be changed.

• new_qmod (int) – The new mod to be set for charge in the ChargeInfo.

• new_name (str) – The new name for charge.

• chargeinfo (ChargeInfo) – The ChargeInfo with charge changed; create new if None.

Returns

leg – A LegCharge with the specified charge changed. Is neither sorted nor bunched!

Return type

LegCharge

classmethod from_drop_charge(leg, charge=None, chargeinfo=None)[source]

Remove a charge from a LegCharge.

Parameters
• leg (LegCharge) – The leg from which to drop/remove a charge.

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

• chargeinfo (ChargeInfo) – The ChargeInfo with charge dropped; create new if None.

Returns

dropped – A LegCharge with the specified charge dropped. Is neither sorted nor bunched!

Return type

LegCharge

classmethod from_qdict(chargeinfo, qdict, qconj=1)[source]

Create a LegCharge from qdict form.

Parameters
classmethod from_qflat(chargeinfo, qflat, qconj=1)[source]

Create a LegCharge from qflat form.

Does neither bunch nor sort. We recommend to sort (and bunch) afterwards, if you expect that tensors using the LegCharge have entries at all positions compatible with the charges.

Parameters
• chargeinfo (ChargeInfo) – The nature of the charge.

• qflat (array_like (ind_len, qnumber)) – qnumber charges for each index of the leg on entry.

• qconj ({-1, 1}) – A flag telling whether the charge points inwards (+1) or outwards (-1).

sort()

sorts by charges

bunch()

bunches contiguous blocks of the same charge.

classmethod from_qind(chargeinfo, slices, charges, qconj=1)[source]

Just a wrapper around self.__init__(), see class doc-string for parameters.

sort()

sorts by charges

bunch()

bunches contiguous blocks of the same charge.

classmethod from_trivial(ind_len, chargeinfo=None, qconj=1)[source]

Create trivial (qnumber=0) LegCharge for given len of indices ind_len.

get_block_sizes()[source]

Return the sizes of the individual blocks.

Returns

sizes – The sizes of the individual blocks; sizes[i] = slices[i+1] - slices[i].

Return type

ndarray, shape (block_number,)

get_charge(qindex)[source]

Return charge self.charges[qindex] * self.qconj for a given qindex.

get_qindex(flat_index)[source]

Find qindex containing a flat index.

Given a flat index, to find the corresponding entry in an Array, we need to determine the block it is saved in. For example, if slices = [[0, 3], [3, 7], [7, 12]], the flat index 5 corresponds to the second entry, qindex = 1 (since 5 is in [3:7]), and the index within the block would be 2 = 5 - 3.

Parameters

flat_index (int) – A flat index of the leg. Negative index counts from behind.

Returns

• qindex (int) – The qindex, i.e. the index of the block containing flat_index.

• index_within_block (int) – The index of flat_index within the block given by qindex.

get_qindex_of_charges(charges)[source]

Return the slice selecting the block for given charge values.

Inverse function of get_charge().

Parameters

charges (1D array_like) – Charge values for which the slice of the block is to be determined.

Returns

slice(i, j) – Slice of the charge values for

Return type

slice

:raises ValueError : if the answer is not unique (because self is not blocked).:

get_slice(qindex)[source]

Return slice selecting the block for a given qindex.

is_blocked()[source]

Returns whether self is blocked, i.e. qindex map 1:1 to charge values.

is_bunched()[source]

Checks whether bunch() would change something.

is_sorted()[source]

Returns whether self.charges is sorted lexiographically.

perm_flat_from_perm_qind(perm_qind)[source]

Convert a permutation of qind (acting on self) into a flat permutation.

perm_qind_from_perm_flat(perm_flat)[source]

Convert flat permutation into qind permutation.

Parameters

perm_flat (1D array) – A permutation acting on self, which doesn’t mix the blocks of qind.

Returns

perm_qind – The permutation of self.qind described by perm_flat.

Return type

1D array

Raises

ValueError – If perm_flat mixes blocks of different qindex.

test_contractible(other)[source]

Raises a ValueError if charges are incompatible for contraction with other.

Parameters

other (LegCharge) – The LegCharge of the other leg condsidered for contraction.

Raises

ValueError – If the charges are incompatible for direct contraction.

Notes

This function checks that two legs are ready for contraction. This is the case, if all of the following conditions are met:

• the ChargeInfo is equal

• the slices are equal

• the charges are the same up to opposite signs qconj:

self.charges * self.qconj = - other.charges * other.qconj


In general, there could also be a change of the total charge, see Charge conservation with np_conserved This special case is not considered here - instead use gauge_total_charge(), if a change of the charge is desired.

If you are sure that the legs should be contractable, check whether the charges are actually valid or whether self and other are blocked or should be sorted.

test_equal()

self.test_contractible(other) just performs self.test_equal(other.conj()).

test_equal(other)[source]

Test if charges are equal including qconj.

Check that all of the following conditions are met:

• the ChargeInfo is equal

• the slices are equal

• the charges are the same up to the signs qconj:

self.charges * self.qconj = other.charges * other.qconj


test_contractible()

self.test_equal(other) is equivalent to self.test_contractible(other.conj()).

to_qdict()[source]

Return charges in qdict form.

Raises ValueError, if not blocked.

to_qflat()[source]

Return charges in qflat form.