Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/ITensorNetworksNext.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ include("AlgorithmsInterfaceExtensions/AlgorithmsInterfaceExtensions.jl")
include("abstracttensornetwork.jl")
include("tensornetwork.jl")
include("itensornetworkoperator.jl")
include("normnetwork.jl")
include("normnetworkview.jl")
include("bilinearforms/abstractbilinearformnetwork.jl")
include("bilinearforms/normnetwork.jl")
include("bilinearforms/quadraticformnetwork.jl")
include("ITensorNetworkGenerators/ITensorNetworkGenerators.jl")
include("contraction_tree.jl")
include("prod_tensors.jl")
Expand Down
6 changes: 6 additions & 0 deletions src/beliefpropagation/beliefpropagation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,12 @@ factor_tensors(factors, vertex) = [factors[vertex]]
function factor_tensors(factors::NormNetwork, vertex)
return [kettensor(factors, vertex), bratensor(factors, vertex)]
end
function factor_tensors(factors::QuadraticFormNetwork, vertex)
return [
kettensor(factors, vertex), operatortensor(factors, vertex),
bratensor(factors, vertex),
]
end

# Contract the incoming messages into the source factor to form the (unnormalized) new message on
# `edge`.
Expand Down
189 changes: 189 additions & 0 deletions src/bilinearforms/abstractbilinearformnetwork.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
using DataGraphs: DataGraphs, get_vertex_data, is_vertex_assigned
using Dictionaries: Dictionaries, isinsertable, issettable
using Graphs: Graphs, edges, vertices
using ITensorBase: ITensorBase, conj, inds, nametype, rename
using NamedGraphs: NamedGraphs, decoded_vertex, encoded_graph, encoded_vertex

"""
abstract type AbstractBilinearFormNetwork{T, V, I} <: AbstractITensorNetwork{T, V}

Supertype of the lazy multi-layer networks built from a ket layer of type
`ITensorNetwork{T, V, I}` and a ket→bra index name mapping.

A subtype implements [`ketnetwork`](@ref) and [`branamemap`](@ref), from which the graph
structure, [`braname`](@ref), [`kettensor`](@ref) and [`bratensor`](@ref) are defined, and,
where it has an operator layer, [`operatornetwork`](@ref) and [`operatortensor`](@ref). The layers as whole networks are returned by [`ketnetwork`](@ref),
[`branetwork`](@ref) and [`operatornetwork`](@ref).
"""
abstract type AbstractBilinearFormNetwork{T, V, I} <: AbstractITensorNetwork{T, V} end

# The checks on a ket→bra name map shared by the bilinear-form constructors; `layers` are the
# networks other than `ket` whose index names a bra name must not reuse.
function check_branamemap(ket, braname, layers...)
if !issubset(linknames(ket), keys(braname))
error("every link name of the ket layer must have a bra name.")
end
if !allunique(braname)
error("the bra names of a bilinear-form network must be distinct.")
end
for name in braname
if has_dimname(ket, name) || any(layer -> has_dimname(layer, name), layers)
error("bra name $name is already an index name of another layer.")
end
end
return nothing
end

# ====================================== Graphs.jl ======================================= #

Graphs.edges(bn::AbstractBilinearFormNetwork) = edges(ketnetwork(bn))
Graphs.vertices(bn::AbstractBilinearFormNetwork) = vertices(ketnetwork(bn))

# ==================================== NamedGraphs.jl ==================================== #

function NamedGraphs.encoded_vertex(bn::AbstractBilinearFormNetwork, vertex)
return encoded_vertex(ketnetwork(bn), vertex)
end
function NamedGraphs.decoded_vertex(bn::AbstractBilinearFormNetwork, code::Integer)
return decoded_vertex(ketnetwork(bn), code)
end
NamedGraphs.encoded_graph(bn::AbstractBilinearFormNetwork) = encoded_graph(ketnetwork(bn))

# ==================================== DataGraphs.jl ===================================== #

function DataGraphs.is_vertex_assigned(bn::AbstractBilinearFormNetwork, vertex)
return isassigned(ketnetwork(bn), vertex)
end

# =================================== Dictionaries.jl ==================================== #

Dictionaries.issettable(::AbstractBilinearFormNetwork) = false
Dictionaries.isinsertable(::AbstractBilinearFormNetwork) = false

# ====================================== interface ======================================= #

# The name type of the indices, the same as the ket network's.
function ITensorBase.nametype(
::Type{<:AbstractBilinearFormNetwork{T, V, I}}
) where {T, V, I}
return I
end
ITensorBase.nametype(bn::AbstractBilinearFormNetwork) = nametype(typeof(bn))

