User Interface
This page covers the stable, user-facing API. For the lower-level named-array model, tensor construction internals and accessors, and experimental features, see the Developer Interface. For a complete alphabetical listing of every documented name, see the Reference.
Indices and tensors
An ITensor labels its dimensions by name, and an Index is a named dimension. Get a tensor's indices with inds, make distinct copies of an index with prime and noprime, and mint a fresh unique name with uniquename.
ITensorBase.Index — Type
Index(space)An index of an ITensor: a named unit range whose name is an IndexName, a freshly minted, unique identifier carrying tags and a prime level. The argument is a space that is converted to a range: Index(2) makes an index of length 2 over Base.OneTo(2), Index(1:3) makes one over an explicit range, and (with GradedArrays loaded) Index([U1(0) => 2, U1(1) => 3]) makes one over a graded range. Each call mints a new name, so two indices built the same way are still distinct, and tensors share a dimension only when they share the same Index.
Examples
julia> i = Index(2);
julia> length(i)
2ITensorBase.inds — Function
inds(a::AbstractNamedTensor)
inds(a::AbstractNamedTensor, dim::Int)The named axes (indices) of a, as a Vector with one entry per dimension. Each entry pairs a dimension's axis with its name. The second form returns the index of dimension dim. Compare with dimnames, which returns just the names without the axes. The axes function returns the same indices as a Tuple, which the AbstractArray interface relies on; inds returns a Vector because the indices are most often manipulated as a collection (filter, setdiff, union).
Examples
julia> a = nameddims(zeros(2, 3), (:i, :j));
julia> inds(a)
2-element Vector{NamedUnitRange{Symbol, Int64, Base.OneTo{Int64}}}:
named(Base.OneTo(2), :i)
named(Base.OneTo(3), :j)
julia> inds(a, 1)
named(Base.OneTo(2), :i)ITensorBase.prime — Function
prime(i)Increment the prime level of an index or index name by one, returning a new index that is distinct from i. Priming is the usual way to make a second copy of an index that carries the same tags but is not contracted against the original. The inverse is noprime, which resets the prime level to zero.
Examples
julia> i = Index(2);
julia> prime(i) == i
false
julia> noprime(prime(i)) == i
trueITensorBase.noprime — Function
noprime(i)Reset the prime level of an index or index name to zero, returning a new index. This undoes any number of prime calls.
Examples
julia> i = Index(2);
julia> noprime(prime(i)) == i
trueITensorBase.uniquename — Function
uniquename([rng,] name)
uniquename([rng,] type::Type)Mint a fresh, unique name. Given an existing name (or a name type), produce a new name of the same flavor that is distinct from any other, for example to label a freshly generated dimension in a matrix factorization. Randomness defaults to OS entropy (Random.RandomDevice) so that minting a name neither perturbs nor is perturbed by the numerical RNG. Pass an explicit rng for a reproducible name.
Examples
julia> i = Index(2);
julia> uniquename(i) != i
trueConstructors
Build a tensor by calling a Base array constructor on indices instead of sizes. randn, rand, zeros, ones, and fill all accept indices and return an ITensor carrying them. These are Base functions extended to accept indices, so they are shown here by example rather than in the Reference.
using ITensorBase: Index
i, j = Index(2), Index(3)
randn(i, j)Index(length=2|id=d218719f)×Index(length=3|id=613ac666) ITensor:
2×3 Matrix{Float64}:
0.302087 -0.0426031 0.633876
0.309829 -1.37752 0.77182zeros(i, j)Index(length=2|id=d218719f)×Index(length=3|id=613ac666) ITensor:
2×3 Matrix{Float64}:
0.0 0.0 0.0
0.0 0.0 0.0To name an existing array, index it by the indices: array[indices...] returns an ITensor wrapping array with one name per dimension. This is the recommended way to turn an unnamed array into a named one.
randn(2, 3)[i, j]Index(length=2|id=d218719f)×Index(length=3|id=613ac666) ITensor:
2×3 Matrix{Float64}:
1.4229 -0.712038 1.35794
-1.11814 1.48135 -0.919932Algebra
ITensors support the standard arithmetic. * contracts over shared indices, leaving the unshared ones.
k = Index(2)
a, b = randn(i, j), randn(j, k)
a * bIndex(length=2|id=d218719f)×Index(length=2|id=6234f92d) ITensor:
2×2 Matrix{Float64}:
-1.50257 1.65148
-1.704 0.976197+ and - add and subtract tensors. They are matched up by index, so the operands need not list their indices in the same order.
c = randn(j, i)
a + cIndex(length=2|id=d218719f)×Index(length=3|id=613ac666) ITensor:
2×3 Matrix{Float64}:
-1.4018 -2.57631 -0.86738
0.305071 -0.485435 -0.631958Multiplying by a scalar scales the tensor.
2 * aIndex(length=2|id=d218719f)×Index(length=3|id=613ac666) ITensor:
2×3 Matrix{Float64}:
-2.30411 -2.4944 0.836183
-1.48299 -1.18934 1.52689Broadcasting
Broadcasting works elementwise and matches operands by name, so they need not share index order. Its advantage over the plain arithmetic above is fusion: a dotted expression is evaluated in a single pass over the elements, without allocating the intermediate tensors the undotted form does.
For example, the plain expression below allocates 2 * a and 3 * c before adding them:
2 * a + 3 * cIndex(length=2|id=d218719f)×Index(length=3|id=613ac666) ITensor:
2×3 Matrix{Float64}:
-3.05334 -6.48172 -3.02023
1.65671 -0.861636 -2.65932Adding dots fuses the whole expression into one pass, giving the same result with no intermediates:
2 .* a .+ 3 .* cIndex(length=2|id=d218719f)×Index(length=3|id=613ac666) ITensor:
2×3 Matrix{Float64}:
-3.05334 -6.48172 -3.02023
1.65671 -0.861636 -2.65932Non-linear broadcasting (functions of one or more tensors, such as sin.(a) or a .^ 2) is experimental and incompletely supported, and is subject to change.
Factorizations
Matrix factorizations from MatrixAlgebraKit work on an ITensor by naming which indices form the codomain (rows) of the matrix the tensor is interpreted as; the remaining indices form the domain (columns). The factors share a freshly named index over the bond between them, so they contract back together with *.
A QR decomposition, splitting index i off from the rest:
using MatrixAlgebraKit: qr_compact
q, r = qr_compact(a, (i,))
q * r ≈ atrueA singular value decomposition returns three factors:
using MatrixAlgebraKit: svd_compact
u, s, v = svd_compact(a, (i,))
u * s * v ≈ atrueThese are MatrixAlgebraKit factorizations wrapped to act on an ITensor by name. MatrixAlgebraKit provides many more, including eigendecompositions, polar decompositions, and truncated and full variants, along with keyword options controlling them; see the MatrixAlgebraKit documentation for the full list and the keyword syntax. The aim is to wrap all of them, but coverage is still being filled in, so please open an issue if one you need is not available yet.