diff --git a/Project.toml b/Project.toml index 20138855..48d634e5 100644 --- a/Project.toml +++ b/Project.toml @@ -1,32 +1,26 @@ name = "ITensorBase" uuid = "4795dd04-0d67-49bb-8f44-b89c448a1dc7" -version = "0.15.5" +version = "0.16.0" authors = ["ITensor developers and contributors"] [workspace] projects = ["benchmark", "dev", "docs", "examples", "test"] [deps] -AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" -Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" -ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MatrixAlgebraKit = "6c742aac-3347-4629-af66-fc926824e5e4" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" TensorAlgebra = "68bd88dc-f39d-4e12-b2ca-f046b68fcc6a" -TermInterface = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" VectorInterface = "409d34a3-91d5-4945-b6ec-7529ddf182d8" -WrappedUnions = "325db55a-9c6c-5b90-b1a2-ec87e7a38c44" [weakdeps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" GradedArrays = "bc96ca6e-b7c8-4bb6-888e-c93f838762c2" Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6" -OMEinsumContractionOrders = "6f22d1fd-8eed-4bb7-9776-e7d684900715" TensorKit = "07d1fe3e-3e46-537d-9eac-e9e13d0d4cec" TensorKitSectors = "13a9c161-d5da-41f0-bcbd-e1a08ae0647f" @@ -34,28 +28,21 @@ TensorKitSectors = "13a9c161-d5da-41f0-bcbd-e1a08ae0647f" ITensorBaseAdaptExt = "Adapt" ITensorBaseGradedArraysExt = ["GradedArrays", "TensorKitSectors"] ITensorBaseMooncakeExt = "Mooncake" -ITensorBaseOMEinsumContractionOrdersExt = "OMEinsumContractionOrders" ITensorBaseTensorKitExt = "TensorKit" [compat] -AbstractTrees = "0.4.5" Accessors = "0.1.39" Adapt = "4.1.1" ArrayLayouts = "1.11" -Combinatorics = "1" -ConstructionBase = "1.6" GradedArrays = "0.17" LinearAlgebra = "1.10" MatrixAlgebraKit = "0.2, 0.3, 0.4, 0.5, 0.6" Mooncake = "0.4.202, 0.5" -OMEinsumContractionOrders = "1.3" Random = "1.10" SimpleTraits = "0.9.4" TensorAlgebra = "0.23" TensorKit = "0.17" TensorKitSectors = "0.3.9" -TermInterface = "2" UUIDs = "1.10" VectorInterface = "0.6" -WrappedUnions = "0.3" julia = "1.10" diff --git a/docs/Project.toml b/docs/Project.toml index 2744e454..bb1f875e 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -16,7 +16,7 @@ path = ".." Documenter = "1" DocumenterInterLinks = "1" GradedArrays = "0.17" -ITensorBase = "0.15" +ITensorBase = "0.16" ITensorFormatter = "0.2.27" Literate = "2" MatrixAlgebraKit = "0.2, 0.3, 0.4, 0.5, 0.6" diff --git a/examples/Project.toml b/examples/Project.toml index c219fcf2..d639c853 100644 --- a/examples/Project.toml +++ b/examples/Project.toml @@ -6,5 +6,5 @@ MatrixAlgebraKit = "6c742aac-3347-4629-af66-fc926824e5e4" path = ".." [compat] -ITensorBase = "0.15" +ITensorBase = "0.16" MatrixAlgebraKit = "0.2, 0.3, 0.4, 0.5, 0.6" diff --git a/ext/ITensorBaseOMEinsumContractionOrdersExt/ITensorBaseOMEinsumContractionOrdersExt.jl b/ext/ITensorBaseOMEinsumContractionOrdersExt/ITensorBaseOMEinsumContractionOrdersExt.jl deleted file mode 100644 index 048bc1cb..00000000 --- a/ext/ITensorBaseOMEinsumContractionOrdersExt/ITensorBaseOMEinsumContractionOrdersExt.jl +++ /dev/null @@ -1,34 +0,0 @@ -module ITensorBaseOMEinsumContractionOrdersExt - -using ITensorBase.TermInterface: arguments -using ITensorBase: ITensorBase, inds, ismul, optimize_contraction_order -using OMEinsumContractionOrders: - OMEinsumContractionOrders, CodeOptimizer, EinCode, NestedEinsum, optimize_code - -# Rebuild a nested product expression from an optimized `NestedEinsum`, mapping each -# leaf's `tensorindex` back to the corresponding argument of the flat product. -function nested_einsum_to_expr(f, code::NestedEinsum) - # A leaf holds the 1-based index of its input tensor; internal nodes hold `-1`. - return if code.tensorindex != -1 - f(code.tensorindex) - else - prod(Base.Fix1(nested_einsum_to_expr, f), code.args) - end -end - -# Find a contraction order with any OMEinsumContractionOrders optimizer (`GreedyMethod`, -# `TreeSA`, `KaHyParBipartite`, ...) by forwarding to `optimize_code`. -function ITensorBase.optimize_contraction_order(alg::CodeOptimizer, a) - @assert ismul(a) - ts = arguments(a) - ixs = collect.(inds.(ts)) - all_inds = reduce(vcat, ixs) - labels = unique(all_inds) - size_dict = Dict(i => length(i) for i in labels) - # Open indices (appearing on a single tensor) are the output of the network. - iy = filter(i -> count(==(i), all_inds) == 1, labels) - code = optimize_code(EinCode(ixs, iy), size_dict, alg) - return nested_einsum_to_expr(i -> ts[i], code) -end - -end diff --git a/src/ITensorBase.jl b/src/ITensorBase.jl index 983be9e5..4cb3555e 100644 --- a/src/ITensorBase.jl +++ b/src/ITensorBase.jl @@ -36,14 +36,4 @@ include("sorteddict.jl") include("index.jl") include("quirks.jl") -# Lazy and symbolic ITensor expressions. -include("lazyitensors/baseextensions.jl") -include("lazyitensors/itensorbaseextensions.jl") -include("lazyitensors/applied.jl") -include("lazyitensors/lazyinterface.jl") -include("lazyitensors/lazybroadcast.jl") -include("lazyitensors/lazyitensor.jl") -include("lazyitensors/symbolicitensor.jl") -include("lazyitensors/evaluation_order.jl") - end diff --git a/src/abstractnamedtensor.jl b/src/abstractnamedtensor.jl index ea100fb3..6399f460 100644 --- a/src/abstractnamedtensor.jl +++ b/src/abstractnamedtensor.jl @@ -117,10 +117,10 @@ inds(a::AbstractNamedTensor, dim::Int) = axes(a)[dim] isnamed(::Type{<:AbstractNamedTensor}) = true -function dim(a::AbstractNamedTensor, n) +function findname(a::AbstractNamedTensor, n) return findfirst(==(name(n)), names(a)) end -dims(a::AbstractNamedTensor, ns) = Base.Fix1(dim, a).(ns) +findnames(a::AbstractNamedTensor, ns) = Base.Fix1(findname, a).(ns) dimname_isequal(x) = Base.Fix1(dimname_isequal, x) dimname_isequal(x, y) = isequal(x, y) @@ -140,7 +140,7 @@ dimname_isequal(r1::NamedUnitRange, r2::Name) = name(r1) == name(r2) dimname_isequal(r1::Name, r2::NamedUnitRange) = name(r1) == name(r2) function to_inds(a::AbstractNamedTensor, dims) - is = Base.Fix1(dim, a).(name.(dims)) + is = Base.Fix1(findname, a).(name.(dims)) return Base.Fix1(inds, a).(is) end @@ -348,8 +348,8 @@ end VI.inner(x::AbstractNamedTensor, y::AbstractNamedTensor) = LinearAlgebra.dot(x, y) -Base.axes(a::AbstractNamedTensor, dimname::Name) = axes(a, dim(a, dimname)) -Base.size(a::AbstractNamedTensor, dimname::Name) = size(a, dim(a, dimname)) +Base.axes(a::AbstractNamedTensor, dimname::Name) = axes(a, findname(a, dimname)) +Base.size(a::AbstractNamedTensor, dimname::Name) = size(a, findname(a, dimname)) # Lowered through `TensorAlgebra.similar_map` (all-codomain, so identical to # `similar(parent, elt, axes)` for dense) so non-`AbstractArray` backends whose `similar` diff --git a/src/lazyitensors/applied.jl b/src/lazyitensors/applied.jl deleted file mode 100644 index 0eaca174..00000000 --- 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 984b1971..00000000 --- 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 639aa086..00000000 --- a/src/lazyitensors/evaluation_order.jl +++ /dev/null @@ -1,112 +0,0 @@ -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 - -function time_complexity( - ::typeof(*), t1::AbstractNamedTensor, t2::AbstractNamedTensor - ) - return prod(length, (inds(t1) ∪ inds(t2))) -end -function time_complexity( - ::typeof(+), t1::AbstractNamedTensor, t2::AbstractNamedTensor - ) - @assert issetequal(names(t1), names(t2)) - return prod(size(t1)) -end -function time_complexity(::typeof(*), c::Number, t::AbstractNamedTensor) - return prod(size(t)) -end -function time_complexity(::typeof(*), t::AbstractNamedTensor, 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 -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 - args = arguments(a) - # Choose and remove the contracted pair by position. Removing it by value would also - # drop any other argument equal to it, silently losing a tensor from a product with - # repeated arguments. - i1, i2 = argmin(combinations(eachindex(args), 2)) do (i1, i2) - # Penalize outer product contractions. - # TODO: Still order the outer products by time complexity, - # say by checking if there are only outer products left. - isdisjoint(names(args[i1]), names(args[i2])) && return typemax(Int) - return time_complexity(*, args[i1], args[i2]) - end - rest = [arg for (i, arg) in pairs(args) if i ∉ (i1, i2)] - contracted_arguments = [rest; [args[i1] * args[i2]]] - 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 f8bea02e..00000000 --- a/src/lazyitensors/itensorbaseextensions.jl +++ /dev/null @@ -1,29 +0,0 @@ -# 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::NamedTensor, h::UInt64) - h = hash(:NamedTensor, h) - h = hash(unnamed(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 -# Only print the dimension names when printing with `AbstractTrees.print_tree`. -function AbstractTrees.printnode(io::IO, a::AbstractNamedTensor) - names_a = "{" * join(map(s -> "\"$s\"", names(a)), ", ") * "}" - print(io, names_a) - return nothing -end - -# Custom version of `AbstractTrees.printnode` to -# avoid type piracy when overloading on `AbstractNamedTensor`. -# Method specializations (`LazyNamedTensor`, `SymbolicNamedTensor`) live in -# `lazyitensor.jl` and `symbolicitensor.jl`. -printnode_namedtensor(io::IO, x) = AbstractTrees.printnode(io, x) diff --git a/src/lazyitensors/lazybroadcast.jl b/src/lazyitensors/lazybroadcast.jl deleted file mode 100644 index 0149ed20..00000000 --- a/src/lazyitensors/lazybroadcast.jl +++ /dev/null @@ -1,13 +0,0 @@ -# Lazy broadcasting. -struct LazyNamedTensorStyle <: Base.Broadcast.AbstractArrayStyle{Any} end -function Broadcast.broadcasted(::LazyNamedTensorStyle, f, as...) - return error("Arbitrary broadcasting not supported for LazyNamedTensor.") -end -# Linear operations. -Broadcast.broadcasted(::LazyNamedTensorStyle, ::typeof(+), a1, a2) = a1 + a2 -Broadcast.broadcasted(::LazyNamedTensorStyle, ::typeof(-), a1, a2) = a1 - a2 -Broadcast.broadcasted(::LazyNamedTensorStyle, ::typeof(*), c::Number, a) = c * a -Broadcast.broadcasted(::LazyNamedTensorStyle, ::typeof(*), a, c::Number) = a * c -Broadcast.broadcasted(::LazyNamedTensorStyle, ::typeof(*), a::Number, b::Number) = a * b -Broadcast.broadcasted(::LazyNamedTensorStyle, ::typeof(/), a, c::Number) = a / c -Broadcast.broadcasted(::LazyNamedTensorStyle, ::typeof(-), a) = -a diff --git a/src/lazyitensors/lazyinterface.jl b/src/lazyitensors/lazyinterface.jl deleted file mode 100644 index abb97f73..00000000 --- a/src/lazyitensors/lazyinterface.jl +++ /dev/null @@ -1,213 +0,0 @@ -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(nameof(typeof(a)), h) - # Use `_hash`, which defines a custom hash for NamedTensor. - 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_namedtensor` to avoid type piracy, - # since it overloads on `AbstractNamedTensor`. - return printnode_namedtensor(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 names_lazy(a) - u = unwrap(a) - if !iscall(u) - return names(u) - elseif ismul(u) - return mapreduce(names, 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 unnamed_lazy(a) - u = unwrap(a) - if !iscall(u) - return unnamed(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 fc897296..00000000 --- a/src/lazyitensors/lazyitensor.jl +++ /dev/null @@ -1,102 +0,0 @@ -using WrappedUnions: @wrapped - -@wrapped struct LazyNamedTensor{ - DimName, A <: AbstractNamedTensor{DimName}, - } <: AbstractNamedTensor{DimName} - union::Union{A, Mul{LazyNamedTensor{DimName, A}}} -end - -parenttype(::Type{LazyNamedTensor{DimName, A}}) where {DimName, A} = A -function parenttype(::Type{LazyNamedTensor{DimName}}) where {DimName} - return AbstractNamedTensor{DimName} -end -parenttype(::Type{LazyNamedTensor}) = AbstractNamedTensor - -function LazyNamedTensor(a::AbstractNamedTensor) - return LazyNamedTensor{nametype(typeof(a)), typeof(a)}(a) -end -function LazyNamedTensor(a::Mul{L}) where {L <: LazyNamedTensor} - return LazyNamedTensor{nametype(L), parenttype(L)}(a) -end -lazy(a::LazyNamedTensor) = a -lazy(a::AbstractNamedTensor) = LazyNamedTensor(a) -lazy(a::Mul{<:LazyNamedTensor}) = LazyNamedTensor(a) - -# Promotion of lazy tensors, by promoting the wrapped (leaf) parent type. A lazy tensor promotes -# with another lazy tensor, or with an eager tensor, to the lazy tensor whose leaf type is the -# promotion of the leaves. So a lazy plain tensor and an operator promote to a lazy operator, -# reusing the eager `NamedTensor` / `NamedTensorOperator` promotion at the leaves. This lets -# `contract_network` homogenize a network that mixes lazy and eager, plain and operator operands -# (a norm-network vertex is a lazy `ket * conj(bra)` product) without materializing anything. -function Base.promote_rule( - ::Type{LazyNamedTensor{D, A1}}, ::Type{LazyNamedTensor{D, A2}} - ) where {D, A1, A2} - return LazyNamedTensor{D, promote_type(A1, A2)} -end -function Base.promote_rule( - ::Type{LazyNamedTensor{D, A}}, ::Type{T} - ) where {D, A, T <: AbstractNamedTensor{D}} - return LazyNamedTensor{D, promote_type(A, T)} -end -# `convert` mirrors the promotion: wrap an eager tensor as lazy (converting it to the target leaf -# type first), or rebuild a lazy product with each leaf converted to the target leaf type. -function Base.convert(::Type{LazyNamedTensor{D, A}}, a::AbstractNamedTensor{D}) where {D, A} - return lazy(convert(A, a)) -end -function Base.convert( - ::Type{LazyNamedTensor{D, A2}}, a::LazyNamedTensor{D, A1} - ) where {D, A1, A2} - iscall(a) || return lazy(convert(A2, unwrap(a))) - return lazy(Mul(map(arg -> convert(LazyNamedTensor{D, A2}, arg), arguments(a)))) -end - -names(a::LazyNamedTensor) = names_lazy(a) -inds(a::LazyNamedTensor) = inds_lazy(a) -# `axes` is computed from `inds_lazy` rather than the generic `unnamed`-based fallback -# because a `Mul` expression has no materialized `unnamed` array to take axes of. -Base.axes(a::LazyNamedTensor) = Tuple(inds_lazy(a)) -unnamed(a::LazyNamedTensor) = unnamed_lazy(a) - -# Broadcasting -function Base.BroadcastStyle(::Type{<:LazyNamedTensor}) - return LazyNamedTensorStyle() -end - -# Derived functionality. -function TermInterface.maketerm(type::Type{LazyNamedTensor}, head, args, metadata) - return maketerm_lazy(type, head, args, metadata) -end -Base.getindex(a::LazyNamedTensor, I::Int...) = getindex_lazy(a, I...) -TermInterface.arguments(a::LazyNamedTensor) = arguments_lazy(a) -TermInterface.children(a::LazyNamedTensor) = children_lazy(a) -TermInterface.head(a::LazyNamedTensor) = head_lazy(a) -TermInterface.iscall(a::LazyNamedTensor) = iscall_lazy(a) -TermInterface.isexpr(a::LazyNamedTensor) = isexpr_lazy(a) -TermInterface.operation(a::LazyNamedTensor) = operation_lazy(a) -TermInterface.sorted_arguments(a::LazyNamedTensor) = sorted_arguments_lazy(a) -AbstractTrees.children(a::LazyNamedTensor) = abstracttrees_children_lazy(a) -TermInterface.sorted_children(a::LazyNamedTensor) = sorted_children_lazy(a) -ismul(a::LazyNamedTensor) = ismul_lazy(a) -AbstractTrees.nodevalue(a::LazyNamedTensor) = nodevalue_lazy(a) -Base.Broadcast.materialize(a::LazyNamedTensor) = materialize_lazy(a) -Base.copy(a::LazyNamedTensor) = copy_lazy(a) -Base.:(==)(a1::LazyNamedTensor, a2::LazyNamedTensor) = equals_lazy(a1, a2) -Base.isequal(a1::LazyNamedTensor, a2::LazyNamedTensor) = isequal_lazy(a1, a2) -Base.hash(a::LazyNamedTensor, h::UInt64) = hash_lazy(a, h) -map_arguments(f, a::LazyNamedTensor) = map_arguments_lazy(f, a) -substitute(a::LazyNamedTensor, substitutions) = substitute_lazy(a, substitutions) -AbstractTrees.printnode(io::IO, a::LazyNamedTensor) = printnode_lazy(io, a) -printnode_namedtensor(io::IO, a::LazyNamedTensor) = printnode_lazy(io, a) -Base.show(io::IO, a::LazyNamedTensor) = show_lazy(io, a) -Base.show(io::IO, mime::MIME"text/plain", a::LazyNamedTensor) = show_lazy(io, mime, a) -Base.:*(a::LazyNamedTensor) = mul_lazy(a) -Base.:*(a1::LazyNamedTensor, a2::LazyNamedTensor) = mul_lazy(a1, a2) -Base.:+(a1::LazyNamedTensor, a2::LazyNamedTensor) = add_lazy(a1, a2) -Base.:-(a1::LazyNamedTensor, a2::LazyNamedTensor) = sub_lazy(a1, a2) -Base.:*(a1::Number, a2::LazyNamedTensor) = mul_lazy(a1, a2) -Base.:*(a1::LazyNamedTensor, a2::Number) = mul_lazy(a1, a2) -Base.:/(a1::LazyNamedTensor, a2::Number) = div_lazy(a1, a2) -Base.:-(a::LazyNamedTensor) = sub_lazy(a) - -# `IndexName`-specialized alias, paralleling `ITensor = NamedTensor{IndexName}`. -const LazyITensor = LazyNamedTensor{IndexName} diff --git a/src/lazyitensors/symbolicitensor.jl b/src/lazyitensors/symbolicitensor.jl deleted file mode 100644 index ed9da5b0..00000000 --- a/src/lazyitensors/symbolicitensor.jl +++ /dev/null @@ -1,80 +0,0 @@ -# Expression leaf with no array payload, so it defines no `unnamed`/`getindex`. -# A symbolic tensor is a placeholder substituted with a real tensor before -# contraction, so it only needs what drives contraction-order selection: the -# `names` and the index `size`s (the cost model uses lengths). Its `axes` are -# reconstructed as plain ranges of those sizes. Storing sizes and names as -# fields rather than type parameters lets symbolic tensors of different rank -# share one concrete type so a flat `Mul` over them stays concretely typed. -struct SymbolicNamedTensor{DimName, Name} <: AbstractNamedTensor{DimName} - name::Name - size::Vector{Int} - names::Vector{DimName} -end -function SymbolicNamedTensor(symname, inds) - dnames = collect(name.(inds)) - DimName = isempty(inds) ? typeof(symname) : eltype(dnames) - sizes = Int[length(i) for i in inds] - return SymbolicNamedTensor{DimName, typeof(symname)}(symname, sizes, dnames) -end - -symname(a::SymbolicNamedTensor) = getfield(a, :name) - -names(a::SymbolicNamedTensor) = getfield(a, :names) -function Base.axes(a::SymbolicNamedTensor) - return NamedUnitRange.( - Tuple(Base.OneTo.(getfield(a, :size))), - Tuple(getfield(a, :names)) - ) -end -Base.ndims(a::SymbolicNamedTensor) = length(getfield(a, :names)) - -function Base.:(==)(a::SymbolicNamedTensor, b::SymbolicNamedTensor) - return symname(a) == symname(b) && names(a) == names(b) -end -Base.isequal(a::SymbolicNamedTensor, b::SymbolicNamedTensor) = a == b -function Base.hash(a::SymbolicNamedTensor, h::UInt64) - h = hash(:SymbolicNamedTensor, h) - h = hash(symname(a), h) - return hash(names(a), h) -end - -# Products build lazy expressions rather than contracting numerically. -Base.:*(a::SymbolicNamedTensor, b::SymbolicNamedTensor) = lazy(a) * lazy(b) -Base.:*(a::SymbolicNamedTensor, b::LazyNamedTensor) = lazy(a) * b -Base.:*(a::LazyNamedTensor, b::SymbolicNamedTensor) = a * lazy(b) - -issymbolic(a) = a isa SymbolicNamedTensor -issymbolic(a::LazyNamedTensor) = !iscall(a) && issymbolic(unwrap(a)) - -function Base.show(io::IO, a::SymbolicNamedTensor) - print(io, symname(a)) - if ndims(a) > 0 - print(io, "[", join(names(a), ","), "]") - end - return nothing -end -function Base.show(io::IO, mime::MIME"text/plain", a::SymbolicNamedTensor) - summary(io, a) - println(io, ":") - show(io, a) - return nothing -end - -# `IndexName`-specialized alias, paralleling `ITensor = NamedTensor{IndexName}`. -const SymbolicITensor = SymbolicNamedTensor{IndexName} - -using AbstractTrees: AbstractTrees -function AbstractTrees.printnode(io::IO, a::SymbolicNamedTensor) - show(io, a) - return nothing -end - -function symnamedtensor(symname, dims) - return lazy(SymbolicNamedTensor(symname, dims)) -end -symnamedtensor(name) = symnamedtensor(name, ()) - -function printnode_namedtensor(io::IO, a::SymbolicNamedTensor) - AbstractTrees.printnode(io, a) - return nothing -end diff --git a/src/namedtensoroperator.jl b/src/namedtensoroperator.jl index 64dddae6..c8aa88bc 100644 --- a/src/namedtensoroperator.jl +++ b/src/namedtensoroperator.jl @@ -95,7 +95,7 @@ julia> outputinds(op) See also [`outputnames`](@ref), [`inputinds`](@ref), [`outputaxes`](@ref), [`operator`](@ref). """ -outputinds(a::AbstractNamedTensor) = inds(a)[dims(a, outputnames(a))] +outputinds(a::AbstractNamedTensor) = inds(a)[findnames(a, outputnames(a))] """ outputaxes(a) @@ -108,7 +108,9 @@ shape. See also [`outputinds`](@ref), [`inputaxes`](@ref), [`operator`](@ref). """ -outputaxes(a::AbstractNamedTensor) = map(Base.Fix1(inds, a), Tuple(dims(a, outputnames(a)))) +function outputaxes(a::AbstractNamedTensor) + return map(Base.Fix1(inds, a), Tuple(findnames(a, outputnames(a)))) +end """ inputinds(a) @@ -132,7 +134,7 @@ julia> inputinds(op) See also [`inputnames`](@ref), [`outputinds`](@ref), [`inputaxes`](@ref), [`operator`](@ref). """ -inputinds(a::AbstractNamedTensor) = conj.(inds(a)[dims(a, inputnames(a))]) +inputinds(a::AbstractNamedTensor) = conj.(inds(a)[findnames(a, inputnames(a))]) """ inputaxes(a) @@ -144,7 +146,7 @@ the non-dual domain space, so `a * randn(inputaxes(a))` contracts. See also [`inputinds`](@ref), [`outputaxes`](@ref), [`operator`](@ref). """ function inputaxes(a::AbstractNamedTensor) - return map(conj ∘ Base.Fix1(inds, a), Tuple(dims(a, inputnames(a)))) + return map(conj ∘ Base.Fix1(inds, a), Tuple(findnames(a, inputnames(a)))) end # `outputname(a, i, default)` returns the output name paired with input name `i`, and diff --git a/test/Project.toml b/test/Project.toml index aa6ef323..6df5ec2b 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,5 +1,4 @@ [deps] -AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" @@ -10,7 +9,6 @@ JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MatrixAlgebraKit = "6c742aac-3347-4629-af66-fc926824e5e4" Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6" -OMEinsumContractionOrders = "6f22d1fd-8eed-4bb7-9776-e7d684900715" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3" @@ -18,28 +16,24 @@ Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb" TensorAlgebra = "68bd88dc-f39d-4e12-b2ca-f046b68fcc6a" TensorKit = "07d1fe3e-3e46-537d-9eac-e9e13d0d4cec" TensorKitSectors = "13a9c161-d5da-41f0-bcbd-e1a08ae0647f" -TermInterface = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" VectorInterface = "409d34a3-91d5-4945-b6ec-7529ddf182d8" -WrappedUnions = "325db55a-9c6c-5b90-b1a2-ec87e7a38c44" [sources.ITensorBase] path = ".." [compat] -AbstractTrees = "0.4.5" Adapt = "4" Aqua = "0.8.9" Combinatorics = "1" GradedArrays = "0.17" -ITensorBase = "0.15" +ITensorBase = "0.16" ITensorPkgSkeleton = "0.3.42" JLArrays = "0.2, 0.3" LinearAlgebra = "1.10" MatrixAlgebraKit = "0.2, 0.3, 0.4, 0.5, 0.6" Mooncake = "0.4, 0.5" -OMEinsumContractionOrders = "1.3" Random = "1.10" SafeTestsets = "0.1" StableRNGs = "1" @@ -47,8 +41,6 @@ Suppressor = "0.2" TensorAlgebra = "0.23" TensorKit = "0.17" TensorKitSectors = "0.3.9" -TermInterface = "2" Test = "1.10" UUIDs = "1.10" VectorInterface = "0.6" -WrappedUnions = "0.3" diff --git a/test/test_abstracttrees.jl b/test/test_abstracttrees.jl deleted file mode 100644 index 54fc911b..00000000 --- a/test/test_abstracttrees.jl +++ /dev/null @@ -1,9 +0,0 @@ -using AbstractTrees: printnode -using ITensorBase: NamedTensor -using Test: @test, @testset - -@testset "AbstractTrees" begin - a = randn(3, 4) - na = NamedTensor(a, ("i", "j")) - @test sprint(printnode, na) == "{\"i\", \"j\"}" -end diff --git a/test/test_lazyitensors.jl b/test/test_lazyitensors.jl deleted file mode 100644 index 23eb5bff..00000000 --- a/test/test_lazyitensors.jl +++ /dev/null @@ -1,189 +0,0 @@ -using AbstractTrees: AbstractTrees, print_tree, printnode -using Base.Broadcast: materialize -using ITensorBase: @names, Greedy, LazyNamedTensor, Mul, NamedOneTo, NamedTensor, - NamedTensorOperator, SymbolicNamedTensor, inds, inputnames, ismul, lazy, names, - operator, optimize_evaluation_order, outputnames, state, substitute, symnamedtensor -using OMEinsumContractionOrders: ExhaustiveSearch, GreedyMethod, TreeSA -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 "LazyNamedTensors" 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 LazyNamedTensor - @test unwrap(li) isa NamedTensor - @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 = NamedTensor(randn(2, 2), (:i, :j)) - a2 = NamedTensor(randn(2, 2), (:j, :k)) - a3 = NamedTensor(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(LazyNamedTensor, *, [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 "symnamedtensor" begin - a1, a2, a3 = symnamedtensor.((:a1, :a2, :a3)) - @test a1 isa LazyNamedTensor - @test unwrap(a1) isa SymbolicNamedTensor - @test unwrap(a1) == SymbolicNamedTensor(:a1, ()) - @test isequal(unwrap(a1), SymbolicNamedTensor(:a1, ())) - @test isempty(inds(a1)) - @test isempty(names(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 = symnamedtensor.((: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 - - @testset "optimize_evaluation_order ($alg)" for alg in (Greedy(),) - i, j, k, l = NamedOneTo.((2, 3, 4, 5), (:i, :j, :k, :l)) - s = [ - symnamedtensor(:a, (i, j)), - symnamedtensor(:b, (j, k)), - symnamedtensor(:c, (k, l)), - ] - flat = lazy(Mul(s)) - ordered = optimize_evaluation_order(flat; alg) - @test ordered isa LazyNamedTensor - @test ismul(ordered) - # Reordering nests the flat product into binary contractions and preserves - # the open indices. - @test arity(ordered) == 2 - @test issetequal(names(ordered), names(flat)) - end - - @testset "optimize_evaluation_order with repeated arguments ($alg)" for alg in - (Greedy(),) - i, j = NamedOneTo.((2, 3), (:i, :j)) - a = randn(i, j) - # Three equal arguments: the optimizer must contract them pairwise rather than - # treating the repeats as one argument. - flat = lazy(Mul([lazy(a), lazy(a), lazy(a)])) - ordered = optimize_evaluation_order(flat; alg) - @test ismul(ordered) - @test arity(ordered) == 2 - @test issetequal(names(ordered), names(flat)) - @test materialize(ordered) ≈ (a * a) * a - end - - @testset "optimize_evaluation_order (OMEinsumContractionOrders $alg)" for alg in - ( - ExhaustiveSearch(), - GreedyMethod(), - TreeSA(), - ) - i, j, k, l = NamedOneTo.((2, 3, 4, 5), (:i, :j, :k, :l)) - s = [ - symnamedtensor(:a, (i, j)), - symnamedtensor(:b, (j, k)), - symnamedtensor(:c, (k, l)), - ] - flat = lazy(Mul(s)) - ordered = optimize_evaluation_order(flat; alg) - @test ordered isa LazyNamedTensor - @test ismul(ordered) - @test arity(ordered) == 2 - @test issetequal(names(ordered), names(flat)) - end -end - -@testset "lazy operator promotion" begin - i, j = NamedOneTo.(2, (:i, :j)) - p = randn(i, j) # eager plain - o = operator(randn(i, j), (i,), (j,)) # eager operator - lp = lazy(p) # lazy plain - lo = lazy(o) # lazy operator - P, O, LP, LO = typeof(p), typeof(o), typeof(lp), typeof(lo) - - # A lazy tensor promotes with a lazy or an eager tensor by promoting the leaf type, so any mix - # containing a lazy operand or an operator climbs to the lazy operator `LO`, while an all-plain - # network stays eager. - @test promote_type(P, O) == O - @test promote_type(P, LP) == LP - @test promote_type(P, LO) == LO - @test promote_type(O, LP) == LO - @test promote_type(O, LO) == LO - @test promote_type(LP, LO) == LO - @test promote_type(P, P) == P - - # `convert` wraps an eager tensor as lazy (converting the leaf), and rebuilds a lazy product with - # each leaf converted to the target leaf type. - @test convert(LP, p) isa LP - @test convert(LO, o) isa LO - clo = convert(LO, lp) - @test clo isa LO - @test materialize(clo) isa NamedTensorOperator - @test isempty(outputnames(materialize(clo))) && isempty(inputnames(materialize(clo))) -end diff --git a/test/test_namedtensor_basics.jl b/test/test_namedtensor_basics.jl index dd71c6ff..8734be94 100644 --- a/test/test_namedtensor_basics.jl +++ b/test/test_namedtensor_basics.jl @@ -1,8 +1,8 @@ using Combinatorics: Combinatorics using ITensorBase: @names, AbstractNamedTensor, Name, NameMismatch, Named, NamedCartesianIndex, NamedCartesianIndices, NamedOneTo, NamedTensor, NamedUnitRange, - align, aligned, apply, dim, dims, inds, isnamed, name, names, nametype, product, rename, - setnames, unname, unnamed, unnamedtype + align, aligned, apply, findname, findnames, inds, isnamed, name, names, nametype, + product, rename, setnames, unname, unnamed, unnamedtype using LinearAlgebra: LinearAlgebra using Random: default_rng using TensorAlgebra: datatype @@ -47,9 +47,9 @@ end # `Base.names` is an alternative spelling that forwards to `ITensorBase.names`. @test Base.names(na) == names(na) @test Base.names(na, 1) == names(na, 1) - @test dim(na, "i") == 1 - @test dim(na, "j") == 2 - @test dims(na, ("j", "i")) == (2, 1) + @test findname(na, "i") == 1 + @test findname(na, "j") == 2 + @test findnames(na, ("j", "i")) == (2, 1) @test na[1, 1] == a[1, 1] # The parent array's concrete type is erased from the type but is still # recoverable from an instance.