"""
braname(bn::AbstractBilinearFormNetwork, name)

The bra-layer index name corresponding to the ket-layer index name `name`.
"""
function braname(bn::AbstractBilinearFormNetwork, name)
if !has_dimname(ketnetwork(bn), name)
error("index name $name not found underlying tensor network.")
end
# A name absent from the map has no separate bra copy and maps to itself: a site index of a
# norm network, or a site index a quadratic form's operator does not act on.
return get(branamemap(bn), name, name)
end

"""
branamemap(bn::AbstractBilinearFormNetwork)

The ket→bra name map, holding a bra name for each ket index name that has a separate bra copy.
"""
function branamemap end

"""
kettensor(bn::AbstractBilinearFormNetwork, vertex)

The ket-layer tensor at `vertex`.
"""
kettensor(bn::AbstractBilinearFormNetwork, vertex) = ketnetwork(bn)[vertex]

"""
operatortensor(bn::AbstractBilinearFormNetwork, vertex)

The operator-layer tensor at `vertex`, with its index names renamed so that its input legs
meet the ket layer and its output legs meet the bra layer.
"""
function operatortensor end

function conj_bratensor(bn::AbstractBilinearFormNetwork, vertex)
return rename(n -> braname(bn, n), kettensor(bn, vertex))
end

"""
bratensor(bn::AbstractBilinearFormNetwork, vertex)

The bra-layer tensor at `vertex`.
"""
bratensor(bn::AbstractBilinearFormNetwork, vertex) = conj(conj_bratensor(bn, vertex))

"""
ketnetwork(bn::AbstractBilinearFormNetwork)

The ket-layer network of `bn`.
"""
function ketnetwork end

"""
operatornetwork(bn::AbstractBilinearFormNetwork)

The operator-layer network of `bn`, for a subtype that has an operator layer.
"""
function operatornetwork end

"""
branetwork(bn::AbstractBilinearFormNetwork)

The bra-layer network of `bn`. Unless a subtype stores its bra layer as a network, this is a
`BraView`, whose tensors are built by [`bratensor`](@ref) when accessed.
"""
branetwork(bn::AbstractBilinearFormNetwork) = BraView(bn)

"""
struct BraView{T, V, I, P <: AbstractBilinearFormNetwork{T, V, I}} <: AbstractITensorNetwork{T, V}

The bra layer of the bilinear-form network `parent(view)`, with each vertex tensor built by
[`bratensor`](@ref) when accessed. Its graph structure and mutability are those of the parent.
"""
struct BraView{T, V, I, P <: AbstractBilinearFormNetwork{T, V, I}} <:
AbstractITensorNetwork{T, V}
parent::P
function BraView(parent::AbstractBilinearFormNetwork{T, V, I}) where {T, V, I}
return new{T, V, I, typeof(parent)}(parent)
end
end

Base.parent(nnv::BraView) = nnv.parent

# ==================================== DataGraphs.jl ===================================== #

DataGraphs.get_vertex_data(nnv::BraView, vertex) = bratensor(parent(nnv), vertex)
function DataGraphs.is_vertex_assigned(nnv::BraView, vertex)
return is_vertex_assigned(parent(nnv), vertex)
end

# ==================================== ITensorBase.jl ==================================== #

function ITensorBase.inds(nnv::BraView, vertex)
return conj.(inds(conj_bratensor(parent(nnv), vertex)))
end

# ====================================== Graphs.jl ======================================= #

Graphs.edges(nnv::BraView) = edges(parent(nnv))
Graphs.vertices(nnv::BraView) = vertices(parent(nnv))

# ==================================== NamedGraphs.jl ==================================== #

function NamedGraphs.encoded_vertex(nnv::BraView, vertex)
return encoded_vertex(parent(nnv), vertex)
end
function NamedGraphs.decoded_vertex(nnv::BraView, code::Integer)
return decoded_vertex(parent(nnv), code)
end
NamedGraphs.encoded_graph(nnv::BraView) = encoded_graph(parent(nnv))

# =================================== Dictionaries.jl ==================================== #

Dictionaries.issettable(nnv::BraView) = issettable(parent(nnv))
Dictionaries.isinsertable(nnv::BraView) = isinsertable(parent(nnv))
97 changes: 4 additions & 93 deletions src/normnetwork.jl → src/bilinearforms/normnetwork.jl
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
using Dictionaries: Dictionary, Indices, dictionary
using ITensorBase: ITensorBase, conj, nametype, rename, similar_operator
using ITensorBase: similar_operator
using ITensorNetworksNext

