Tree Tensor Networks

Overview

A TreeTensorNetwork (alias TTN) is an ITensorNetwork whose underlying graph is a tree (no cycles). This additional structure enables exact, efficient canonical gauges via QR decomposition — a key ingredient in variational algorithms such as DMRG and TDVP.

A TreeTensorNetwork carries an extra piece of metadata: the ortho_region, which records which vertices currently form the orthogonality center of the network. Algorithms update this field as the gauge changes.

MPS (matrix product states) are the special case of a TreeTensorNetwork on a 1D path graph. The mps constructor enforces this topology and provides a convenient interface for 1D calculations.

Construction

From an IndsNetwork or graph

using Graphs: vertices
using ITensorNetworks: ITensorNetwork, TreeTensorNetwork, mps, ortho_region, orthogonalize,
    random_mps, random_ttn, siteinds, ttn
using ITensors: ITensors
using LinearAlgebra: norm
using NamedGraphs.NamedGraphGenerators: named_comb_tree

# Comb-tree TTN (a popular tree topology for 2D-like systems)
g = named_comb_tree((3, 2))
sites = siteinds("S=1/2", g)

psi = ttn(sites)  # zero-initialised
psi = ttn(v -> "Up", sites)  # product state

# Random TTN
psi = random_ttn(sites; link_space = 2)

# 1D MPS
s1d = siteinds("S=1/2", 6)
mps_state = mps(v -> "Up", s1d)  # product MPS
mps_state = random_mps(s1d; link_space = 2)
ITensorNetworks.TreeTensorNetwork{Int64} with 6 vertices:
6-element NamedGraphs.OrderedDictionaries.OrderedIndices{Int64}:
 1
 2
 3
 4
 5
 6

and 5 edge(s):
1 => 2
2 => 3
3 => 4
4 => 5
5 => 6

