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.

Construction

From an OpSum (Hamiltonian)

A common way to obtain a Hamiltonian-shaped TTN is to convert an OpSum over an IndsNetwork of site indices.

ITensorNetworks.TreeTensorNetworkMethod
TreeTensorNetwork(os::OpSum, sites::IndsNetwork{<:Index}; kwargs...)
TreeTensorNetwork(eltype::Type{<:Number}, os::OpSum, sites::IndsNetwork{<:Index}; kwargs...)

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

source

From an existing ITensorNetwork

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.

using Graphs: edges, vertices
using ITensorNetworks: ITensorNetwork, TreeTensorNetwork, ortho_region, orthogonalize,
    siteinds
using ITensors: ITensors, Index, random_itensor
using LinearAlgebra: norm
using NamedGraphs: NamedGraph
using NamedGraphs.GraphsExtensions: incident_edges
using NamedGraphs.NamedGraphGenerators: named_comb_tree

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

# Build a structured `ITensorNetwork` with shared link indices on each edge
χ = 2
links = Dict(e => Index(χ, "Link") for e in edges(g))
tensors = Dict(map(collect(vertices(g))) do v
    site_v = sites[v]
    link_v = [haskey(links, e) ? links[e] : links[reverse(e)] for e in incident_edges(g, v)]
    return v => random_itensor(site_v..., link_v...)
end)
itn = ITensorNetwork(tensors)
psi = TreeTensorNetwork(itn)
ITensorNetworks.TreeTensorNetwork{Tuple{Int64, Int64}} with 6 vertices:
6-element NamedGraphs.OrderedDictionaries.OrderedIndices{Tuple{Int64, Int64}}:
 (3, 2)
 (1, 2)
 (3, 1)
 (1, 1)
 (2, 2)
 (2, 1)

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

with vertex data:
6-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}:
 (3, 2) │ ((dim=2|id=990|"S=1/2,Site,n=3×2"), (dim=2|id=848|"Link"))
 (1, 2) │ ((dim=2|id=1|"S=1/2,Site,n=1×2"), (dim=2|id=62|"Link"))
 (3, 1) │ ((dim=2|id=464|"S=1/2,Site,n=3×1"), (dim=2|id=872|"Link"), (dim=2|id=…
 (1, 1) │ ((dim=2|id=794|"S=1/2,Site,n=1×1"), (dim=2|id=260|"Link"), (dim=2|id=…
 (2, 2) │ ((dim=2|id=994|"S=1/2,Site,n=2×2"), (dim=2|id=596|"Link"))
 (2, 1) │ ((dim=2|id=92|"S=1/2,Site,n=2×1"), (dim=2|id=260|"Link"), (dim=2|id=8…

To strip the gauge metadata back to a plain ITensorNetwork:

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

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

with vertex data:
6-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}:
 (3, 2) │ ((dim=2|id=990|"S=1/2,Site,n=3×2"), (dim=2|id=848|"Link"))
 (1, 2) │ ((dim=2|id=1|"S=1/2,Site,n=1×2"), (dim=2|id=62|"Link"))
 (3, 1) │ ((dim=2|id=464|"S=1/2,Site,n=3×1"), (dim=2|id=872|"Link"), (dim=2|id=…
 (1, 1) │ ((dim=2|id=794|"S=1/2,Site,n=1×1"), (dim=2|id=260|"Link"), (dim=2|id=…
 (2, 2) │ ((dim=2|id=994|"S=1/2,Site,n=2×2"), (dim=2|id=596|"Link"))
 (2, 1) │ ((dim=2|id=92|"S=1/2,Site,n=2×1"), (dim=2|id=260|"Link"), (dim=2|id=8…

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}}:
 (3, 2)
 (1, 2)
ITensorNetworks.orthogonalizeFunction
orthogonalize(ttn::AbstractTreeTensorNetwork, region) -> 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.

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}}:
 (3, 2)
 (1, 2)
 (3, 1)
 (1, 1)
 (2, 2)
 (2, 1)

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

with vertex data:
6-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}:
 (3, 2) │ ((dim=2|id=990|"S=1/2,Site,n=3×2"), (dim=2|id=743|"3×1,3×2"))
 (1, 2) │ ((dim=2|id=1|"S=1/2,Site,n=1×2"), (dim=2|id=59|"1×1,1×2"))
 (3, 1) │ ((dim=2|id=464|"S=1/2,Site,n=3×1"), (dim=2|id=419|"2×1,3×1"), (dim=2|…
 (1, 1) │ ((dim=2|id=794|"S=1/2,Site,n=1×1"), (dim=2|id=59|"1×1,1×2"), (dim=2|i…
 (2, 2) │ ((dim=2|id=994|"S=1/2,Site,n=2×2"), (dim=2|id=145|"2×1,2×2"))
 (2, 1) │ ((dim=2|id=92|"S=1/2,Site,n=2×1"), (dim=2|id=877|"1×1,2×1"), (dim=2|i…

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.

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}}:
 (3, 2)
 (1, 2)
 (3, 1)
 (1, 1)
 (2, 2)
 (2, 1)

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

with vertex data:
6-element Dictionaries.Dictionary{Tuple{Int64, Int64}, Any}:
 (3, 2) │ ((dim=2|id=990|"S=1/2,Site,n=3×2"), (dim=2|id=743|"3×1,3×2"))
 (1, 2) │ ((dim=2|id=1|"S=1/2,Site,n=1×2"), (dim=2|id=59|"1×1,1×2"))
 (3, 1) │ ((dim=2|id=464|"S=1/2,Site,n=3×1"), (dim=2|id=419|"2×1,3×1"), (dim=2|…
 (1, 1) │ ((dim=2|id=794|"S=1/2,Site,n=1×1"), (dim=2|id=59|"1×1,1×2"), (dim=2|i…
 (2, 2) │ ((dim=2|id=994|"S=1/2,Site,n=2×2"), (dim=2|id=145|"2×1,2×2"))
 (2, 1) │ ((dim=2|id=92|"S=1/2,Site,n=2×1"), (dim=2|id=877|"1×1,2×1"), (dim=2|i…
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