Skip to content
Merged
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
8 changes: 1 addition & 7 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "ITensorNetworksNext"
uuid = "302f2e75-49f0-4526-aef7-d8ba550cb06c"
version = "0.5.0"
version = "0.6.0"
authors = ["ITensor developers <support@itensor.org> and contributors"]

[workspace]
Expand All @@ -10,11 +10,9 @@ projects = ["benchmark", "dev", "docs", "examples", "test"]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
AlgorithmsInterface = "d1e3940c-cd12-4505-8585-b0a4b322527d"
BackendSelection = "680c2d7c-f67a-4cc9-ae9c-da132b1447a5"
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
DataGraphs = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a"
Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4"
FunctionImplementations = "7c7cc465-9c6a-495f-bdd1-f42428e86d0c"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
ITensorBase = "4795dd04-0d67-49bb-8f44-b89c448a1dc7"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand All @@ -26,7 +24,6 @@ SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
SplitApplyCombine = "03a91e81-4c3e-53e1-a0a4-9c0c8f19dd66"
TensorAlgebra = "68bd88dc-f39d-4e12-b2ca-f046b68fcc6a"
TermInterface = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c"
TypeParameterAccessors = "7e5a90cf-f82e-492e-a09b-e3e26432c138"
WrappedUnions = "325db55a-9c6c-5b90-b1a2-ec87e7a38c44"

[weakdeps]
Expand All @@ -39,11 +36,9 @@ ITensorNetworksNextTensorOperationsExt = "TensorOperations"
AbstractTrees = "0.4.5"
Adapt = "4.3"
AlgorithmsInterface = "0.1"
BackendSelection = "0.1.6"
Combinatorics = "1"
DataGraphs = "0.4"
Dictionaries = "0.4.5"
FunctionImplementations = "0.4.1"
Graphs = "1.13.1"
ITensorBase = "0.6.2"
LinearAlgebra = "1.10"
Expand All @@ -56,6 +51,5 @@ SplitApplyCombine = "1.2.3"
TensorAlgebra = "0.9.7"
TensorOperations = "5.3.1"
TermInterface = "2"
TypeParameterAccessors = "0.4.4"
WrappedUnions = "0.3"
julia = "1.10"
2 changes: 1 addition & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ path = ".."
[compat]
Documenter = "1"
ITensorFormatter = "0.2.27"
ITensorNetworksNext = "0.5"
ITensorNetworksNext = "0.6"
Literate = "2"
2 changes: 1 addition & 1 deletion examples/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ ITensorNetworksNext = "302f2e75-49f0-4526-aef7-d8ba550cb06c"
path = ".."

[compat]
ITensorNetworksNext = "0.5"
ITensorNetworksNext = "0.6"
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module ITensorNetworksNextTensorOperationsExt

using BackendSelection: @Algorithm_str, Algorithm
using ITensorBase: denamed, inds
using ITensorNetworksNext.LazyITensors.TermInterface: arguments
using ITensorNetworksNext.LazyITensors: LazyITensors, ismul, substitute, symnameddims
using ITensorNetworksNext.LazyITensors:
LazyITensors, Optimal, ismul, substitute, symnameddims
using TensorOperations: TensorOperations, optimaltree

function contraction_tree_to_expr(f, tree)
Expand All @@ -14,7 +14,7 @@ function contraction_tree_to_expr(f, tree)
end
end

