Contracting ITensors

Tensor contraction is often the most costly step of tensor algorithms. Code for contracting tensors can be fragile and error-prone when the tensor interface depends on the index ordering.

ITensor gets around these issues by using "intelligent" indices which recognize each other and automatically contract, regardless of the order they are in. ITensor works behind the scenes to make sure this is done as efficiently as possible.

To contract two ITensors, use the * operator, which contracts all matching indices. Some pairs of indices may match, yet you do not want them to be contracted. To prevent this from happening, change the prime level of such indices on one or both tensors as in the second example below.

A Simple Example

Given three distinct Index objects i,j, and k, say we make the following ITensors:

auto A = ITensor(i,j);
auto B = ITensor(k,j);

Then the following code contracts over the index j

auto C = A * B;

In traditional notation this means performing the sum

$$ C_{i k} = \sum_j A_{i j} B_{k j} \ . $$

If there had been other matching indices between A and B other than j, the * operator would have contracted them too. Indices i and k did not match (they could be copies of the same Index but we are assuming this is not the case) so they remain uncontracted and become the indices of C.

Interestingly, because of the way ITensor contraction is defined, B*A gives the same result as A*B. ITensor contraction is a commutative operation.

A More Complex Example

Of course, the real usefulness of a tensor library is handling cases where tensors have three or more indices.

Say we have an ITensor with indices i,s, and j

auto W = ITensor(i,s,j);

and want to contract W with itself, summing over indices i and j, but leaving s uncontracted.

In traditional tensor notation, we want to compute

$$ D_{s s^\prime} = \sum_{i,j} W_{i s j} W_{i s^\prime j} \ . $$

But this notation can become cumbersome for more complicated contractions.

A nicer way to notate a tensor contraction is by using a diagram

In diagram notation a tensor is a blob and each line denotes an index. Connecting two lines implies those indices are summed over. The remaining unpaired lines are the indices of the resulting tensor.

Both notations indicate our contraction strategy should be to prime the Index s on one copy of W. Calling prime(W,s) returns a copy of W with s replaced by s'. Then multiplying

auto D = W * prime(W,s);

automatically contracts i and j, but not s and s' since these no longer compare equal. Printing the result D confirms that it has only s and s' as indices.

ITensor Basics Factorizing ITensors

Back to Book
Back to Main