with vertex data:
6-element Dictionaries.Dictionary{Int64, Any}:
 1 │ ((dim=2|id=367|"S=1/2,Site,n=1"), (dim=2|id=616|"1,2"))
 2 │ ((dim=2|id=894|"S=1/2,Site,n=2"), (dim=2|id=616|"1,2"), (dim=2|id=730|"2,3…
 3 │ ((dim=2|id=614|"S=1/2,Site,n=3"), (dim=2|id=730|"2,3"), (dim=2|id=396|"3,4…
 4 │ ((dim=2|id=859|"S=1/2,Site,n=4"), (dim=2|id=396|"3,4"), (dim=2|id=518|"4,5…
 5 │ ((dim=2|id=824|"S=1/2,Site,n=5"), (dim=2|id=518|"4,5"), (dim=2|id=689|"5,6…
 6 │ ((dim=2|id=334|"S=1/2,Site,n=6"), (dim=2|id=689|"5,6"))
ITensorNetworks.ttnFunction
ttn(args...; ortho_region=nothing) -> TreeTensorNetwork

Construct a TreeTensorNetwork (TTN) using the same interface as ITensorNetwork. All positional and keyword arguments are forwarded to the ITensorNetwork constructor.

If ortho_region is not specified, no particular gauge is assumed. Call orthogonalize to impose a gauge.

Example

julia> using NamedGraphs.NamedGraphGenerators: named_comb_tree

julia> g = named_comb_tree((2, 2));

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

julia> psi = ttn(v -> "Up", s);

See also: mps, random_ttn, TreeTensorNetwork.

source
ttn(a::ITensor, is::IndsNetwork; ortho_region=..., kwargs...) -> TreeTensorNetwork

Decompose a dense ITensor a into a TreeTensorNetwork with the tree structure described by the IndsNetwork is.

Successive QR/SVD factorizations are applied following a post-order DFS traversal from the root vertex, then the network is orthogonalized to ortho_region (defaults to the root). Extra kwargs (e.g. cutoff, maxdim) are forwarded to the factorization.

Example

julia> using NamedGraphs.NamedGraphGenerators: named_comb_tree

julia> using ITensors: ITensors

julia> g = named_comb_tree((3, 1));

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

julia> A = ITensors.random_itensor(only(s[(1, 1)]), only(s[(2, 1)]), only(s[(3, 1)]));

julia> ttn_A = ttn(A, s);
source
ttn(os::OpSum, sites::IndsNetwork{<:Index}; kwargs...)
ttn(eltype::Type{<:Number}, os::OpSum, sites::IndsNetwork{<:Index}; kwargs...)

Convert an OpSum object os to a TreeTensorNetwork, with indices given by sites.

source
ITensorNetworks.mpsFunction
mps(args...; ortho_region=nothing) -> TreeTensorNetwork

Construct a matrix product state (MPS) as a TreeTensorNetwork on a 1D path graph. The interface is identical to ttn but is intended for 1D (chain) topologies.

See also: ttn, random_mps.

source
mps(f, is::Vector{<:Index}; kwargs...) -> TreeTensorNetwork

Construct a matrix product state (MPS) from a function f and a flat vector of site indices is. The indices are arranged on a 1D path graph automatically.

Example

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

julia> psi = mps(v -> "Up", s);
source
ITensorNetworks.random_ttnFunction
random_ttn(args...; kwargs...) -> TreeTensorNetwork

Construct a random, unit-norm TreeTensorNetwork. Arguments are forwarded to random_tensornetwork, which accepts the same interface as ITensorNetwork.

Example

julia> using NamedGraphs.NamedGraphGenerators: named_comb_tree

julia> g = named_comb_tree((2, 2));

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

julia> psi = random_ttn(s; link_space = 2);

See also: ttn, random_mps.

source
ITensorNetworks.random_mpsFunction
random_mps(args...; kwargs...) -> TreeTensorNetwork

Construct a random, unit-norm matrix product state (MPS) as a TreeTensorNetwork. Arguments are forwarded to random_ttn.

Example

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

julia> psi = random_mps(s; link_space = 2);

See also: mps, random_ttn.

source
random_mps(f, is::Vector{<:Index}; kwargs...) -> TreeTensorNetwork

Construct a random MPS from a function f and a flat vector of site indices is.

source
random_mps(s::Vector{<:Index}; kwargs...) -> TreeTensorNetwork

Construct a random MPS from a flat vector of site indices s.

source

The TreeTensorNetwork type and conversion

The TreeTensorNetwork struct wraps an ITensorNetwork and records the current orthogonality region. Use the TreeTensorNetwork constructor to convert a plain ITensorNetwork with tree topology into a TTN, and ITensorNetwork to strip the gauge metadata when you need a plain network again.

itn = ITensorNetwork(psi)  # TTN → ITensorNetwork
psi = TreeTensorNetwork(itn)  # ITensorNetwork → TTN
ITensorNetworks.TreeTensorNetwork{Tuple{Int64, Int64}} with 6 vertices:
6-element NamedGraphs.OrderedDictionaries.OrderedIndices{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
 (3, 1)
 (1, 2)
 (2, 2)
 (3, 2)

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

with vertex data:
6-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}:
 (1, 1) │ ((dim=2|id=179|"S=1/2,Site,n=1×1"), (dim=2|id=884|"1×1,2×1"), (dim=2|…
 (2, 1) │ ((dim=2|id=198|"S=1/2,Site,n=2×1"), (dim=2|id=884|"1×1,2×1"), (dim=2|…
 (3, 1) │ ((dim=2|id=700|"S=1/2,Site,n=3×1"), (dim=2|id=579|"2×1,3×1"), (dim=2|…
 (1, 2) │ ((dim=2|id=187|"S=1/2,Site,n=1×2"), (dim=2|id=769|"1×1,1×2"))
 (2, 2) │ ((dim=2|id=982|"S=1/2,Site,n=2×2"), (dim=2|id=658|"2×1,2×2"))
 (3, 2) │ ((dim=2|id=903|"S=1/2,Site,n=3×2"), (dim=2|id=292|"3×1,3×2"))
ITensorNetworks.TreeTensorNetworkType
TreeTensorNetwork{V} <: AbstractTreeTensorNetwork{V}

A tensor network whose underlying graph is a tree. In addition to the tensor data, it tracks an ortho_region: the set of vertices that currently form the orthogonality center of the network.

TTN is an alias for TreeTensorNetwork.

Use ttn or mps to construct instances, and orthogonalize to bring the network into a canonical gauge.

See also: ITensorNetwork, ttn, mps, random_ttn.

source
ITensorNetworks.ITensorNetworkMethod
ITensorNetwork(tn::TreeTensorNetwork) -> ITensorNetwork

Convert a TreeTensorNetwork to a plain ITensorNetwork, discarding orthogonality metadata. The returned network shares the same underlying tensor data.

See also: TreeTensorNetwork, ttn.

source

From a dense ITensor

A dense tensor can be decomposed into a TTN by successive QR/SVD factorisations along the tree edges. Truncation parameters (e.g. cutoff, maxdim) are forwarded to the factorisation step.

g = named_comb_tree((3, 1))
sites = siteinds("S=1/2", g)
A = ITensors.random_itensor(only(sites[(1, 1)]), only(sites[(2, 1)]), only(sites[(3, 1)]))
ttn_A = ttn(A, sites)
ITensorNetworks.TreeTensorNetwork{Tuple{Int64, Int64}} with 3 vertices:
3-element NamedGraphs.OrderedDictionaries.OrderedIndices{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
 (3, 1)

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

with vertex data:
3-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}:
 (1, 1) │ ((dim=2|id=974|"S=1/2,Site,n=1×1"), (dim=2|id=700|"1×1,2×1"))
 (2, 1) │ ((dim=2|id=729|"S=1/2,Site,n=2×1"), (dim=2|id=631|"2×1,3×1"), (dim=2|…
 (3, 1) │ ((dim=2|id=757|"S=1/2,Site,n=3×1"), (dim=2|id=631|"2×1,3×1"))
ITensorNetworks.ttnMethod
ttn(a::ITensor, is::IndsNetwork; ortho_region=..., kwargs...) -> TreeTensorNetwork

Decompose a dense ITensor a into a TreeTensorNetwork with the tree structure described by the IndsNetwork is.

Successive QR/SVD factorizations are applied following a post-order DFS traversal from the root vertex, then the network is orthogonalized to ortho_region (defaults to the root). Extra kwargs (e.g. cutoff, maxdim) are forwarded to the factorization.

Example

julia> using NamedGraphs.NamedGraphGenerators: named_comb_tree

julia> using ITensors: ITensors

julia> g = named_comb_tree((3, 1));

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

julia> A = ITensors.random_itensor(only(s[(1, 1)]), only(s[(2, 1)]), only(s[(3, 1)]));

julia> ttn_A = ttn(A, s);
source

Orthogonal Gauge

One of the most powerful features of tree tensor networks is the ability to bring the network into an orthogonal gauge in linear time. When the network is in a gauge centered on vertex v, all tensors away from v are isometric with respect to the bond pointing toward v. This makes computing local observables, inner products, and eigenvalue problems numerically efficient and stable.

The current orthogonality center is tracked by the ortho_region field.

v = collect(vertices(psi))[1]
v1 = collect(vertices(psi))[1]
v2 = collect(vertices(psi))[2]
vs = [v]
psi = orthogonalize(psi, v)  # QR-sweep to put ortho center at vertex v
psi = orthogonalize(psi, [v1, v2])  # two-site center (for nsites=2 sweeps)
ortho_region(psi)  # query current ortho region (returns an index set)
2-element Dictionaries.Indices{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
ITensorNetworks.orthogonalizeFunction
orthogonalize(ttn::AbstractTreeTensorNetwork, region; kwargs...) -> TreeTensorNetwork

Bring ttn into an orthogonal gauge with orthogonality center at region. region may be a single vertex or a vector of vertices.

QR decompositions are applied along the unique tree path from the current ortho_region to region, so that all tensors outside region are left- or right-orthogonal with respect to that path.

Example

julia> using NamedGraphs.NamedGraphGenerators: named_comb_tree

julia> using Graphs: vertices

julia> g = named_comb_tree((2, 2));

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

julia> psi = random_ttn(s; link_space = 2);

julia> vs = collect(vertices(psi));

julia> psi = orthogonalize(psi, vs[1]);

julia> psi = orthogonalize(psi, [vs[1], vs[2]]);

See also: ortho_region, truncate.

source

Bond Truncation

After algorithms that grow the bond dimension (e.g. addition, subspace expansion), use truncate to recompress the network. For TreeTensorNetwork there are two forms:

  • Whole-network recompression (TTN-specific): truncate(ttn; kwargs...) sweeps from the leaves to the root, orthogonalising and truncating every bond in sequence. This is the preferred form after addition or DMRG expansion.
  • Single-bond truncation (available for any ITensorNetwork): truncate(tn, edge; kwargs...) truncates one bond by SVD — see the ITensor Networks page.
psi = truncate(psi; cutoff = 1e-10, maxdim = 50)
ITensorNetworks.TreeTensorNetwork{Tuple{Int64, Int64}} with 6 vertices:
6-element NamedGraphs.OrderedDictionaries.OrderedIndices{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
 (3, 1)
 (1, 2)
 (2, 2)
 (3, 2)

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

with vertex data:
6-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}:
 (1, 1) │ ((dim=2|id=179|"S=1/2,Site,n=1×1"), (dim=2|id=356|"1×1,2×1"), (dim=2|…
 (2, 1) │ ((dim=2|id=198|"S=1/2,Site,n=2×1"), (dim=2|id=808|"2×1,3×1"), (dim=2|…
 (3, 1) │ ((dim=2|id=700|"S=1/2,Site,n=3×1"), (dim=2|id=803|"3×1,3×2"), (dim=2|…
 (1, 2) │ ((dim=2|id=187|"S=1/2,Site,n=1×2"), (dim=2|id=171|"1×1,1×2"))
 (2, 2) │ ((dim=2|id=982|"S=1/2,Site,n=2×2"), (dim=2|id=384|"2×1,2×2"))
 (3, 2) │ ((dim=2|id=903|"S=1/2,Site,n=3×2"), (dim=2|id=803|"3×1,3×2"))

The sweep-based form orthogonalises each bond before truncating it, so truncation errors are controlled. All keyword arguments accepted by ITensors.svd (e.g. cutoff, maxdim, mindim) are forwarded.

Base.truncateMethod
truncate(tn::AbstractTreeTensorNetwork; root_vertex=..., kwargs...) -> TreeTensorNetwork

Truncate the bond dimensions of tn by sweeping from the leaves toward root_vertex and performing an SVD-based truncation on each bond.

Before truncating each bond the relevant subtree is first orthogonalized (controlled truncation), ensuring that discarded singular values correspond to actual truncation error. Truncation parameters are passed through kwargs.

Keyword Arguments

  • root_vertex: Root of the DFS traversal. Defaults to default_root_vertex(tn).
  • cutoff: Drop singular values smaller than this threshold (relative or absolute).
  • maxdim: Maximum number of singular values to retain on each bond.

Example

julia> using NamedGraphs.NamedGraphGenerators: named_comb_tree

julia> g = named_comb_tree((2, 2));

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

julia> psi = random_ttn(s; link_space = 4);

julia> psi_trunc = truncate(psi; cutoff = 1e-10, maxdim = 2);

See also: orthogonalize.

source

Addition and Arithmetic

Two TTNs with the same graph and site indices can be summed. The result has bond dimension equal to the sum of the two inputs, and can be recompressed with truncate.

psi1, psi2 = psi, psi
psi3 = psi1 + psi2  # or add(psi1, psi2)
psi3 = truncate(psi3; cutoff = 1e-10, maxdim = 50)

2 * psi  # scalar multiplication
psi / norm(psi)  # manual normalisation
ITensorNetworks.TreeTensorNetwork{Tuple{Int64, Int64}} with 6 vertices:
6-element NamedGraphs.OrderedDictionaries.OrderedIndices{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 1)
 (3, 1)
 (1, 2)
 (2, 2)
 (3, 2)

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

with vertex data:
6-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}:
 (1, 1) │ ((dim=2|id=179|"S=1/2,Site,n=1×1"), (dim=2|id=356|"1×1,2×1"), (dim=2|…
 (2, 1) │ ((dim=2|id=198|"S=1/2,Site,n=2×1"), (dim=2|id=808|"2×1,3×1"), (dim=2|…
 (3, 1) │ ((dim=2|id=700|"S=1/2,Site,n=3×1"), (dim=2|id=803|"3×1,3×2"), (dim=2|…
 (1, 2) │ ((dim=2|id=187|"S=1/2,Site,n=1×2"), (dim=2|id=171|"1×1,1×2"))
 (2, 2) │ ((dim=2|id=982|"S=1/2,Site,n=2×2"), (dim=2|id=384|"2×1,2×2"))
 (3, 2) │ ((dim=2|id=903|"S=1/2,Site,n=3×2"), (dim=2|id=803|"3×1,3×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
add(tns::AbstractTreeTensorNetwork...; kwargs...) -> TreeTensorNetwork

Add tree tensor networks together by growing the bond dimension. Equivalent to +(tns...).

See also: +(tns...), truncate.

source
Base.:+Method
+(tn1::AbstractTreeTensorNetwork, tn2::AbstractTreeTensorNetwork; alg="directsum", kwargs...) -> TreeTensorNetwork

Add two tree tensor networks by growing the bond dimension, returning a network that represents the state tn1 + tn2. The bond dimension of the result is the sum of the bond dimensions of the two inputs.

Use truncate afterward to compress the resulting network.

Keyword Arguments

  • alg="directsum": Algorithm for combining the networks. Currently only "directsum" is supported for trees.

Both networks must share the same graph structure and site indices.

See also: add, truncate.

source