ITensor Networks

The ITensorNetwork Type

An ITensorNetwork is the central data structure of this package. It represents a collection of ITensors arranged on a graph, where each edge encodes a shared (contracted) index between the neighboring tensors.

Key facts:

  • The underlying graph is a NamedGraph, so vertices can be any hashable Julia value: integers, tuples, strings, etc.
  • Each vertex holds exactly one ITensor.
  • Edges and link indices are either inferred from shared Index objects (when constructing from a collection of ITensors) or inserted automatically (when constructing from an IndsNetwork).

Construction

The most common entry point is an IndsNetwork — a graph whose vertices and edges carry Index objects. Generate site indices with the siteinds function which takes a site type string (such as "S=1/2" or "Electron") and a NamedGraph. The NamedGraph can be generated from functions such as named_grid, named_comb_tree, etc. from the NamedGraphs.jl NamedGraphGenerators module:

using Graphs: edges, ne, neighbors, nv, vertices
using ITensorNetworks: ITensorNetwork, add, linkinds, siteinds
using ITensors: Index, ITensor
using NamedGraphs.NamedGraphGenerators: named_grid

# 3×3 square-lattice tensor network
g = named_grid((3, 3))
s = siteinds("S=1/2", g)  # one spin-½ Index per vertex

# Zero-initialized, bond dimension 2
ψ = ITensorNetwork(s; link_space = 2)

# Product state — every site in the |↑⟩ state
ψ = ITensorNetwork("Up", s)