function LazyITensors.optimize_contraction_order(alg::Algorithm"optimal", a)
function LazyITensors.optimize_contraction_order(alg::Optimal, a)
@assert ismul(a)
ts = arguments(a)
inds_network = collect.(inds.(ts))
Expand Down
10 changes: 7 additions & 3 deletions src/LazyITensors/evaluation_order.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,19 @@ function optimize_evaluation_order(
return optimize_evaluation_order(alg, a)
end

using BackendSelection: @Algorithm_str, Algorithm
default_optimize_evaluation_order_alg(a) = Algorithm"eager"()
abstract type EvaluationOrderAlgorithm end
struct Greedy <: EvaluationOrderAlgorithm end
# `Optimal` finds the cost-optimal contraction order. The method is provided by
# the TensorOperations extension.
struct Optimal <: EvaluationOrderAlgorithm end
default_optimize_evaluation_order_alg(a) = Greedy()

function optimize_contraction_order(alg, a)
return error("`alg = $alg` not supported.")
end

using Combinatorics: combinations
function optimize_contraction_order(alg::Algorithm"eager", a)
function optimize_contraction_order(alg::Greedy, a)
@assert ismul(a)
arity(a) in (1, 2) && return a
a1, a2 = argmin(combinations(arguments(a), 2)) do (a1, a2)
Expand Down
3 changes: 1 addition & 2 deletions src/TensorNetworkGenerators/delta_network.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using ..ITensorNetworksNext: TensorNetwork
using FunctionImplementations: zero!
using Graphs: AbstractGraph
using ITensorBase: NamedUnitRange, denamed, name, nameddims
using NamedGraphs.GraphsExtensions: incident_edges
Expand All @@ -22,7 +21,7 @@ diagview(a::AbstractArray) = @view a[diagindices(a)]

function diagonaltensor(diag::AbstractVector, ax::Tuple{Vararg{AbstractUnitRange}})
a = similar(diag, ax)
zero!(a)
fill!(a, zero(eltype(a)))
diagview(a) .= diag
return a
end
Expand Down
1 change: 0 additions & 1 deletion src/abstracttensornetwork.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Adapt: Adapt, adapt
using BackendSelection: @Algorithm_str, Algorithm
using DataGraphs: DataGraphs, AbstractDataGraph, edge_data, set_vertex_data!,
underlying_graph, underlying_graph_type, vertex_data
using Dictionaries: Dictionary
Expand Down
5 changes: 2 additions & 3 deletions src/beliefpropagation/beliefpropagation.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using .AlgorithmsInterfaceExtensions:
AlgorithmsInterfaceExtensions as AIE, StopWhenConverged, iterate_diff
using AlgorithmsInterface: AlgorithmsInterface as AI
using BackendSelection: @Algorithm_str, Algorithm
using DataGraphs: edge_data
using Graphs: AbstractEdge, edges, edgetype, has_edge, vertices
using ITensorBase: AbstractITensor
Expand Down Expand Up @@ -236,14 +235,14 @@ end

@kwdef struct SimpleMessageUpdate{ContractionAlg} <: MessageUpdateAlgorithm
normalize::Bool = true
contraction_alg::ContractionAlg = Algorithm"exact"
contraction_alg::ContractionAlg = Exact()
end

function message_update!(algorithm::SimpleMessageUpdate, cache, factors, edge)
messages = collect(incoming_messages(cache, edge))
factor = factors[src(edge)]

new_message = contract_network([messages; [factor]]; algorithm.contraction_alg)
new_message = contract_network([messages; [factor]]; alg = algorithm.contraction_alg)

if algorithm.normalize
message_norm = sum(new_message)
Expand Down
61 changes: 25 additions & 36 deletions src/contract_network.jl
Original file line number Diff line number Diff line change
@@ -1,47 +1,35 @@
using BackendSelection: @Algorithm_str, Algorithm
using Base.Broadcast: materialize
using ITensorNetworksNext.LazyITensors:
Mul, lazy, optimize_evaluation_order, substitute, symnameddims
using Base: @kwdef
using ITensorNetworksNext.LazyITensors: EvaluationOrderAlgorithm, Greedy, Mul, lazy,
optimize_evaluation_order, substitute, symnameddims

# This is related to `MatrixAlgebraKit.select_algorithm`.
# TODO: Define this in BackendSelection.jl.
backend_value(::Algorithm{alg}) where {alg} = alg
using BackendSelection: parameters
function merge_parameters(alg::Algorithm; kwargs...)
return Algorithm(backend_value(alg); merge(parameters(alg), kwargs)...)
# `contract_network`
@kwdef struct Exact{Order, OrderAlg}
order::Order = nothing
order_alg::OrderAlg = Greedy()
end
to_algorithm(alg::Algorithm; kwargs...) = merge_parameters(alg; kwargs...)
to_algorithm(alg; kwargs...) = Algorithm(alg; kwargs...)

# `contract_network`
function contract_network(alg::Algorithm, tn)
function contract_network(alg, tn)
return throw(ArgumentError("`contract_network` algorithm `$(alg)` not implemented."))
end
function default_kwargs(::typeof(contract_network), tn)
return (; alg = Algorithm"exact"(; order_alg = Algorithm"eager"()))
end
function contract_network(tn; alg = default_kwargs(contract_network, tn).alg, kwargs...)
return contract_network(to_algorithm(alg; kwargs...), tn)
function contract_network(tn; alg = Exact())
return contract_network(alg, tn)
end

# `contract_network(::Algorithm"exact", ...)`
function get_order(alg::Algorithm"exact", tn)
# Allow specifying either `order` or `order_alg`.
order = get(alg, :order, nothing)
order = if !isnothing(order)
order
# `contract_network(::Exact, ...)`
function get_order(alg::Exact, tn)
# Allow specifying either an explicit `order` or an `order_alg` to compute one.
order = if !isnothing(alg.order)
alg.order
else
default_order_alg = default_kwargs(contraction_order, tn).alg
order_alg = get(alg, :order_alg, default_order_alg)
# TODO: Capture other keyword arguments and pass them to `contraction_order`.
contraction_order(tn; alg = order_alg)
contraction_order(tn; alg = alg.order_alg)
end
# Contraction order may or may not have indices attached, canonicalize the format
# by attaching indices.
subs = Dict(symnameddims(i) => symnameddims(i, Tuple(axes(tn[i]))) for i in keys(tn))
return substitute(order, subs)
end
function contract_network(alg::Algorithm"exact", tn)
function contract_network(alg::Exact, tn)
order = get_order(alg, tn)
syms_to_ts = Dict(symnameddims(i, Tuple(axes(tn[i]))) => lazy(tn[i]) for i in keys(tn))
tn_expression = substitute(order, syms_to_ts)
Expand All @@ -50,20 +38,21 @@ end

# `contraction_order`
function contraction_order end
default_kwargs(::typeof(contraction_order), tn) = (; alg = Algorithm"eager"())
function contraction_order(tn; alg = default_kwargs(contraction_order, tn).alg, kwargs...)
return contraction_order(to_algorithm(alg; kwargs...), tn)
function contraction_order(tn; alg = Greedy())
return contraction_order(alg, tn)
end
# Convert the tensor network to a flat symbolic multiplication expression.
function contraction_order(alg::Algorithm"flat", tn)
struct Flat end
function contraction_order(alg::Flat, tn)
# Same as: `reduce((a, b) -> *(a, b; flatten = true), syms)`.
syms = vec([symnameddims(i, Tuple(axes(tn[i]))) for i in keys(tn)])
return lazy(Mul(syms))
end
function contraction_order(alg::Algorithm"left_associative", tn)
struct LeftAssociative end
function contraction_order(alg::LeftAssociative, tn)
return prod(i -> symnameddims(i, Tuple(axes(tn[i]))), keys(tn))
end
function contraction_order(alg::Algorithm, tn)
s = contraction_order(Algorithm"flat"(), tn)
function contraction_order(alg::EvaluationOrderAlgorithm, tn)
s = contraction_order(Flat(), tn)
return optimize_evaluation_order(s; alg)
end
4 changes: 1 addition & 3 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
AlgorithmsInterface = "d1e3940c-cd12-4505-8585-b0a4b322527d"
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
BackendSelection = "680c2d7c-f67a-4cc9-ae9c-da132b1447a5"
DataGraphs = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a"
Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4"
GradedArrays = "bc96ca6e-b7c8-4bb6-888e-c93f838762c2"
Expand Down Expand Up @@ -31,13 +30,12 @@ path = ".."
AbstractTrees = "0.4.5"
AlgorithmsInterface = "0.1"
Aqua = "0.8.14"
BackendSelection = "0.1"
DataGraphs = "0.4"
Dictionaries = "0.4.5"
GradedArrays = "0.9.4"
Graphs = "1.13.1"
ITensorBase = "0.6.2"
ITensorNetworksNext = "0.5"
ITensorNetworksNext = "0.6"
ITensorPkgSkeleton = "0.3.42"
MatrixAlgebraKit = "0.6"
NamedGraphs = "0.11.5"
Expand Down
19 changes: 10 additions & 9 deletions test/test_contract_network.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using BackendSelection: @Algorithm_str, Algorithm
using Graphs: edges
using ITensorBase: Index
using ITensorNetworksNext: TensorNetwork, contract_network, linkinds, siteinds
using ITensorNetworksNext.LazyITensors: Greedy, Optimal
using ITensorNetworksNext:
Exact, LeftAssociative, TensorNetwork, contract_network, linkinds, siteinds
using NamedGraphs.GraphsExtensions: arranged_edges, incident_edges
using NamedGraphs.NamedGraphGenerators: named_grid
using TensorOperations: TensorOperations
using Test: @test, @testset

@testset "contract_network" begin
orderalg = alg -> Algorithm"exact"(; order_alg = Algorithm(alg))
orderalg = order_alg -> Exact(; order_alg)

@testset "Contract Vectors of ITensors" begin
i, j, k = Index(2), Index(2), Index(5)
Expand All @@ -17,9 +18,9 @@ using Test: @test, @testset
C = [5.0, 1.0][j]
D = [-2.0, 3.0, 4.0, 5.0, 1.0][k]

ABCD_1 = contract_network([A, B, C, D]; alg = orderalg("left_associative"))
ABCD_2 = contract_network([A, B, C, D]; alg = orderalg("eager"))
ABCD_3 = contract_network([A, B, C, D]; alg = orderalg("optimal"))
ABCD_1 = contract_network([A, B, C, D]; alg = orderalg(LeftAssociative()))
ABCD_2 = contract_network([A, B, C, D]; alg = orderalg(Greedy()))
ABCD_3 = contract_network([A, B, C, D]; alg = orderalg(Optimal()))
@test ABCD_1 == ABCD_2 == ABCD_3
end

Expand All @@ -33,9 +34,9 @@ using Test: @test, @testset
return randn(Tuple(is))
end

z1 = contract_network(tn; alg = orderalg("left_associative"))[]
z2 = contract_network(tn; alg = orderalg("eager"))[]
z3 = contract_network(tn; alg = orderalg("optimal"))[]
z1 = contract_network(tn; alg = orderalg(LeftAssociative()))[]
z2 = contract_network(tn; alg = orderalg(Greedy()))[]
z3 = contract_network(tn; alg = orderalg(Optimal()))[]

@test abs(z1 - z2) / abs(z1) <= 1.0e3 * eps(Float64)
@test abs(z1 - z3) / abs(z1) <= 1.0e3 * eps(Float64)
Expand Down
21 changes: 10 additions & 11 deletions test/test_lazyitensors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ using WrappedUnions: unwrap
@test AbstractTrees.children(l1) ≡ ()
@test AbstractTrees.nodevalue(l1) ≡ a1
@test sprint(show, l1) == sprint(show, a1)
# Show-string format depends on how `Index` names are displayed; not load-bearing.
@test_broken sprint(printnode, l1) == "[:i, :j]"
@test_broken sprint(print_tree, l1) == "[:i, :j]\n"
# The leaf format mirrors ITensorBase's display of a tensor's index names.
@test sprint(printnode, l1) == "{\"i\", \"j\"}"
@test sprint(print_tree, l1) == "{\"i\", \"j\"}\n"

l = l1 * l2 * l3
@test arguments(l) == [l1 * l2, l3]
Expand All @@ -69,14 +69,13 @@ using WrappedUnions: unwrap
@test sorted_children(l) == [l1 * l2, l3]
@test AbstractTrees.children(l) == [l1 * l2, l3]
@test AbstractTrees.nodevalue(l) ≡ *
# Show-string format depends on how `Index` names are displayed; not load-bearing.
@test_broken sprint(show, l) == "(([:i, :j] * [:j, :k]) * [:k, :l])"
@test_broken sprint(printnode, l) == "(([:i, :j] * [:j, :k]) * [:k, :l])"
@test_broken sprint(print_tree, l) ==
"(([:i, :j] * [:j, :k]) * [:k, :l])\n" *
"├─ ([:i, :j] * [:j, :k])\n" *
"│ ├─ [:i, :j]\n│ └─ [:j, :k]\n" *
"└─ [:k, :l]\n"
@test sprint(show, l) == "(({\"i\", \"j\"} * {\"j\", \"k\"}) * {\"k\", \"l\"})"
@test sprint(printnode, l) == "(({\"i\", \"j\"} * {\"j\", \"k\"}) * {\"k\", \"l\"})"
@test sprint(print_tree, l) ==
"(({\"i\", \"j\"} * {\"j\", \"k\"}) * {\"k\", \"l\"})\n" *
"├─ ({\"i\", \"j\"} * {\"j\", \"k\"})\n" *
"│ ├─ {\"i\", \"j\"}\n│ └─ {\"j\", \"k\"}\n" *
"└─ {\"k\", \"l\"}\n"
end

@testset "symnameddims" begin
Expand Down