From f92676ef3965af05c26e41af3f6dd41c15618bdd Mon Sep 17 00:00:00 2001 From: Matthew Fishman Date: Mon, 22 Jun 2026 16:52:08 -0400 Subject: [PATCH 1/3] Consume the lazy and symbolic ITensor layer from ITensorBase Remove the local `LazyITensors` submodule and import its types and contraction-order machinery directly from `ITensorBase`, where the implementation now lives. Drop the redundant `TensorOperations` extension and the `AbstractTrees`, `TermInterface`, and `WrappedUnions` dependencies that only the local copy used. --- Project.toml | 19 +- .../ITensorNetworksNextTensorOperationsExt.jl | 27 --- src/ITensorNetworksNext.jl | 1 - src/LazyITensors/LazyITensors.jl | 12 - src/LazyITensors/applied.jl | 49 ---- src/LazyITensors/baseextensions.jl | 3 - src/LazyITensors/evaluation_order.jl | 112 --------- src/LazyITensors/itensorbaseextensions.jl | 23 -- src/LazyITensors/lazybroadcast.jl | 13 -- src/LazyITensors/lazyinterface.jl | 214 ------------------ src/LazyITensors/lazyitensor.jl | 67 ------ src/LazyITensors/symbolicitensor.jl | 69 ------ src/beliefpropagation/messagecache.jl | 1 - src/contract_network.jl | 4 +- src/tensornetwork.jl | 3 +- test/Project.toml | 8 +- test/test_contract_network.jl | 3 +- test/test_lazyitensors.jl | 108 --------- test/test_tensornetwork.jl | 3 +- 19 files changed, 11 insertions(+), 728 deletions(-) delete mode 100644 ext/ITensorNetworksNextTensorOperationsExt/ITensorNetworksNextTensorOperationsExt.jl delete mode 100644 src/LazyITensors/LazyITensors.jl delete mode 100644 src/LazyITensors/applied.jl delete mode 100644 src/LazyITensors/baseextensions.jl delete mode 100644 src/LazyITensors/evaluation_order.jl delete mode 100644 src/LazyITensors/itensorbaseextensions.jl delete mode 100644 src/LazyITensors/lazybroadcast.jl delete mode 100644 src/LazyITensors/lazyinterface.jl delete mode 100644 src/LazyITensors/lazyitensor.jl delete mode 100644 src/LazyITensors/symbolicitensor.jl delete mode 100644 test/test_lazyitensors.jl diff --git a/Project.toml b/Project.toml index 17e6934..a0df38f 100644 --- a/Project.toml +++ b/Project.toml @@ -1,13 +1,12 @@ name = "ITensorNetworksNext" uuid = "302f2e75-49f0-4526-aef7-d8ba550cb06c" -version = "0.6.0" +version = "0.6.1" authors = ["ITensor developers and contributors"] [workspace] projects = ["benchmark", "dev", "docs", "examples", "test"] [deps] -AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" AlgorithmsInterface = "d1e3940c-cd12-4505-8585-b0a4b322527d" Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" @@ -23,24 +22,19 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" SplitApplyCombine = "03a91e81-4c3e-53e1-a0a4-9c0c8f19dd66" TensorAlgebra = "68bd88dc-f39d-4e12-b2ca-f046b68fcc6a" -TermInterface = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c" -WrappedUnions = "325db55a-9c6c-5b90-b1a2-ec87e7a38c44" -[weakdeps] -TensorOperations = "6aa20fa7-93e2-5fca-9bc0-fbd0db3c71a2" - -[extensions] -ITensorNetworksNextTensorOperationsExt = "TensorOperations" +[sources.ITensorBase] +rev = "mf/lazyitensors" +url = "https://github.com/ITensor/ITensorBase.jl" [compat] -AbstractTrees = "0.4.5" Adapt = "4.3" AlgorithmsInterface = "0.1" Combinatorics = "1" DataGraphs = "0.4" Dictionaries = "0.4.5" Graphs = "1.13.1" -ITensorBase = "0.6.2" +ITensorBase = "0.6.3" LinearAlgebra = "1.10" MacroTools = "0.5.16" MatrixAlgebraKit = "0.6" @@ -49,7 +43,4 @@ Random = "1.10" SimpleTraits = "0.9.5" SplitApplyCombine = "1.2.3" TensorAlgebra = "0.9.7" -TensorOperations = "5.3.1" -TermInterface = "2" -WrappedUnions = "0.3" julia = "1.10" diff --git a/ext/ITensorNetworksNextTensorOperationsExt/ITensorNetworksNextTensorOperationsExt.jl b/ext/ITensorNetworksNextTensorOperationsExt/ITensorNetworksNextTensorOperationsExt.jl deleted file mode 100644 index 6d5e4f3..0000000 --- a/ext/ITensorNetworksNextTensorOperationsExt/ITensorNetworksNextTensorOperationsExt.jl +++ /dev/null @@ -1,27 +0,0 @@ -module ITensorNetworksNextTensorOperationsExt - -using ITensorBase: denamed, inds -using ITensorNetworksNext.LazyITensors.TermInterface: arguments -using ITensorNetworksNext.LazyITensors: - LazyITensors, Optimal, ismul, substitute, symnameddims -using TensorOperations: TensorOperations, optimaltree - -function contraction_tree_to_expr(f, tree) - return if !(tree isa AbstractVector) - f(tree) - else - prod(Base.Fix1(contraction_tree_to_expr, f), tree) - end -end - -function LazyITensors.optimize_contraction_order(alg::Optimal, a) - @assert ismul(a) - ts = arguments(a) - inds_network = collect.(inds.(ts)) - # Converting dims to Float64 to minimize overflow issues - inds_to_dims = Dict(i => Float64(length(denamed(i))) for i in reduce(∪, inds_network)) - tree, _ = optimaltree(inds_network, inds_to_dims) - return contraction_tree_to_expr(i -> ts[i], tree) -end - -end diff --git a/src/ITensorNetworksNext.jl b/src/ITensorNetworksNext.jl index 3ae73cc..50f3970 100644 --- a/src/ITensorNetworksNext.jl +++ b/src/ITensorNetworksNext.jl @@ -10,7 +10,6 @@ end include("select_algorithm.jl") include("AlgorithmsInterfaceExtensions/AlgorithmsInterfaceExtensions.jl") -include("LazyITensors/LazyITensors.jl") include("abstracttensornetwork.jl") include("tensornetwork.jl") include("TensorNetworkGenerators/TensorNetworkGenerators.jl") diff --git a/src/LazyITensors/LazyITensors.jl b/src/LazyITensors/LazyITensors.jl deleted file mode 100644 index a76cf17..0000000 --- a/src/LazyITensors/LazyITensors.jl +++ /dev/null @@ -1,12 +0,0 @@ -module LazyITensors - -include("baseextensions.jl") -include("itensorbaseextensions.jl") -include("applied.jl") -include("lazyinterface.jl") -include("lazybroadcast.jl") -include("lazyitensor.jl") -include("symbolicitensor.jl") -include("evaluation_order.jl") - -end diff --git a/src/LazyITensors/applied.jl b/src/LazyITensors/applied.jl deleted file mode 100644 index 0eaca17..0000000 --- a/src/LazyITensors/applied.jl +++ /dev/null @@ -1,49 +0,0 @@ -using AbstractTrees: AbstractTrees -using TermInterface: TermInterface, arguments, iscall, operation - -# Generic functionality for Applied types, like `Mul`, `Add`, etc. -ismul(a) = iscall(a) && operation(a) ≡ * -head_applied(a) = operation(a) -iscall_applied(a) = true -isexpr_applied(a) = iscall(a) -function show_applied(io::IO, a) - args = map(arg -> sprint(AbstractTrees.printnode, arg), arguments(a)) - print(io, "(", join(args, " $(operation(a)) "), ")") - return nothing -end -sorted_arguments_applied(a) = arguments(a) -children_applied(a) = arguments(a) -sorted_children_applied(a) = sorted_arguments(a) -function maketerm_applied(type, head, args, metadata) - term = type(args) - @assert head ≡ operation(term) - return term -end -map_arguments_applied(f, a) = Base.typename(typeof(a)).wrapper(map(f, arguments(a))) -function hash_applied(a, h::UInt64) - h = hash(Symbol(Base.typename(typeof(a)).wrapper), h) - for arg in arguments(a) - h = hash(arg, h) - end - return h -end - -abstract type Applied end -TermInterface.head(a::Applied) = head_applied(a) -TermInterface.iscall(a::Applied) = iscall_applied(a) -TermInterface.isexpr(a::Applied) = isexpr_applied(a) -Base.show(io::IO, a::Applied) = show_applied(io, a) -TermInterface.sorted_arguments(a::Applied) = sorted_arguments_applied(a) -TermInterface.children(a::Applied) = children_applied(a) -TermInterface.sorted_children(a::Applied) = sorted_children_applied(a) -function TermInterface.maketerm(type::Type{<:Applied}, head, args, metadata) - return maketerm_applied(type, head, args, metadata) -end -map_arguments(f, a::Applied) = map_arguments_applied(f, a) -Base.hash(a::Applied, h::UInt64) = hash_applied(a, h) - -struct Mul{A} <: Applied - arguments::Vector{A} -end -TermInterface.arguments(m::Mul) = getfield(m, :arguments) -TermInterface.operation(m::Mul) = * diff --git a/src/LazyITensors/baseextensions.jl b/src/LazyITensors/baseextensions.jl deleted file mode 100644 index 984b197..0000000 --- a/src/LazyITensors/baseextensions.jl +++ /dev/null @@ -1,3 +0,0 @@ -generic_map(f, v) = map(f, v) -generic_map(f, v::AbstractDict) = Dict(eachindex(v) .=> map(f, values(v))) -generic_map(f, v::AbstractSet) = Set([f(x) for x in v]) diff --git a/src/LazyITensors/evaluation_order.jl b/src/LazyITensors/evaluation_order.jl deleted file mode 100644 index 1ff8111..0000000 --- a/src/LazyITensors/evaluation_order.jl +++ /dev/null @@ -1,112 +0,0 @@ -using ITensorBase: denamed, dimnames, inds -using TermInterface: arguments, arity, operation - -# The time complexity of evaluating `f(args...)`. -function time_complexity(f, args...) - return error("Not implemented.") -end -# The space complexity of evaluating `f(args...)`. -function space_complexity(f, args...) - return error("Not implemented.") -end -# The space complexity of `args`. -function input_space_complexity(f, args...) - return error("Not implemented.") -end - -using ITensorBase: AbstractITensor -function time_complexity( - ::typeof(*), t1::AbstractITensor, t2::AbstractITensor - ) - return prod(length ∘ denamed, (inds(t1) ∪ inds(t2))) -end -function time_complexity( - ::typeof(+), t1::AbstractITensor, t2::AbstractITensor - ) - @assert issetequal(dimnames(t1), dimnames(t2)) - return prod(denamed, size(t1)) -end -function time_complexity(::typeof(*), c::Number, t::AbstractITensor) - return prod(denamed, size(t)) -end -function time_complexity(::typeof(*), t::AbstractITensor, c::Number) - return time_complexity(*, c, t) -end - -function evaluation_time_complexity(a) - t = Ref(0) - opwalk(a) do f - return function (args...) - t[] += time_complexity(f, args...) - return f(args...) - end - end - return t[] -end - -# The workspace complexity of evaluating expression. -function evaluation_space_complexity(a) - # TODO: Walk the expression and call `space_complexity` on each node. - return error("Not implemented.") -end -# The complexity of storing the arguments of the expression. -function argument_space_complexity(a) - # TODO: Walk the expression and call `input_space_complexity` on each node. - return error("Not implemented.") -end - -# Flatten a nested expression down to a flat expression, -# removing information about the order of operations. -function flatten_expression(a) - if !iscall(a) - return a - elseif ismul(a) - flattened_arguments = mapreduce(to_mul_arguments, vcat, arguments(a)) - return lazy(Mul(flattened_arguments)) - else - return error("Variant not supported.") - end -end - -function optimize_evaluation_order(alg, a) - if !iscall(a) - return a - elseif ismul(a) - return optimize_contraction_order(alg, a) - else - # TODO: Recurse into other operations, calling `optimize_evaluation_order`. - return error("Variant not supported.") - end -end - -function optimize_evaluation_order( - a; alg = default_optimize_evaluation_order_alg(a) - ) - return optimize_evaluation_order(alg, a) -end - -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::Greedy, a) - @assert ismul(a) - arity(a) in (1, 2) && return a - a1, a2 = argmin(combinations(arguments(a), 2)) do (a1, a2) - # Penalize outer product contractions. - # TODO: Still order the outer products by time complexity, - # say by checking if there are only outer products left. - isdisjoint(dimnames(a1), dimnames(a2)) && return typemax(Int) - return time_complexity(*, a1, a2) - end - contracted_arguments = [filter(∉((a1, a2)), arguments(a)); [a1 * a2]] - return optimize_contraction_order(alg, lazy(Mul(contracted_arguments))) -end diff --git a/src/LazyITensors/itensorbaseextensions.jl b/src/LazyITensors/itensorbaseextensions.jl deleted file mode 100644 index 9824844..0000000 --- a/src/LazyITensors/itensorbaseextensions.jl +++ /dev/null @@ -1,23 +0,0 @@ -using ITensorBase: ITensor, denamed, inds -# Defined to avoid type piracy. -# TODO: Define a proper hash function -# in ITensorBase.jl, maybe one that is -# independent of the order of dimensions. -function _hash(a::ITensor, h::UInt64) - h = hash(:ITensor, h) - h = hash(denamed(a), h) - for i in inds(a) - h = hash(i, h) - end - return h -end -function _hash(x, h::UInt64) - return hash(x, h) -end - -using AbstractTrees: AbstractTrees -# Custom version of `AbstractTrees.printnode` to -# avoid type piracy when overloading on `AbstractITensor`. -# Method specializations (`LazyITensor`, `SymbolicITensor`) live in -# `lazyitensor.jl` and `symbolicitensor.jl`. -printnode_nameddims(io::IO, x) = AbstractTrees.printnode(io, x) diff --git a/src/LazyITensors/lazybroadcast.jl b/src/LazyITensors/lazybroadcast.jl deleted file mode 100644 index 157747f..0000000 --- a/src/LazyITensors/lazybroadcast.jl +++ /dev/null @@ -1,13 +0,0 @@ -# Lazy broadcasting. -struct LazyITensorStyle <: Base.Broadcast.AbstractArrayStyle{Any} end -function Broadcast.broadcasted(::LazyITensorStyle, f, as...) - return error("Arbitrary broadcasting not supported for LazyITensor.") -end -# Linear operations. -Broadcast.broadcasted(::LazyITensorStyle, ::typeof(+), a1, a2) = a1 + a2 -Broadcast.broadcasted(::LazyITensorStyle, ::typeof(-), a1, a2) = a1 - a2 -Broadcast.broadcasted(::LazyITensorStyle, ::typeof(*), c::Number, a) = c * a -Broadcast.broadcasted(::LazyITensorStyle, ::typeof(*), a, c::Number) = a * c -Broadcast.broadcasted(::LazyITensorStyle, ::typeof(*), a::Number, b::Number) = a * b -Broadcast.broadcasted(::LazyITensorStyle, ::typeof(/), a, c::Number) = a / c -Broadcast.broadcasted(::LazyITensorStyle, ::typeof(-), a) = -a diff --git a/src/LazyITensors/lazyinterface.jl b/src/LazyITensors/lazyinterface.jl deleted file mode 100644 index 095afd4..0000000 --- a/src/LazyITensors/lazyinterface.jl +++ /dev/null @@ -1,214 +0,0 @@ -using ITensorBase: denamed, dimnames, inds -using TermInterface: iscall, maketerm, operation, sorted_arguments -using WrappedUnions: unwrap - -lazy(x) = error("Not defined.") - -# Walk the expression `ex`, modifying the -# operations by `opmap` and the arguments by `argmap`. -function walk(opmap, argmap, ex) - if !iscall(ex) - return argmap(ex) - else - return mapfoldl(opmap(operation(ex)), arguments(ex)) do (args...) - return walk(opmap, argmap, args...) - end - end -end -# Walk the expression `ex`, modifying the -# operations by `opmap`. -opwalk(opmap, a) = walk(opmap, identity, a) -# Walk the expression `ex`, modifying the -# arguments by `argmap`. -argwalk(argmap, a) = walk(identity, argmap, a) - -# Generic lazy functionality. -function maketerm_lazy(type::Type, head, args, metadata) - if head ≡ * - return type(maketerm(Mul, head, args, metadata)) - else - return error("Only mul supported right now.") - end -end -function getindex_lazy(a::AbstractArray, I...) - u = unwrap(a) - if !iscall(u) - return u[I...] - else - return error("Indexing into expression not supported.") - end -end -function arguments_lazy(a) - u = unwrap(a) - if !iscall(u) - return error("No arguments.") - elseif ismul(u) - return arguments(u) - else - return error("Variant not supported.") - end -end -using TermInterface: children -children_lazy(a) = arguments(a) -using TermInterface: head -head_lazy(a) = operation(a) -iscall_lazy(a) = iscall(unwrap(a)) -using TermInterface: isexpr -isexpr_lazy(a) = iscall(a) -function operation_lazy(a) - u = unwrap(a) - if !iscall(u) - return error("No operation.") - elseif ismul(u) - return operation(u) - else - return error("Variant not supported.") - end -end -function sorted_arguments_lazy(a) - u = unwrap(a) - if !iscall(u) - return error("No arguments.") - elseif ismul(u) - return sorted_arguments(u) - else - return error("Variant not supported.") - end -end -using TermInterface: sorted_children -sorted_children_lazy(a) = sorted_arguments(a) -ismul_lazy(a) = ismul(unwrap(a)) -using AbstractTrees: AbstractTrees -function abstracttrees_children_lazy(a) - if !iscall(a) - return () - else - return arguments(a) - end -end -using AbstractTrees: nodevalue -function nodevalue_lazy(a) - if !iscall(a) - return unwrap(a) - else - return operation(a) - end -end -using Base.Broadcast: materialize -materialize_lazy(a) = argwalk(unwrap, a) -copy_lazy(a) = materialize(a) -function equals_lazy(a1, a2) - u1, u2 = unwrap.((a1, a2)) - if !iscall(u1) && !iscall(u2) - return u1 == u2 - elseif ismul(u1) && ismul(u2) - return arguments(u1) == arguments(u2) - else - return false - end -end -function isequal_lazy(a1, a2) - u1, u2 = unwrap.((a1, a2)) - if !iscall(u1) && !iscall(u2) - return isequal(u1, u2) - elseif ismul(u1) && ismul(u2) - return isequal(arguments(u1), arguments(u2)) - else - return false - end -end -function hash_lazy(a, h::UInt64) - h = hash(Symbol(Base.typename(typeof(a)).wrapper), h) - # Use `_hash`, which defines a custom hash for ITensor. - return _hash(unwrap(a), h) -end -function map_arguments_lazy(f, a) - u = unwrap(a) - if !iscall(u) - return error("No arguments to map.") - elseif ismul(u) - return lazy(map_arguments(f, u)) - else - return error("Variant not supported.") - end -end -function substitute end -function substitute_lazy(a, substitutions::AbstractDict) - haskey(substitutions, a) && return substitutions[a] - !iscall(a) && return a - return map_arguments(arg -> substitute(arg, substitutions), a) -end -substitute_lazy(a, substitutions) = substitute(a, Dict(substitutions)) -using AbstractTrees: printnode -function printnode_lazy(io, a) - # Use `printnode_nameddims` to avoid type piracy, - # since it overloads on `AbstractITensor`. - return printnode_nameddims(io, unwrap(a)) -end -function show_lazy(io::IO, a) - if !iscall(a) - return show(io, unwrap(a)) - else - return AbstractTrees.printnode(io, a) - end -end -function show_lazy(io::IO, mime::MIME"text/plain", a) - summary(io, a) - println(io, ":") - !iscall(a) ? show(io, mime, unwrap(a)) : show(io, a) - return nothing -end -add_lazy(a1, a2) = error("Not implemented.") -sub_lazy(a) = error("Not implemented.") -sub_lazy(a1, a2) = error("Not implemented.") -function mul_lazy(a) - u = unwrap(a) - if !iscall(u) - return lazy(Mul([a])) - elseif ismul(u) - return a - else - return error("Variant not supported.") - end -end -# Note that this is nested by default. -function mul_lazy(a1, a2; flatten::Bool = false) - return flatten ? mul_lazy_flattened(a1, a2) : mul_lazy_nested(a1, a2) -end -mul_lazy_nested(a1, a2) = lazy(Mul([a1, a2])) -to_mul_arguments(a) = ismul(a) ? arguments(a) : [a] -mul_lazy_flattened(a1, a2) = lazy(Mul([to_mul_arguments(a1); to_mul_arguments(a2)])) -mul_lazy(a1::Number, a2) = error("Not implemented.") -mul_lazy(a1, a2::Number) = error("Not implemented.") -mul_lazy(a1::Number, a2::Number) = a1 * a2 -div_lazy(a1, a2::Number) = error("Not implemented.") - -# ITensorBase.jl named-tensor interface. -function dimnames_lazy(a) - u = unwrap(a) - if !iscall(u) - return dimnames(u) - elseif ismul(u) - return mapreduce(dimnames, symdiff, arguments(u)) - else - return error("Variant not supported.") - end -end -function inds_lazy(a) - u = unwrap(a) - if !iscall(u) - return inds(u) - elseif ismul(u) - return mapreduce(inds, symdiff, arguments(u)) - else - return error("Variant not supported.") - end -end -function denamed_lazy(a) - u = unwrap(a) - if !iscall(u) - return denamed(u) - else - return error("Variant not supported.") - end -end diff --git a/src/LazyITensors/lazyitensor.jl b/src/LazyITensors/lazyitensor.jl deleted file mode 100644 index 4071fee..0000000 --- a/src/LazyITensors/lazyitensor.jl +++ /dev/null @@ -1,67 +0,0 @@ -using ITensorBase: ITensorBase, AbstractITensor -using WrappedUnions: @wrapped - -@wrapped struct LazyITensor{ - DimName, A <: AbstractITensor{DimName}, - } <: AbstractITensor{DimName} - union::Union{A, Mul{LazyITensor{DimName, A}}} -end - -parenttype(::Type{LazyITensor{DimName, A}}) where {DimName, A} = A -parenttype(::Type{LazyITensor{DimName}}) where {DimName} = AbstractITensor{DimName} -parenttype(::Type{LazyITensor}) = AbstractITensor - -function LazyITensor(a::AbstractITensor) - return LazyITensor{ITensorBase.dimnametype(typeof(a)), typeof(a)}(a) -end -function LazyITensor(a::Mul{L}) where {L <: LazyITensor} - return LazyITensor{ITensorBase.dimnametype(L), parenttype(L)}(a) -end -lazy(a::LazyITensor) = a -lazy(a::AbstractITensor) = LazyITensor(a) -lazy(a::Mul{<:LazyITensor}) = LazyITensor(a) - -ITensorBase.dimnames(a::LazyITensor) = dimnames_lazy(a) -ITensorBase.inds(a::LazyITensor) = inds_lazy(a) -ITensorBase.denamed(a::LazyITensor) = denamed_lazy(a) - -# Broadcasting -function Base.BroadcastStyle(::Type{<:LazyITensor}) - return LazyITensorStyle() -end - -# Derived functionality. -function TermInterface.maketerm(type::Type{LazyITensor}, head, args, metadata) - return maketerm_lazy(type, head, args, metadata) -end -Base.getindex(a::LazyITensor, I::Int...) = getindex_lazy(a, I...) -TermInterface.arguments(a::LazyITensor) = arguments_lazy(a) -TermInterface.children(a::LazyITensor) = children_lazy(a) -TermInterface.head(a::LazyITensor) = head_lazy(a) -TermInterface.iscall(a::LazyITensor) = iscall_lazy(a) -TermInterface.isexpr(a::LazyITensor) = isexpr_lazy(a) -TermInterface.operation(a::LazyITensor) = operation_lazy(a) -TermInterface.sorted_arguments(a::LazyITensor) = sorted_arguments_lazy(a) -AbstractTrees.children(a::LazyITensor) = abstracttrees_children_lazy(a) -TermInterface.sorted_children(a::LazyITensor) = sorted_children_lazy(a) -ismul(a::LazyITensor) = ismul_lazy(a) -AbstractTrees.nodevalue(a::LazyITensor) = nodevalue_lazy(a) -Base.Broadcast.materialize(a::LazyITensor) = materialize_lazy(a) -Base.copy(a::LazyITensor) = copy_lazy(a) -Base.:(==)(a1::LazyITensor, a2::LazyITensor) = equals_lazy(a1, a2) -Base.isequal(a1::LazyITensor, a2::LazyITensor) = isequal_lazy(a1, a2) -Base.hash(a::LazyITensor, h::UInt64) = hash_lazy(a, h) -map_arguments(f, a::LazyITensor) = map_arguments_lazy(f, a) -substitute(a::LazyITensor, substitutions) = substitute_lazy(a, substitutions) -AbstractTrees.printnode(io::IO, a::LazyITensor) = printnode_lazy(io, a) -printnode_nameddims(io::IO, a::LazyITensor) = printnode_lazy(io, a) -Base.show(io::IO, a::LazyITensor) = show_lazy(io, a) -Base.show(io::IO, mime::MIME"text/plain", a::LazyITensor) = show_lazy(io, mime, a) -Base.:*(a::LazyITensor) = mul_lazy(a) -Base.:*(a1::LazyITensor, a2::LazyITensor) = mul_lazy(a1, a2) -Base.:+(a1::LazyITensor, a2::LazyITensor) = add_lazy(a1, a2) -Base.:-(a1::LazyITensor, a2::LazyITensor) = sub_lazy(a1, a2) -Base.:*(a1::Number, a2::LazyITensor) = mul_lazy(a1, a2) -Base.:*(a1::LazyITensor, a2::Number) = mul_lazy(a1, a2) -Base.:/(a1::LazyITensor, a2::Number) = div_lazy(a1, a2) -Base.:-(a::LazyITensor) = sub_lazy(a) diff --git a/src/LazyITensors/symbolicitensor.jl b/src/LazyITensors/symbolicitensor.jl deleted file mode 100644 index beb5f30..0000000 --- a/src/LazyITensors/symbolicitensor.jl +++ /dev/null @@ -1,69 +0,0 @@ -using ITensorBase: ITensorBase, AbstractITensor, dimnames, inds, name - -# Expression leaf with no array payload, so it defines no `denamed`/`getindex`. -# Parameterized on `DimName` only (axes stored as a field, not a type parameter) -# so mixed-rank symbolic tensors share one concrete type and a flat `Mul` over -# them stays concretely typed. -struct SymbolicITensor{DimName} <: AbstractITensor{DimName} - name::Any - inds::Any -end -function SymbolicITensor(name, inds) - DimName = isempty(inds) ? typeof(name) : eltype(ITensorBase.name.(inds)) - return SymbolicITensor{DimName}(name, inds) -end - -symname(a::SymbolicITensor) = getfield(a, :name) - -ITensorBase.dimnames(a::SymbolicITensor) = collect(ITensorBase.name.(getfield(a, :inds))) -ITensorBase.inds(a::SymbolicITensor) = getfield(a, :inds) -ITensorBase.dimnametype(::Type{<:SymbolicITensor{DimName}}) where {DimName} = DimName -Base.ndims(a::SymbolicITensor) = length(getfield(a, :inds)) - -function Base.:(==)(a::SymbolicITensor, b::SymbolicITensor) - return symname(a) == symname(b) && dimnames(a) == dimnames(b) -end -Base.isequal(a::SymbolicITensor, b::SymbolicITensor) = a == b -function Base.hash(a::SymbolicITensor, h::UInt64) - h = hash(:SymbolicITensor, h) - h = hash(symname(a), h) - return hash(dimnames(a), h) -end - -# Products build lazy expressions rather than contracting numerically. -Base.:*(a::SymbolicITensor, b::SymbolicITensor) = lazy(a) * lazy(b) -Base.:*(a::SymbolicITensor, b::LazyITensor) = lazy(a) * b -Base.:*(a::LazyITensor, b::SymbolicITensor) = a * lazy(b) - -issymbolic(a) = a isa SymbolicITensor -issymbolic(a::LazyITensor) = !iscall(a) && issymbolic(unwrap(a)) - -function Base.show(io::IO, a::SymbolicITensor) - print(io, symname(a)) - if ndims(a) > 0 - print(io, "[", join(dimnames(a), ","), "]") - end - return nothing -end -function Base.show(io::IO, mime::MIME"text/plain", a::SymbolicITensor) - summary(io, a) - println(io, ":") - show(io, a) - return nothing -end - -using AbstractTrees: AbstractTrees -function AbstractTrees.printnode(io::IO, a::SymbolicITensor) - show(io, a) - return nothing -end - -function symnameddims(symname, dims) - return lazy(SymbolicITensor(symname, dims)) -end -symnameddims(name) = symnameddims(name, ()) - -function printnode_nameddims(io::IO, a::SymbolicITensor) - AbstractTrees.printnode(io, a) - return nothing -end diff --git a/src/beliefpropagation/messagecache.jl b/src/beliefpropagation/messagecache.jl index 0b842a3..585cdf6 100644 --- a/src/beliefpropagation/messagecache.jl +++ b/src/beliefpropagation/messagecache.jl @@ -2,7 +2,6 @@ using DataGraphs: DataGraphs, AbstractDataGraph, edge_data, edge_data_type, set_vertex_data!, underlying_graph, underlying_graph_type, vertex_data, vertex_data_type using Dictionaries: Dictionary, delete!, getindices, set! using Graphs: AbstractGraph, connected_components, is_directed, is_tree -using ITensorNetworksNext.LazyITensors: LazyITensor, lazy, parenttype using NamedGraphs.GraphsExtensions: IsDirected, boundary_edges, default_root_vertex, directed_graph, forest_cover, in_incident_edges, post_order_dfs_edges, undirected_graph, vertextype diff --git a/src/contract_network.jl b/src/contract_network.jl index cdacc97..b6b5215 100644 --- a/src/contract_network.jl +++ b/src/contract_network.jl @@ -1,7 +1,7 @@ using Base.Broadcast: materialize using Base: @kwdef -using ITensorNetworksNext.LazyITensors: EvaluationOrderAlgorithm, Greedy, Mul, lazy, - optimize_evaluation_order, substitute, symnameddims +using ITensorBase: EvaluationOrderAlgorithm, Greedy, Mul, lazy, optimize_evaluation_order, + substitute, symnameddims # `contract_network` @kwdef struct Exact{Order, OrderAlg} diff --git a/src/tensornetwork.jl b/src/tensornetwork.jl index 1a56fb6..3c6aa47 100644 --- a/src/tensornetwork.jl +++ b/src/tensornetwork.jl @@ -1,11 +1,10 @@ -using .LazyITensors: Mul, lazy using Combinatorics: combinations using DataGraphs.DataGraphsPartitionedGraphsExt using DataGraphs: DataGraphs, AbstractDataGraph, DataGraph, edge_data, get_vertices_data, vertex_data, vertex_data_type using Dictionaries: AbstractDictionary, Indices, dictionary, set!, unset! using Graphs: AbstractSimpleGraph, rem_edge!, rem_vertex! -using ITensorBase: AbstractITensor, dimnames +using ITensorBase: AbstractITensor, dimnames, lazy using NamedGraphs.GraphsExtensions: GraphsExtensions, arrange_edge, arranged_edges, vertextype using NamedGraphs.PartitionedGraphs: AbstractPartitionedGraph, PartitionedGraphs, diff --git a/test/Project.toml b/test/Project.toml index 06fd820..ac2e588 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,5 +1,4 @@ [deps] -AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" AlgorithmsInterface = "d1e3940c-cd12-4505-8585-b0a4b322527d" Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" DataGraphs = "b5a273c3-7e6c-41f6-98bd-8d7f1525a36a" @@ -19,22 +18,19 @@ StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3" Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb" TensorAlgebra = "68bd88dc-f39d-4e12-b2ca-f046b68fcc6a" TensorOperations = "6aa20fa7-93e2-5fca-9bc0-fbd0db3c71a2" -TermInterface = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -WrappedUnions = "325db55a-9c6c-5b90-b1a2-ec87e7a38c44" [sources.ITensorNetworksNext] path = ".." [compat] -AbstractTrees = "0.4.5" AlgorithmsInterface = "0.1" Aqua = "0.8.14" DataGraphs = "0.4" Dictionaries = "0.4.5" GradedArrays = "0.9.4" Graphs = "1.13.1" -ITensorBase = "0.6.2" +ITensorBase = "0.6.3" ITensorNetworksNext = "0.6" ITensorPkgSkeleton = "0.3.42" MatrixAlgebraKit = "0.6" @@ -46,6 +42,4 @@ StableRNGs = "1" Suppressor = "0.2.8" TensorAlgebra = "0.9.7" TensorOperations = "5.3.1" -TermInterface = "2" Test = "1.10" -WrappedUnions = "0.3" diff --git a/test/test_contract_network.jl b/test/test_contract_network.jl index d8ee2d9..6525764 100644 --- a/test/test_contract_network.jl +++ b/test/test_contract_network.jl @@ -1,6 +1,5 @@ using Graphs: edges -using ITensorBase: Index -using ITensorNetworksNext.LazyITensors: Greedy, Optimal +using ITensorBase: Greedy, Index, Optimal using ITensorNetworksNext: Exact, LeftAssociative, TensorNetwork, contract_network, linkinds, siteinds using NamedGraphs.GraphsExtensions: arranged_edges, incident_edges diff --git a/test/test_lazyitensors.jl b/test/test_lazyitensors.jl deleted file mode 100644 index ec29899..0000000 --- a/test/test_lazyitensors.jl +++ /dev/null @@ -1,108 +0,0 @@ -using AbstractTrees: AbstractTrees, print_tree, printnode -using Base.Broadcast: materialize -using ITensorBase: @names, ITensor, denamed, dimnames, inds, nameddims, namedoneto -using ITensorNetworksNext.LazyITensors: - LazyITensor, Mul, SymbolicITensor, ismul, lazy, substitute, symnameddims -using TermInterface: arguments, arity, children, head, iscall, isexpr, maketerm, operation, - sorted_arguments, sorted_children -using Test: @test, @test_broken, @test_throws, @testset -using WrappedUnions: unwrap - -@testset "LazyITensors" begin - @testset "Basics" begin - i, j, k, l = namedoneto.(2, (:i, :j, :k, :l)) - a1 = randn(i, j) - a2 = randn(j, k) - a3 = randn(k, l) - l1, l2, l3 = lazy.((a1, a2, a3)) - for li in (l1, l2, l3) - @test li isa LazyITensor - @test unwrap(li) isa ITensor - @test inds(li) == inds(unwrap(li)) - @test copy(li) == unwrap(li) - @test materialize(li) == unwrap(li) - end - l = l1 * l2 * l3 - @test copy(l) ≈ a1 * a2 * a3 - @test materialize(l) ≈ a1 * a2 * a3 - @test issetequal(inds(l), symdiff(inds.((a1, a2, a3))...)) - @test unwrap(l) isa Mul - @test ismul(unwrap(l)) - @test unwrap(l).arguments == [l1 * l2, l3] - # TermInterface.jl - @test operation(unwrap(l)) ≡ * - @test arguments(unwrap(l)) == [l1 * l2, l3] - end - - @testset "TermInterface" begin - a1 = nameddims(randn(2, 2), (:i, :j)) - a2 = nameddims(randn(2, 2), (:j, :k)) - a3 = nameddims(randn(2, 2), (:k, :l)) - l1, l2, l3 = lazy.((a1, a2, a3)) - - @test_throws ErrorException arguments(l1) - @test_throws ErrorException arity(l1) - @test_throws ErrorException children(l1) - @test_throws ErrorException head(l1) - @test !iscall(l1) - @test !isexpr(l1) - @test_throws ErrorException operation(l1) - @test_throws ErrorException sorted_arguments(l1) - @test_throws ErrorException sorted_children(l1) - @test AbstractTrees.children(l1) ≡ () - @test AbstractTrees.nodevalue(l1) ≡ a1 - @test sprint(show, l1) == sprint(show, a1) - # 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] - @test arity(l) == 2 - @test children(l) == [l1 * l2, l3] - @test head(l) ≡ * - @test iscall(l) - @test isexpr(l) - @test l == maketerm(LazyITensor, *, [l1 * l2, l3], nothing) - @test operation(l) ≡ * - @test sorted_arguments(l) == [l1 * l2, l3] - @test sorted_children(l) == [l1 * l2, l3] - @test AbstractTrees.children(l) == [l1 * l2, l3] - @test AbstractTrees.nodevalue(l) ≡ * - @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 - a1, a2, a3 = symnameddims.((:a1, :a2, :a3)) - @test a1 isa LazyITensor - @test unwrap(a1) isa SymbolicITensor - @test unwrap(a1) == SymbolicITensor(:a1, ()) - @test isequal(unwrap(a1), SymbolicITensor(:a1, ())) - @test inds(a1) == () - @test isempty(dimnames(a1)) - - ex = a1 * a2 * a3 - @test copy(ex) == ex - @test arguments(ex) == [a1 * a2, a3] - @test operation(ex) ≡ * - @test sprint(show, ex) == "((a1 * a2) * a3)" - end - - @testset "substitute" begin - s = symnameddims.((:a1, :a2, :a3)) - i = @names i[1:4] - a = (randn(2, 2)[i[1], i[2]], randn(2, 2)[i[2], i[3]], randn(2, 2)[i[3], i[4]]) - l = lazy.(a) - - seq = s[1] * (s[2] * s[3]) - net = substitute(seq, s .=> l) - @test net == l[1] * (l[2] * l[3]) - @test arguments(net) == [l[1], l[2] * l[3]] - end -end diff --git a/test/test_tensornetwork.jl b/test/test_tensornetwork.jl index ddd89e2..3f3cbd1 100644 --- a/test/test_tensornetwork.jl +++ b/test/test_tensornetwork.jl @@ -1,8 +1,7 @@ using DataGraphs: assigned_edge_data, assigned_vertex_data, underlying_graph, vertex_data using Graphs: add_edge!, add_vertex!, dst, edges, edgetype, has_edge, has_vertex, is_directed, ne, nv, rem_vertex!, src, vertices -using ITensorBase: Index -using ITensorNetworksNext.LazyITensors: LazyITensor +using ITensorBase: Index, LazyITensor using ITensorNetworksNext: TensorNetwork, fix_edges!, linkaxes, linkinds, linknames, siteaxes, siteinds, sitenames using NamedGraphs.GraphsExtensions: incident_edges, subgraph, vertextype From 0ce3a4472cc6490de15c659d017dc66c4d165d80 Mon Sep 17 00:00:00 2001 From: Matthew Fishman Date: Mon, 22 Jun 2026 17:46:45 -0400 Subject: [PATCH 2/3] Drop the ITensorBase [sources] pin now that 0.6.3 is registered --- Project.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Project.toml b/Project.toml index a0df38f..bd5f615 100644 --- a/Project.toml +++ b/Project.toml @@ -23,10 +23,6 @@ SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" SplitApplyCombine = "03a91e81-4c3e-53e1-a0a4-9c0c8f19dd66" TensorAlgebra = "68bd88dc-f39d-4e12-b2ca-f046b68fcc6a" -[sources.ITensorBase] -rev = "mf/lazyitensors" -url = "https://github.com/ITensor/ITensorBase.jl" - [compat] Adapt = "4.3" AlgorithmsInterface = "0.1" From 7381a262581e9c52f2860998cdbfdd63bd79adab Mon Sep 17 00:00:00 2001 From: Matthew Fishman Date: Mon, 22 Jun 2026 17:56:01 -0400 Subject: [PATCH 3/3] Re-trigger CI after dropping the ITensorBase source pin