# Staggered initialization with a vertex-dependent function
ψ = ITensorNetwork(v -> isodd(sum(v)) ? "Up" : "Dn", s)
ITensorNetworks.ITensorNetwork{Tuple{Int64, Int64}} with 9 vertices:
9-element NamedGraphs.OrderedDictionaries.OrderedIndices{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
 (3, 1)
 (1, 2)
 (2, 2)
 (3, 2)
 (1, 3)
 (2, 3)
 (3, 3)

and 12 edge(s):
(1, 1) => (2, 1)
(1, 1) => (1, 2)
(2, 1) => (3, 1)
(2, 1) => (2, 2)
(3, 1) => (3, 2)
(1, 2) => (2, 2)
(1, 2) => (1, 3)
(2, 2) => (3, 2)
(2, 2) => (2, 3)
(3, 2) => (3, 3)
(1, 3) => (2, 3)
(2, 3) => (3, 3)

with vertex data:
9-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}:
 (1, 1) │ ((dim=2|id=386|"S=1/2,Site,n=1×1"), (dim=1|id=109|"1×1,2×1"), (dim=1|…
 (2, 1) │ ((dim=2|id=627|"S=1/2,Site,n=2×1"), (dim=1|id=109|"1×1,2×1"), (dim=1|…
 (3, 1) │ ((dim=2|id=140|"S=1/2,Site,n=3×1"), (dim=1|id=949|"2×1,3×1"), (dim=1|…
 (1, 2) │ ((dim=2|id=171|"S=1/2,Site,n=1×2"), (dim=1|id=95|"1×1,1×2"), (dim=1|i…
 (2, 2) │ ((dim=2|id=948|"S=1/2,Site,n=2×2"), (dim=1|id=539|"2×1,2×2"), (dim=1|…
 (3, 2) │ ((dim=2|id=218|"S=1/2,Site,n=3×2"), (dim=1|id=157|"3×1,3×2"), (dim=1|…
 (1, 3) │ ((dim=2|id=446|"S=1/2,Site,n=1×3"), (dim=1|id=979|"1×2,1×3"), (dim=1|…
 (2, 3) │ ((dim=2|id=91|"S=1/2,Site,n=2×3"), (dim=1|id=292|"2×2,2×3"), (dim=1|i…
 (3, 3) │ ((dim=2|id=415|"S=1/2,Site,n=3×3"), (dim=1|id=839|"3×2,3×3"), (dim=1|…

When you already have ITensors in hand, edges are inferred automatically from shared indices:

i, j, k = Index(2, "i"), Index(2, "j"), Index(2, "k")
A, B, C = ITensor(i, j), ITensor(j, k), ITensor(k)

tn = ITensorNetwork([A, B, C])  # integer vertices 1, 2, 3
tn = ITensorNetwork(["A", "B", "C"], [A, B, C])  # named vertices
tn = ITensorNetwork(["A" => A, "B" => B, "C" => C])  # from pairs
ITensorNetworks.ITensorNetwork{String} with 3 vertices:
3-element NamedGraphs.OrderedDictionaries.OrderedIndices{String}:
 "A"
 "B"
 "C"

and 2 edge(s):
"A" => "B"
"B" => "C"

with vertex data:
3-element Dictionaries.Dictionary{String, Any}:
 "A" │ ((dim=2|id=865|"i"), (dim=2|id=454|"j"))
 "B" │ ((dim=2|id=454|"j"), (dim=2|id=689|"k"))
 "C" │ ((dim=2|id=689|"k"),)
ITensorNetworks.ITensorNetworkType
ITensorNetwork{V}

A tensor network where each vertex holds an ITensor. The network graph is a NamedGraph{V} and edges represent shared indices between neighboring tensors.

Constructors

From an IndsNetwork (most common):

ITensorNetwork(is::IndsNetwork; link_space = 1)
ITensorNetwork(f, is::IndsNetwork; link_space = 1)
ITensorNetwork(eltype, undef, is::IndsNetwork; link_space = 1)
  • With no function argument f, tensors are initialized to zero.
  • With a function f(v) that returns a state label (e.g. "Up", "Dn") or an ITensor constructor, tensors are initialized accordingly.
  • link_space controls the bond-index dimension (default 1).

From a graph (site indices inferred as trivial):

ITensorNetwork(graph::AbstractNamedGraph; link_space = 1)
ITensorNetwork(f, graph::AbstractNamedGraph; link_space = 1)

From a collection of ITensors:

ITensorNetwork(ts::AbstractVector{ITensor})
ITensorNetwork(vs, ts::AbstractVector{ITensor})
ITensorNetwork(ts::AbstractVector{<:Pair{<:Any, ITensor}})
ITensorNetwork(ts::AbstractDict{<:Any, ITensor})

Edges are inferred from shared indices between tensors.

From a single ITensor:

ITensorNetwork(t::ITensor)

Wraps the tensor in a single-vertex network.

Example

julia> using NamedGraphs.NamedGraphGenerators: named_grid

julia> g = named_grid((4,));

julia> s = siteinds("S=1/2", g);

julia> tn = ITensorNetwork(s; link_space = 2);

julia> tn = ITensorNetwork("Up", s);

See also: IndsNetwork, ttn, TreeTensorNetwork.

source

Accessing Data

v = (1, 2)
T = ψ[v]  # ITensor at vertex (1,2)
ψ[v] = T  # replace tensor at a vertex
vertices(ψ)  # all vertex labels
edges(ψ)  # all edges
neighbors(ψ, v)  # neighbouring vertices of v
nv(ψ), ne(ψ)  # vertex / edge counts
siteinds(ψ)  # IndsNetwork of site (physical) indices
linkinds(ψ)  # IndsNetwork of bond (virtual) indices
ITensorNetworks.IndsNetwork{Tuple{Int64, Int64}, ITensors.Index} with 9 vertices:
9-element NamedGraphs.OrderedDictionaries.OrderedIndices{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
 (3, 1)
 (1, 2)
 (2, 2)
 (3, 2)
 (1, 3)
 (2, 3)
 (3, 3)

and 12 edge(s):
(1, 1) => (2, 1)
(1, 1) => (1, 2)
(2, 1) => (3, 1)
(2, 1) => (2, 2)
(3, 1) => (3, 2)
(1, 2) => (2, 2)
(1, 2) => (1, 3)
(2, 2) => (3, 2)
(2, 2) => (2, 3)
(3, 2) => (3, 3)
(1, 3) => (2, 3)
(2, 3) => (3, 3)

with vertex data:
0-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Vector{ITensors.Index}}

and edge data:
12-element Dictionaries.Dictionary{NamedGraphs.NamedEdge{Tuple{Int64, Int64}}, Vector{ITensors.Index}}:
 (1, 1) => (2, 1) │ ITensors.Index[(dim=1|id=109|"1×1,2×1")]
 (1, 1) => (1, 2) │ ITensors.Index[(dim=1|id=95|"1×1,1×2")]
 (2, 1) => (3, 1) │ ITensors.Index[(dim=1|id=949|"2×1,3×1")]
 (2, 1) => (2, 2) │ ITensors.Index[(dim=1|id=539|"2×1,2×2")]
 (3, 1) => (3, 2) │ ITensors.Index[(dim=1|id=157|"3×1,3×2")]
 (1, 2) => (2, 2) │ ITensors.Index[(dim=1|id=429|"1×2,2×2")]
 (1, 2) => (1, 3) │ ITensors.Index[(dim=1|id=979|"1×2,1×3")]
 (2, 2) => (3, 2) │ ITensors.Index[(dim=1|id=11|"2×2,3×2")]
 (2, 2) => (2, 3) │ ITensors.Index[(dim=1|id=292|"2×2,2×3")]
 (3, 2) => (3, 3) │ ITensors.Index[(dim=1|id=839|"3×2,3×3")]
 (1, 3) => (2, 3) │ ITensors.Index[(dim=1|id=824|"1×3,2×3")]
 (2, 3) => (3, 3) │ ITensors.Index[(dim=1|id=777|"2×3,3×3")]

Adding Two ITensorNetworks

Two networks with the same graph and site indices can be added. The result represents the tensor network ψ₁ + ψ₂ and has bond dimension equal to the sum of the two input bond dimensions. Individual bonds of the result can be recompressed with truncate(tn, edge). For TreeTensorNetwork, the no-argument form truncate(ttn; kwargs...) sweeps and recompresses all bonds at once.

ψ1, ψ2 = ψ, ψ
ψ12 = add(ψ1, ψ2)
ψ12 = ψ1 + ψ2
ITensorNetworks.ITensorNetwork{Tuple{Int64, Int64}} with 9 vertices:
9-element NamedGraphs.OrderedDictionaries.OrderedIndices{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
 (3, 1)
 (1, 2)
 (2, 2)
 (3, 2)
 (1, 3)
 (2, 3)
 (3, 3)

and 12 edge(s):
(1, 1) => (2, 1)
(1, 1) => (1, 2)
(2, 1) => (3, 1)
(2, 1) => (2, 2)
(3, 1) => (3, 2)
(1, 2) => (2, 2)
(1, 2) => (1, 3)
(2, 2) => (3, 2)
(2, 2) => (2, 3)
(3, 2) => (3, 3)
(1, 3) => (2, 3)
(2, 3) => (3, 3)

with vertex data:
9-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}:
 (1, 1) │ ((dim=2|id=386|"S=1/2,Site,n=1×1"), (dim=2|id=734|"1×1,2×1"), (dim=2|…
 (2, 1) │ ((dim=2|id=627|"S=1/2,Site,n=2×1"), (dim=2|id=734|"1×1,2×1"), (dim=2|…
 (3, 1) │ ((dim=2|id=140|"S=1/2,Site,n=3×1"), (dim=2|id=236|"2×1,3×1"), (dim=2|…
 (1, 2) │ ((dim=2|id=171|"S=1/2,Site,n=1×2"), (dim=2|id=76|"1×1,1×2"), (dim=2|i…
 (2, 2) │ ((dim=2|id=948|"S=1/2,Site,n=2×2"), (dim=2|id=151|"2×1,2×2"), (dim=2|…
 (3, 2) │ ((dim=2|id=218|"S=1/2,Site,n=3×2"), (dim=2|id=246|"3×1,3×2"), (dim=2|…
 (1, 3) │ ((dim=2|id=446|"S=1/2,Site,n=1×3"), (dim=2|id=156|"1×2,1×3"), (dim=2|…
 (2, 3) │ ((dim=2|id=91|"S=1/2,Site,n=2×3"), (dim=2|id=819|"2×2,2×3"), (dim=2|i…
 (3, 3) │ ((dim=2|id=415|"S=1/2,Site,n=3×3"), (dim=2|id=555|"3×2,3×3"), (dim=2|…
ITensorNetworks.addMethod
add(tn1::AbstractITensorNetwork, tn2::AbstractITensorNetwork) -> ITensorNetwork

Add two ITensorNetworks together by taking their direct sum (growing the bond dimension). The result represents the state tn1 + tn2, with bond dimension on each edge equal to the sum of the bond dimensions of tn1 and tn2.

Both networks must have the same vertex set and matching site indices at each vertex.

Use truncate on the result to compress back to a lower bond dimension.

See also: Base.:+ for TreeTensorNetwork, truncate.

source

Bond Truncation

A single bond (edge) of any ITensorNetwork can be truncated by SVD:

edge = (1, 2) => (1, 3)
ψ12 = truncate(ψ12, (1, 2) => (1, 3))  # truncate the bond between vertices (1,2) and (1,3)
ψ12 = truncate(ψ12, edge)  # or pass an AbstractEdge directly
ITensorNetworks.ITensorNetwork{Tuple{Int64, Int64}} with 9 vertices:
9-element NamedGraphs.OrderedDictionaries.OrderedIndices{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
 (3, 1)
 (1, 2)
 (2, 2)
 (3, 2)
 (1, 3)
 (2, 3)
 (3, 3)

and 12 edge(s):
(1, 1) => (2, 1)
(1, 1) => (1, 2)
(2, 1) => (3, 1)
(2, 1) => (2, 2)
(3, 1) => (3, 2)
(1, 2) => (2, 2)
(1, 2) => (1, 3)
(2, 2) => (3, 2)
(2, 2) => (2, 3)
(3, 2) => (3, 3)
(1, 3) => (2, 3)
(2, 3) => (3, 3)

with vertex data:
9-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}:
 (1, 1) │ ((dim=2|id=386|"S=1/2,Site,n=1×1"), (dim=2|id=734|"1×1,2×1"), (dim=2|…
 (2, 1) │ ((dim=2|id=627|"S=1/2,Site,n=2×1"), (dim=2|id=734|"1×1,2×1"), (dim=2|…
 (3, 1) │ ((dim=2|id=140|"S=1/2,Site,n=3×1"), (dim=2|id=236|"2×1,3×1"), (dim=2|…
 (1, 2) │ ((dim=2|id=171|"S=1/2,Site,n=1×2"), (dim=2|id=76|"1×1,1×2"), (dim=2|i…
 (2, 2) │ ((dim=2|id=948|"S=1/2,Site,n=2×2"), (dim=2|id=151|"2×1,2×2"), (dim=2|…
 (3, 2) │ ((dim=2|id=218|"S=1/2,Site,n=3×2"), (dim=2|id=246|"3×1,3×2"), (dim=2|…
 (1, 3) │ ((dim=2|id=446|"S=1/2,Site,n=1×3"), (dim=2|id=167|"1×3,2×3"), (dim=2|…
 (2, 3) │ ((dim=2|id=91|"S=1/2,Site,n=2×3"), (dim=2|id=819|"2×2,2×3"), (dim=2|i…
 (3, 3) │ ((dim=2|id=415|"S=1/2,Site,n=3×3"), (dim=2|id=555|"3×2,3×3"), (dim=2|…

Truncation parameters (cutoff, maxdim, mindim, …) are forwarded to ITensors.svd. For a TreeTensorNetwork, the sweep-based truncate(ttn; kwargs...) is usually more convenient because it recompresses the entire network at once with controlled errors; see the Tree Tensor Networks page.

Base.truncateMethod
truncate(tn::AbstractITensorNetwork, edge; kwargs...) -> ITensorNetwork

Truncate the bond across edge in tn by performing an SVD and discarding small singular values. edge may be an AbstractEdge or a Pair of vertices.

Truncation parameters are passed as keyword arguments and forwarded to ITensors.svd:

  • cutoff: Drop singular values smaller than this threshold.
  • maxdim: Maximum number of singular values to keep.
  • mindim: Minimum number of singular values to keep.

This operates on a single bond. For TreeTensorNetwork, the no-argument form truncate(ttn; kwargs...) sweeps all bonds and is generally preferred for full recompression after addition or subspace expansion.

See also: Base.truncate(::AbstractTreeTensorNetwork).

source