Matrix-product operators (MPO, MPOList)#

Similar to the MPS, the matrix-product operator is an efficient representation of operators acting on quantum states, based on a tensor-network structure.

\[O = \sum_{\vec{i},\vec{\alpha},\vec{j}} \prod_{n=1}^N B_{\alpha_n,i_n,i_n,\alpha_n} \vert i_1,i_2\ldots i_N\rangle \langle j_1,j_2\ldots j_N\vert\]

As before, the \(i_n,j_n\) are indices labelling quantum states of the N subsystems, while the \(\alpha_i\) are integer indices connecting (correlating) neigboring quantum systems. The difference is that now this models an operator, transforming quantum states from \(j_n\) to \(i_n\) combinations.

In SeeMPS, matrix-product operators are represented by two classes, MPO and MPOList, encoding either one operator \(O\), or a sequence of them, \(O_{M-1} \cdots O_1 \cdot O_0\), in this order, as elements of an MPO list O[m].

Creation#

Matrix product states can be created by supplying the tensors that form the state, and in the case of small wavefunctions, they can be reconstructed directly from the state vector of the composite quantum state. In addition to this, we offer modules offer specific operators for implementing quantum Fourier transforms, QUBO opertors, etc. MPO’s and their aggregates also can be scaled by a scalar, creating new objects with transformed tensors. And finally, MPO’s can be enlarged to include new quantum subsystems—for instance, when you wish to implement a QFT onto a set of qubits, the extend() function allows you to do it.

MPO(data[, strategy])

Matrix Product Operator class.

MPOList(mpos[, strategy])

Sequence of matrix-product operators.

__mul__(n)

Multiply an MPO by a scalar n * self

__mul__(n)

Multiply an MPO by a scalar n as in n * self.

extend(L[, sites, dimensions])

Enlarge an MPO so that it acts on a larger Hilbert space with 'L' sites.

extend(L[, sites, dimensions])

Enlarge an MPOList so that it acts on a larger Hilbert space with 'L' sites.

Application#

One of the advantages of matrix-product operators is that they can be efficiently applied to matrix-product states, preserving the matrix-product form, and with a cost that is linear in the system size. This is illustrated by the graph below, sketching the contraction of an MPO (first row, 4-dimensional tensors) with an MPS (lower row, 3-legged tensors).

_images/mpo-mps-contraction.drawio.svg

The drawback of this contraction is that it results in potentially larger tensors. Indeed, in the example above, a trivial contraction will create an MPS with tensors of size \(dD\times d\times dD\).

We offer two functions to apply MPO’s onto MPS’. The first one is the seemps.operators.MPO.apply(), which offers a lot of control on the contraction and later simplification of the MPS (see simplification algorithm). The other alternative is the matrix multiplication operator @, which relies on the strategy stored in the state for contraction and simplification.

apply(state[, strategy, simplify])

Implement multiplication A @ state between a matrix-product operator A and a matrix-product state state.

apply(state[, strategy, simplify])

Implement multiplication A @ state between a matrix-product operator A and a matrix-product state state.

__matmul__(b)

Implement multiplication self @ b.

__matmul__(b)

Implement multiplication self @ b.

expectation(bra[, ket])

Expectation value of MPO on one or two MPS states.

As an example, consider the application of a quantum Fourier transform onto a random MPS:

>>> import seemps
>>> mps = seemps.random_uniform_mps(2, 10)
>>> mpo = seemps.qft.qft_mpo(10)
>>> Fmps = mpo @ mps

The same can be done in a slightly more controlled way, as in:

>>> Fmps = mpo.apply(mps, strategy=seemps.Strategy(tolerance=1e-9))

Note that there are dedicated functions to compute expectation values of matrix product operators. Thus instead of using the slow contraction:

>>> scprod(mps, mpo @ mps)

you should instead use the specialized algorithms:

>>> mpo.expectation(mps)