"""
struct NormNetwork{T, V, I} <: AbstractITensorNetwork{T, V}
struct NormNetwork{T, V, I} <: AbstractBilinearFormNetwork{T, V, I}

Lazy wrapper representing the norm `⟨tn|tn⟩` of `tn::ITensorNetwork{T, V, I}`,
together with a per-edge ket→bra name mapping that, for each index in the ket layer, defines
the name of the corresponding index in the bra layer.
"""
struct NormNetwork{T, V, I} <: AbstractITensorNetwork{T, V}
struct NormNetwork{T, V, I} <: AbstractBilinearFormNetwork{T, V, I}
ket::ITensorNetwork{T, V, I}
braname::Dictionary{I, I}
function NormNetwork(
Expand All @@ -31,18 +31,7 @@ function NormNetwork(tn::ITensorNetwork, linknames = ITensorNetworksNext.linknam
end

function check_input(::Type{<:NormNetwork}, ket, braname)
if !issubset(linknames(ket), keys(braname))
error("every link name of the ket layer must have a bra name.")
end
if !allunique(braname)
error("the bra names of a norm network must be distinct.")
end
for name in braname
if has_dimname(ket, name)
error("bra name $name is already an index name of the ket layer.")
end
end
return nothing
return check_branamemap(ket, braname)
end

function Base.eltype(::Type{<:NormNetwork})
Expand All @@ -51,21 +40,6 @@ function Base.eltype(::Type{<:NormNetwork})
)
end

# ====================================== Graphs.jl ======================================= #

Graphs.edges(nn::NormNetwork) = edges(ketnetwork(nn))
Graphs.vertices(nn::NormNetwork) = vertices(ketnetwork(nn))

# ==================================== NamedGraphs.jl ==================================== #

function NamedGraphs.encoded_vertex(nn::NormNetwork, vertex)
return encoded_vertex(ketnetwork(nn), vertex)
end
function NamedGraphs.decoded_vertex(nn::NormNetwork, code::Integer)
return decoded_vertex(ketnetwork(nn), code)
end
NamedGraphs.encoded_graph(nn::NormNetwork) = encoded_graph(ketnetwork(nn))

# ==================================== DataGraphs.jl ===================================== #

function DataGraphs.get_vertex_data(nn::NormNetwork, vertex)
Expand All @@ -74,74 +48,11 @@ function DataGraphs.get_vertex_data(nn::NormNetwork, vertex)
)
end

function DataGraphs.is_vertex_assigned(nn::NormNetwork, vertex)
return isassigned(ketnetwork(nn), vertex)
end

# =================================== Dictionaries.jl ==================================== #

Dictionaries.issettable(::NormNetwork) = false
Dictionaries.isinsertable(::NormNetwork) = false

# ====================================== interface ======================================= #

# The name type of the indices, the same as the ket network's.
ITensorBase.nametype(::Type{<:NormNetwork{T, V, I}}) where {T, V, I} = I
ITensorBase.nametype(nn::NormNetwork) = nametype(typeof(nn))

"""
ketnetwork(nn::NormNetwork)

The ket-layer network of `nn`.
"""
ketnetwork(nn::NormNetwork) = nn.ket

"""
branetwork(nn::NormNetwork)

The bra-layer network of `nn`, a `BraView` whose tensors are built by [`bratensor`](@ref) when
accessed.
"""
branetwork(nn::NormNetwork) = BraView(nn)

"""
branamemap(nn::NormNetwork)

The ket→bra name map, holding a bra name for each ket index name that has a separate bra copy.
"""
branamemap(nn::NormNetwork) = nn.braname

"""
braname(nn::NormNetwork, name)

The bra-layer index name corresponding to the ket-layer index name `name`.
"""
function braname(nn::NormNetwork, name)
if !has_dimname(ketnetwork(nn), name)
error("index name $name not found underlying tensor network.")
end
# The names absent from the map are the site indices, which map to themselves.
return get(branamemap(nn), name, name)
end

"""
kettensor(nn::NormNetwork, vertex)

The ket-layer tensor at `vertex`.
"""
kettensor(nn::NormNetwork, vertex) = ketnetwork(nn)[vertex]

function conj_bratensor(nn::NormNetwork, vertex)
return rename(n -> braname(nn, n), kettensor(nn, vertex))
end

"""
bratensor(nn::NormNetwork, vertex)

The bra-layer tensor at `vertex`.
"""
bratensor(nn::NormNetwork, vertex) = conj(conj_bratensor(nn, vertex))

"""
flatten_network(nn::NormNetwork) -> ITensorNetwork

Expand Down
Loading
Loading