diff --git a/Project.toml b/Project.toml index ffdfee9..9bcdecf 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "ITensorBase" uuid = "4795dd04-0d67-49bb-8f44-b89c448a1dc7" -version = "0.6.3" +version = "0.7.0" authors = ["ITensor developers and contributors"] [workspace] @@ -14,6 +14,7 @@ Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +MatrixAlgebraKit = "6c742aac-3347-4629-af66-fc926824e5e4" OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" @@ -46,11 +47,12 @@ Combinatorics = "1" Compat = "4.16" ConstructionBase = "1.6" LinearAlgebra = "1.10" +MatrixAlgebraKit = "0.2, 0.3, 0.4, 0.5, 0.6" Mooncake = "0.4.202, 0.5" OrderedCollections = "1.6" Random = "1.10" SimpleTraits = "0.9.4" -TensorAlgebra = "0.9.6" +TensorAlgebra = "0.10" TensorOperations = "5.3.1" TermInterface = "2" TupleTools = "1.6" diff --git a/README.md b/README.md index f328f2b..324459d 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ julia> Pkg.add("ITensorBase") ## Examples ````julia -using ITensorBase: ITensorBase, ITensor, Index, aligndims, dename -using LinearAlgebra: qr +using ITensorBase: ITensorBase, ITensor, Index, aligndims, unname +using MatrixAlgebraKit: qr_compact using Test: @test i = Index(2) j = Index(2) @@ -54,11 +54,11 @@ a = randn(i, j) a′ = randn(j, i) b = randn(j, k) c = a * b -@test dename(c, (i, k)) ≈ dename(a, (i, j)) * dename(b, (j, k)) +@test unname(c, (i, k)) ≈ unname(a, (i, j)) * unname(b, (j, k)) d = a + a′ -@test dename(d, (i, j)) ≈ dename(a, (i, j)) + dename(a′, (i, j)) +@test unname(d, (i, j)) ≈ unname(a, (i, j)) + unname(a′, (i, j)) @test a ≈ aligndims(a, (j, i)) -q, r = qr(a, (i,)) +q, r = qr_compact(a, (i,)) @test q * r ≈ a ```` diff --git a/docs/Project.toml b/docs/Project.toml index 31c43b8..03cbb58 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -3,6 +3,7 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" ITensorBase = "4795dd04-0d67-49bb-8f44-b89c448a1dc7" ITensorFormatter = "b6bf39f1-c9d3-4bad-aad8-593d802f65fd" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" +MatrixAlgebraKit = "6c742aac-3347-4629-af66-fc926824e5e4" TensorAlgebra = "68bd88dc-f39d-4e12-b2ca-f046b68fcc6a" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" @@ -11,8 +12,9 @@ path = ".." [compat] Documenter = "1" -ITensorBase = "0.6" +ITensorBase = "0.7" ITensorFormatter = "0.2.27" Literate = "2" -TensorAlgebra = "0.9.6" +MatrixAlgebraKit = "0.2, 0.3, 0.4, 0.5, 0.6" +TensorAlgebra = "0.10" Test = "1.10" diff --git a/examples/Project.toml b/examples/Project.toml index 6b8443d..16bf8e1 100644 --- a/examples/Project.toml +++ b/examples/Project.toml @@ -1,10 +1,10 @@ [deps] ITensorBase = "4795dd04-0d67-49bb-8f44-b89c448a1dc7" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +MatrixAlgebraKit = "6c742aac-3347-4629-af66-fc926824e5e4" [sources.ITensorBase] path = ".." [compat] -ITensorBase = "0.6" -LinearAlgebra = "1.10" +ITensorBase = "0.7" +MatrixAlgebraKit = "0.2, 0.3, 0.4, 0.5, 0.6" diff --git a/examples/README.jl b/examples/README.jl index 529f869..2d7f5b5 100644 --- a/examples/README.jl +++ b/examples/README.jl @@ -43,8 +43,8 @@ julia> Pkg.add("ITensorBase") # ## Examples -using ITensorBase: ITensorBase, ITensor, Index, aligndims, dename -using LinearAlgebra: qr +using ITensorBase: ITensorBase, ITensor, Index, aligndims, unname +using MatrixAlgebraKit: qr_compact using Test: @test i = Index(2) j = Index(2) @@ -55,9 +55,9 @@ a = randn(i, j) a′ = randn(j, i) b = randn(j, k) c = a * b -@test dename(c, (i, k)) ≈ dename(a, (i, j)) * dename(b, (j, k)) +@test unname(c, (i, k)) ≈ unname(a, (i, j)) * unname(b, (j, k)) d = a + a′ -@test dename(d, (i, j)) ≈ dename(a, (i, j)) + dename(a′, (i, j)) +@test unname(d, (i, j)) ≈ unname(a, (i, j)) + unname(a′, (i, j)) @test a ≈ aligndims(a, (j, i)) -q, r = qr(a, (i,)) +q, r = qr_compact(a, (i,)) @test q * r ≈ a diff --git a/ext/ITensorBaseAdaptExt/ITensorBaseAdaptExt.jl b/ext/ITensorBaseAdaptExt/ITensorBaseAdaptExt.jl index dc8dc0d..f874b33 100644 --- a/ext/ITensorBaseAdaptExt/ITensorBaseAdaptExt.jl +++ b/ext/ITensorBaseAdaptExt/ITensorBaseAdaptExt.jl @@ -1,10 +1,10 @@ module ITensorBaseAdaptExt using Adapt: Adapt, adapt -using ITensorBase: AbstractITensor, denamed, dimnames, nameddims +using ITensorBase: AbstractITensor, dimnames, nameddims, unnamed function Adapt.adapt_structure(to, a::AbstractITensor) - return nameddims(adapt(to, denamed(a)), dimnames(a)) + return nameddims(adapt(to, unnamed(a)), dimnames(a)) end end diff --git a/ext/ITensorBaseMooncakeExt/ITensorBaseMooncakeExt.jl b/ext/ITensorBaseMooncakeExt/ITensorBaseMooncakeExt.jl index 7b80b42..7aeaa75 100644 --- a/ext/ITensorBaseMooncakeExt/ITensorBaseMooncakeExt.jl +++ b/ext/ITensorBaseMooncakeExt/ITensorBaseMooncakeExt.jl @@ -22,12 +22,12 @@ Mooncake.tangent_type(::Type{<:NamedUnitRange}) = Mooncake.NoTangent @zero_derivative DefaultCtx Tuple{typeof(uniquename), Any, Any} @zero_derivative DefaultCtx Tuple{typeof(to_inds), Any, Any} -using ITensorBase: AbstractITensor, ITensor, denamed +using ITensorBase: AbstractITensor, ITensor, unnamed using Mooncake: Tangent function Base.copyto!(dest::ITensor, src::Tangent) # TODO: Account for the `inds` of the Tangent? In other words, is the tangent data # aligned with the `dest` data? - copyto!(denamed(dest), src.fields.parent) + copyto!(unnamed(dest), src.fields.parent) return dest end diff --git a/ext/ITensorBaseTensorOperationsExt/ITensorBaseTensorOperationsExt.jl b/ext/ITensorBaseTensorOperationsExt/ITensorBaseTensorOperationsExt.jl index f1797d3..d8b3977 100644 --- a/ext/ITensorBaseTensorOperationsExt/ITensorBaseTensorOperationsExt.jl +++ b/ext/ITensorBaseTensorOperationsExt/ITensorBaseTensorOperationsExt.jl @@ -1,8 +1,8 @@ module ITensorBaseTensorOperationsExt using ITensorBase.TermInterface: arguments -using ITensorBase: ITensorBase, Optimal, denamed, inds, ismul, optimize_contraction_order, - substitute, symnameddims +using ITensorBase: ITensorBase, Optimal, inds, ismul, optimize_contraction_order, + substitute, symnameddims, unnamed using TensorOperations: TensorOperations, optimaltree function contraction_tree_to_expr(f, tree) @@ -18,7 +18,7 @@ function ITensorBase.optimize_contraction_order(alg::Optimal, 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)) + inds_to_dims = Dict(i => Float64(length(i)) for i in reduce(∪, inds_network)) tree, _ = optimaltree(inds_network, inds_to_dims) return contraction_tree_to_expr(i -> ts[i], tree) end diff --git a/src/abstractitensor.jl b/src/abstractitensor.jl index 350af23..ddcc882 100644 --- a/src/abstractitensor.jl +++ b/src/abstractitensor.jl @@ -48,13 +48,13 @@ dimnametype(type::Type{<:AbstractITensor}) = Any # Unwrapping the names (named-array interface). # TODO: Use `IsNamed` trait? -denamed(a::AbstractITensor) = throw(MethodError(denamed, a)) -denamed(a::AbstractITensor, inds) = denamed(aligneddims(a, inds)) -dename(a::AbstractITensor, inds) = denamed(aligndims(a, inds)) +unnamed(a::AbstractITensor) = throw(MethodError(unnamed, a)) +unnamed(a::AbstractITensor, inds) = unnamed(aligneddims(a, inds)) +unname(a::AbstractITensor, inds) = unnamed(aligndims(a, inds)) # Output the named axes/indices of the named dims array, as a `Tuple` (even though # the dimension names are stored as a `Vector`). -inds(a::AbstractITensor) = named.(axes(denamed(a)), Tuple(dimnames(a))) +inds(a::AbstractITensor) = named.(axes(unnamed(a)), Tuple(dimnames(a))) inds(a::AbstractITensor, dim::Int) = inds(a)[dim] isnamed(::Type{<:AbstractITensor}) = true @@ -91,7 +91,7 @@ end """ nameddims(a::AbstractArray, inds) -Construct a named dimensions array from an denamed array `a` and named dimensions `inds`. +Construct a named dimensions array from an unnamed array `a` and named dimensions `inds`. """ function nameddims(a::AbstractArray, inds) return ITensor(a, inds) @@ -127,8 +127,8 @@ function checked_indexin(x::AbstractUnitRange, y::AbstractUnitRange) return findfirst(==(first(x)), y):findfirst(==(last(x)), y) end -Base.copy(a::AbstractITensor) = nameddimsof(a, copy(denamed(a))) -Base.zero(a::AbstractITensor) = nameddimsof(a, zero(denamed(a))) +Base.copy(a::AbstractITensor) = nameddimsof(a, copy(unnamed(a))) +Base.zero(a::AbstractITensor) = nameddimsof(a, zero(unnamed(a))) # `CartesianIndices` of a named tensor is the parent's, via the named axes (as the # `AbstractArray` fallback did through `axes`). @@ -138,7 +138,7 @@ Base.CartesianIndices(a::AbstractITensor) = CartesianIndices(axes(a)) # The default `AbstractArray` fallback would broadcast `conj` over elements without # touching the axes, which silently changes the contraction convention for tensors # with graded (dual-tagged) axes. -Base.conj(a::AbstractITensor) = nameddimsof(a, conj(denamed(a))) +Base.conj(a::AbstractITensor) = nameddimsof(a, conj(unnamed(a))) # `LinearAlgebra.normalize` infers result eltype via `typeof(first(a)/nrm)`, which # scalar-indexes block-structured storage. `a / norm(a, p)` already preserves names. @@ -146,7 +146,7 @@ function LinearAlgebra.normalize(a::AbstractITensor, p::Real = 2) return a / LinearAlgebra.norm(a, p) end function LinearAlgebra.normalize!(a::AbstractITensor, p::Real = 2) - LinearAlgebra.normalize!(denamed(a), p) + LinearAlgebra.normalize!(unnamed(a), p) return a end @@ -162,18 +162,18 @@ Base.:/(a::AbstractITensor, x::Number) = a ./ x # Forward `Random.randn!` / `Random.rand!` to the concrete storage so they # see the runtime eltype. function Random.randn!(rng::Random.AbstractRNG, a::AbstractITensor) - Random.randn!(rng, denamed(a)) + Random.randn!(rng, unnamed(a)) return a end function Random.rand!(rng::Random.AbstractRNG, a::AbstractITensor) - Random.rand!(rng, denamed(a)) + Random.rand!(rng, unnamed(a)) return a end function Base.copyto!(a_dest::AbstractITensor, a_src::AbstractITensor) - a′_dest = denamed(a_dest) - # TODO: Use `denamed` to do the permutations lazily. - a′_src = dename(a_src, inds(a_dest)) + a′_dest = unnamed(a_dest) + # TODO: Use `unnamed` to do the permutations lazily. + a′_src = unname(a_src, inds(a_dest)) copyto!(a′_dest, a′_src) return a_dest end @@ -193,13 +193,13 @@ end # These are defined since the Base versions assume the eltype and ndims are known # at compile time, which isn't true for ITensors. -Base.Array(a::AbstractITensor) = Array(denamed(a)) -Base.Array{T}(a::AbstractITensor) where {T} = Array{T}(denamed(a)) -Base.Array{T, N}(a::AbstractITensor) where {T, N} = Array{T, N}(denamed(a)) +Base.Array(a::AbstractITensor) = Array(unnamed(a)) +Base.Array{T}(a::AbstractITensor) where {T} = Array{T}(unnamed(a)) +Base.Array{T, N}(a::AbstractITensor) where {T, N} = Array{T, N}(unnamed(a)) Base.AbstractArray{T}(a::AbstractITensor) where {T} = AbstractArray{T, ndims(a)}(a) function Base.AbstractArray{T, N}(a::AbstractITensor) where {T, N} dest = similar(a, T) - copyto_axcheck!(denamed(dest), denamed(a)) + copyto_axcheck!(unnamed(dest), unnamed(a)) return dest end @@ -210,8 +210,9 @@ function Base.size(a::AbstractITensor) return length.(axes(a)) end -# `length` is intentionally not defined: an ITensor's dimensions are named and -# unordered, so there is no canonical linearization into `1:length`. +# An ITensor has no single name, so `length` is the plain element count. It is the +# product of the (now plain `Int`) per-dimension sizes. +Base.length(a::AbstractITensor) = prod(size(a)) # Circumvent issue when ndims isn't known at compile time. Base.axes(a::AbstractITensor, d) = axes(a)[d] @@ -220,26 +221,26 @@ Base.axes(a::AbstractITensor, d) = axes(a)[d] Base.size(a::AbstractITensor, d) = size(a)[d] # Circumvent issue when ndims isn't known at compile time. -Base.ndims(a::AbstractITensor) = ndims(denamed(a)) +Base.ndims(a::AbstractITensor) = ndims(unnamed(a)) # Circumvent issue when eltype isn't known at compile time. -Base.eltype(a::AbstractITensor) = eltype(denamed(a)) +Base.eltype(a::AbstractITensor) = eltype(unnamed(a)) using VectorInterface: VectorInterface, scalartype # Circumvent issue when eltype isn't known at compile time. -VectorInterface.scalartype(a::AbstractITensor) = scalartype(denamed(a)) +VectorInterface.scalartype(a::AbstractITensor) = scalartype(unnamed(a)) Base.axes(a::AbstractITensor, dimname::Name) = axes(a, dim(a, dimname)) Base.size(a::AbstractITensor, dimname::Name) = size(a, dim(a, dimname)) function similar_nameddims(a::AbstractITensor, elt::Type, ax) return nameddims( - similar(denamed(a), elt, denamed.(Tuple(ax))), + similar(unnamed(a), elt, unnamed.(Tuple(ax))), name.(ax) ) end function similar_nameddims(a::AbstractArray, elt::Type, ax) - return nameddims(similar(a, elt, denamed.(Tuple(ax))), name.(ax)) + return nameddims(similar(a, elt, unnamed.(Tuple(ax))), name.(ax)) end # Base.similar gets the eltype at compile time. @@ -248,7 +249,7 @@ function Base.similar(a::AbstractITensor, elt::Type) return similar_nameddims(a, elt) end function similar_nameddims(a::AbstractITensor, elt::Type) - return nameddimsof(a, similar(denamed(a), elt)) + return nameddimsof(a, similar(unnamed(a), elt)) end # This is defined explicitly since the Base version expects the eltype @@ -282,44 +283,44 @@ function Base.similar( return similar_nameddims(a, elt, inds) end function setdimnames(a::AbstractITensor, dimnames) - return nameddims(denamed(a), dimnames) + return nameddims(unnamed(a), dimnames) end function replacedimnames(a::AbstractITensor, replacements::Pair...) new_dimnames = replace(dimnames(a), replacements...) - return nameddims(denamed(a), new_dimnames) + return nameddims(unnamed(a), new_dimnames) end function replacedimnames(f, a::AbstractITensor) new_dimnames = replace(f, dimnames(a)) - return nameddims(denamed(a), new_dimnames) + return nameddims(unnamed(a), new_dimnames) end mapdimnames(f, a::AbstractITensor) = replacedimnames(f, a) function replaceinds(a::AbstractITensor, replacements::Pair...) new_inds = replace(inds(a), replacements...) - return denamed(a)[new_inds...] + return unnamed(a)[new_inds...] end function replaceinds(f, a::AbstractITensor) new_inds = replace(f, inds(a)) - return denamed(a)[new_inds...] + return unnamed(a)[new_inds...] end mapinds(f, a::AbstractITensor) = replaceinds(f, a) # `Base.isempty(a::AbstractArray)` is defined as `length(a) == 0`, -# which involves comparing a named integer to an denamed integer +# which involves comparing a named integer to an unnamed integer # which isn't well defined. -Base.isempty(a::AbstractITensor) = isempty(denamed(a)) +Base.isempty(a::AbstractITensor) = isempty(unnamed(a)) # Define this on objects rather than types in case the wrapper type # isn't known at compile time, like for the ITensor type. -Base.IndexStyle(a::AbstractITensor) = IndexStyle(denamed(a)) -Base.eachindex(a::AbstractITensor) = eachindex(denamed(a)) +Base.IndexStyle(a::AbstractITensor) = IndexStyle(unnamed(a)) +Base.eachindex(a::AbstractITensor) = eachindex(unnamed(a)) # Iteration, keys, and pairs forward to the parent (these were previously inherited # from `AbstractArray`). -Base.iterate(a::AbstractITensor, state...) = iterate(denamed(a), state...) -Base.keys(a::AbstractITensor) = keys(denamed(a)) -Base.pairs(a::AbstractITensor) = pairs(denamed(a)) +Base.iterate(a::AbstractITensor, state...) = iterate(unnamed(a), state...) +Base.keys(a::AbstractITensor) = keys(unnamed(a)) +Base.pairs(a::AbstractITensor) = pairs(unnamed(a)) # Multi-argument `eachindex` dispatches on the named index style, as the # `AbstractArray` version did. @@ -376,8 +377,8 @@ function Base.eltype( return NamedDimsCartesianIndex{N, Index} end Base.eltype(I::NamedDimsCartesianIndices) = eltype(typeof(I)) -Base.axes(I::NamedDimsCartesianIndices) = (only ∘ axes ∘ denamed).(I.indices) -Base.size(I::NamedDimsCartesianIndices) = (length ∘ denamed).(I.indices) +Base.axes(I::NamedDimsCartesianIndices) = (only ∘ axes).(I.indices) +Base.size(I::NamedDimsCartesianIndices) = length.(I.indices) function Base.getindex(a::NamedDimsCartesianIndices{N}, I::Vararg{Int, N}) where {N} index = map(a.indices, I) do r, i @@ -386,15 +387,15 @@ function Base.getindex(a::NamedDimsCartesianIndices{N}, I::Vararg{Int, N}) where return NamedDimsCartesianIndex(index) end -function denamed(I::NamedDimsCartesianIndices) - return CartesianIndices(denamed.(I.indices)) +function unnamed(I::NamedDimsCartesianIndices) + return CartesianIndices(unnamed.(I.indices)) end # Iterating yields `NamedDimsCartesianIndex`es. The generic `AbstractITensor` -# iteration forwards to `denamed`, which here is a plain `CartesianIndices`, so +# iteration forwards to `unnamed`, which here is a plain `CartesianIndices`, so # convert each parent index back through `getindex`. function Base.iterate(I::NamedDimsCartesianIndices, state...) - y = iterate(denamed(I), state...) + y = iterate(unnamed(I), state...) isnothing(y) && return nothing cartesian, next_state = y return I[Tuple(cartesian)...], next_state @@ -411,14 +412,14 @@ function Base.eachindex( return NamedDimsCartesianIndices(inds(a1)) end -# `dename` (eager), not `denamed` (lazy view): reducing over a lazy permuted view +# `unname` (eager), not `unnamed` (lazy view): reducing over a lazy permuted view # scalar-indexes, which graded arrays forbid. # Base version ignores dimension names. # TODO: Use `mapreduce(isequal, &&, a1, a2)`? function Base.isequal(a1::AbstractITensor, a2::AbstractITensor) issetequal(dimnames(a1), dimnames(a2)) || return false - return isequal(denamed(a1), dename(a2, dimnames(a1))) + return isequal(unnamed(a1), unname(a2, dimnames(a1))) end # Base version ignores dimension names. @@ -426,13 +427,13 @@ end # TODO: Handle `missing` values properly. function Base.:(==)(a1::AbstractITensor, a2::AbstractITensor) issetequal(dimnames(a1), dimnames(a2)) || return false - return denamed(a1) == dename(a2, dimnames(a1)) + return unnamed(a1) == unname(a2, dimnames(a1)) end # Base version ignores dimension names. function Base.isapprox(a1::AbstractITensor, a2::AbstractITensor; kwargs...) issetequal(dimnames(a1), dimnames(a2)) || return false - return isapprox(denamed(a1), dename(a2, dimnames(a1)); kwargs...) + return isapprox(unnamed(a1), unname(a2, dimnames(a1)); kwargs...) end # Generalization of `Base.sort` to Tuples for Julia v1.10 compatibility. @@ -443,7 +444,7 @@ _sort(x::NTuple{N}; kwargs...) where {N} = NTuple{N}(sort(collect(x); kwargs...) function Base.hash(a::AbstractITensor, h::UInt64) h = hash(:ITensor, h) a′ = aligneddims(a, _sort(dimnames(a))) - h = hash(denamed(a′), h) + h = hash(unnamed(a′), h) for i in inds(a′) h = hash(i, h) end @@ -454,8 +455,8 @@ end # Scalar indexing -Base.firstindex(a::AbstractITensor) = firstindex(denamed(a)) -Base.lastindex(a::AbstractITensor) = lastindex(denamed(a)) +Base.firstindex(a::AbstractITensor) = firstindex(unnamed(a)) +Base.lastindex(a::AbstractITensor) = lastindex(unnamed(a)) function Base.firstindex(a::AbstractITensor, d) return FirstIndex(a, d) @@ -478,7 +479,7 @@ function Base.to_indices( return to_indices(a, Tuple(axes(a)), I) end function Base.checkbounds(::Type{Bool}, a::AbstractITensor, I::Int...) - return checkbounds(Bool, denamed(a), I...) + return checkbounds(Bool, unnamed(a), I...) end function Base.to_indices( @@ -489,7 +490,7 @@ function Base.to_indices( @assert isperm(perm) I = map(p -> I[p], perm) return map(inds(a), I) do dimname, i - return checked_indexin(denamed(i), denamed(dimname)) + return checked_indexin(unnamed(i), unnamed(dimname)) end end function Base.to_indices( @@ -513,7 +514,7 @@ function Base.getindex(a::AbstractITensor, I...) end function Base.getindex(a::AbstractITensor, I1::Int, Irest::Int...) - return getindex(denamed(a), I1, Irest...) + return getindex(unnamed(a), I1, Irest...) end function Base.getindex( a::AbstractITensor, I1::NamedInteger, Irest::NamedInteger... @@ -521,15 +522,15 @@ function Base.getindex( return getindex(a, to_indices(a, (I1, Irest...))...) end function Base.getindex(a::AbstractITensor) - return getindex(denamed(a)) + return getindex(unnamed(a)) end # Linear indexing. function Base.getindex(a::AbstractITensor, I::Int) - return getindex(denamed(a), I) + return getindex(unnamed(a), I) end function Base.setindex!(a::AbstractITensor, value, I1::Int, Irest::Int...) - setindex!(denamed(a), value, I1, Irest...) + setindex!(unnamed(a), value, I1, Irest...) return a end function Base.setindex!(a::AbstractITensor, value, I::CartesianIndex) @@ -553,17 +554,17 @@ function Base.setindex!(a::AbstractITensor, value, I1::Pair, Irest::Pair...) return a end function Base.setindex!(a::AbstractITensor, value) - setindex!(denamed(a), value) + setindex!(unnamed(a), value) return a end # Linear indexing. function Base.setindex!(a::AbstractITensor, value, I::Int) - setindex!(denamed(a), value, I) + setindex!(unnamed(a), value, I) return a end function Base.isassigned(a::AbstractITensor, I::Int...) - return isassigned(denamed(a), I...) + return isassigned(unnamed(a), I...) end # Slicing @@ -608,7 +609,7 @@ function Base.getindex(a::Array, I1::NamedUnitRange) end function Base.view(a::AbstractArray, I1::NamedViewIndex, Irest::NamedViewIndex...) I = (I1, Irest...) - return nameddims(view(a, denamed.(I)...), name.(I)) + return nameddims(view(a, unnamed.(I)...), name.(I)) end # TODO: Should this be a view? @@ -647,7 +648,7 @@ function Base.view(a::AbstractITensor, I1::NamedViewIndex, Irest::NamedViewIndex "Dimension name mismatch $(dimnames(a)), $(name.(I))." ) ) - Ip = map(p -> denamed(I[p]), perm) + Ip = map(p -> unnamed(I[p]), perm) return view_nameddims(a, Ip...) end @@ -666,7 +667,7 @@ isscalarindex(I::Real) = true function view_nameddims(a::AbstractITensor, I...) nonscalar_dims = filter(dim -> !isscalarindex(I[dim]), ntuple(identity, ndims(a))) nonscalar_dimnames = map(dim -> dimnames(a, dim), nonscalar_dims) - return nameddims(view(denamed(a), I...), nonscalar_dimnames) + return nameddims(view(unnamed(a), I...), nonscalar_dimnames) end function Base.view(a::AbstractITensor, I::ViewIndex...) @@ -712,7 +713,7 @@ end function Base.setindex!( a::AbstractITensor, value::AbstractArray, I1::ViewIndex, Irest::ViewIndex... ) - setindex!(denamed(a), value, I1, Irest...) + setindex!(unnamed(a), value, I1, Irest...) return a end @@ -726,7 +727,7 @@ function aligndims(a::AbstractITensor, dims) "Dimension name mismatch $(dimnames(a)), $(new_dimnames)." ) ) - return nameddims(permutedims(denamed(a), perm), new_dimnames) + return nameddims(permutedims(unnamed(a), perm), new_dimnames) end function aligneddims(a::AbstractITensor, dims) @@ -738,7 +739,7 @@ function aligneddims(a::AbstractITensor, dims) ) ) return nameddims( - permuteddims(denamed(a), perm), new_dimnames + permuteddims(unnamed(a), perm), new_dimnames ) end @@ -772,7 +773,7 @@ for (f, f′) in [(:rand, :_rand), (:randn, :_randn)] elt::Type{<:Number}, ax::Tuple{NamedUnitRange, Vararg{NamedUnitRange}} ) - a = $f′(rng, elt, denamed.(ax)) + a = $f′(rng, elt, unnamed.(ax)) return a[Name.(name.(ax))...] end function Base.$f( @@ -807,7 +808,7 @@ for f in [:zeros, :ones], dimtype in [:NamedInteger, :NamedUnitRange] function Base.$f( elt::Type{<:Number}, ax::Tuple{$dimtype, Vararg{$dimtype}} ) - a = $f(elt, denamed.(ax)) + a = $f(elt, unnamed.(ax)) return a[Name.(name.(ax))...] end function Base.$f(elt::Type{<:Number}, dim1::$dimtype, dims::Vararg{$dimtype}) @@ -820,7 +821,7 @@ end for dimtype in [:NamedInteger, :NamedUnitRange] @eval begin function Base.fill(value, ax::Tuple{$dimtype, Vararg{$dimtype}}) - a = fill(value, denamed.(ax)) + a = fill(value, unnamed.(ax)) return a[Name.(name.(ax))...] end function Base.fill(value, dim1::$dimtype, dims::Vararg{$dimtype}) @@ -830,15 +831,15 @@ for dimtype in [:NamedInteger, :NamedUnitRange] end function Base.fill!(a::AbstractITensor, v) - fill!(denamed(a), v) + fill!(unnamed(a), v) return a end function Base.map!(f, a_dest::AbstractITensor, a_srcs::AbstractITensor...) - a′_dest = denamed(a_dest) - # TODO: Use `denamed` to do the permutations lazily. - # TODO: Define `dename[d](dimnames) = Base.Fix1(dename[d], dimnames)` and use it here? - a′_srcs = Base.Fix2(dename, dimnames(a_dest)).(a_srcs) + a′_dest = unnamed(a_dest) + # TODO: Use `unnamed` to do the permutations lazily. + # TODO: Define `unname[d](dimnames) = Base.Fix1(unname[d], dimnames)` and use it here? + a′_srcs = Base.Fix2(unname, dimnames(a_dest)).(a_srcs) map!(f, a′_dest, a′_srcs...) return a_dest end @@ -849,19 +850,19 @@ function Base.map(f, a_srcs::AbstractITensor...) end function Base.mapreduce(f, op, a::AbstractITensor; kwargs...) - return mapreduce(f, op, denamed(a); kwargs...) + return mapreduce(f, op, unnamed(a); kwargs...) end # `sum` is routed to the underlying data rather than left to fall back on the # `mapreduce` method above because some array types (such as graded arrays) define -# `Base.sum` directly but not the general `mapreduce`, so the denamed `sum` is the +# `Base.sum` directly but not the general `mapreduce`, so the unnamed `sum` is the # path that works for them. function Base.sum(a::AbstractITensor; kwargs...) - return sum(denamed(a); kwargs...) + return sum(unnamed(a); kwargs...) end function LinearAlgebra.promote_leaf_eltypes(a::AbstractITensor) - return LinearAlgebra.promote_leaf_eltypes(denamed(a)) + return LinearAlgebra.promote_leaf_eltypes(unnamed(a)) end # Printing @@ -912,12 +913,12 @@ end function Base.show(io::IO, mime::MIME"text/plain", a::AbstractITensor) summary(io, a) println(io, ":") - show(io, mime, denamed(a)) + show(io, mime, unnamed(a)) return nothing end function Base.show(io::IO, a::AbstractITensor) - show(io, denamed(a)) + show(io, unnamed(a)) print(io, "[", join(inds(a), ", "), "]") return nothing end diff --git a/src/abstractnamedarray.jl b/src/abstractnamedarray.jl index b623e9e..0bec3da 100644 --- a/src/abstractnamedarray.jl +++ b/src/abstractnamedarray.jl @@ -1,15 +1,15 @@ -# `Name` leads (matching `AbstractITensor{DimName}`); `DenamedT` is the unwrapped -# element type and `N` the rank. The element type is always `Named{Name, DenamedT}`, +# `Name` leads (matching `AbstractITensor{DimName}`); `UnnamedT` is the unwrapped +# element type and `N` the rank. The element type is always `Named{Name, UnnamedT}`, # so it is hardcoded in the `AbstractArray` supertype rather than carried as a # parameter. The wrapped-container type lives only on the concrete subtypes. -abstract type AbstractNamedArray{Name, DenamedT, N} <: -AbstractArray{Named{Name, DenamedT}, N} end +abstract type AbstractNamedArray{Name, UnnamedT, N} <: +AbstractArray{Named{Name, UnnamedT}, N} end -const AbstractNamedVector{Name, DenamedT} = AbstractNamedArray{Name, DenamedT, 1} -const AbstractNamedMatrix{Name, DenamedT} = AbstractNamedArray{Name, DenamedT, 2} +const AbstractNamedVector{Name, UnnamedT} = AbstractNamedArray{Name, UnnamedT, 1} +const AbstractNamedMatrix{Name, UnnamedT} = AbstractNamedArray{Name, UnnamedT, 2} # Minimal interface. -denamed(a::AbstractNamedArray) = throw(MethodError(denamed, Tuple{typeof(a)})) +unnamed(a::AbstractNamedArray) = throw(MethodError(unnamed, Tuple{typeof(a)})) name(a::AbstractNamedArray) = throw(MethodError(name, Tuple{typeof(a)})) # This can be customized to output different named array types, @@ -21,10 +21,10 @@ named(a::AbstractArray, name) = namedarray(a, name) # Derived interface. # TODO: Use `Accessors.@set`? -setname(a::AbstractNamedArray, name) = namedarray(denamed(a), name) +setname(a::AbstractNamedArray, name) = namedarray(unnamed(a), name) # `Name` leads, so `nametype` reads it from the abstract type. The wrapped -# container type lives only on the concrete subtypes, so `denamedtype` is defined +# container type lives only on the concrete subtypes, so `unnamedtype` is defined # per concrete type rather than here. nametype(::Type{<:AbstractNamedArray{Name}}) where {Name} = Name @@ -33,55 +33,57 @@ isnamed(::Type{<:AbstractNamedArray}) = true # Equality and hashing are type-agnostic across named array types, following Base's # array convention (`[1, 2, 3] == 1:3`, and they hash equally): two named arrays are -# equal when their names and denamed values are equal, regardless of concrete type. +# equal when their names and unnamed values are equal, regardless of concrete type. # Hashing uses a single shared tag (not the concrete type) so that # `a == b => hash(a) == hash(b)` holds; there are no external subtypes that need to # override this. function Base.:(==)(a1::AbstractNamedArray, a2::AbstractNamedArray) - return name(a1) == name(a2) && denamed(a1) == denamed(a2) + return name(a1) == name(a2) && unnamed(a1) == unnamed(a2) end Base.hash(a::AbstractNamedArray, h::UInt) = hash_named(:NamedArray, a, h) -getindex_named(a::AbstractArray, I...) = named(getindex(denamed(a), I...), name(a)) +getindex_named(a::AbstractArray, I...) = named(getindex(unnamed(a), I...), name(a)) # Array funcionality. -Base.size(a::AbstractNamedArray) = map(s -> named(s, name(a)), size(denamed(a))) -Base.axes(a::AbstractNamedArray) = map(s -> named(s, name(a)), axes(denamed(a))) -Base.eachindex(a::AbstractNamedArray) = eachindex(denamed(a)) -# A named array carries a single name, so its length is that name attached to the -# denamed length. No fusion is involved, unlike a multi-dim `AbstractITensor`, which -# has no single name and so does not define `length`. -Base.length(a::AbstractNamedArray) = named(length(denamed(a)), name(a)) +Base.size(a::AbstractNamedArray) = size(unnamed(a)) +# `axes`/`eachindex` are the positional index layer and stay plain (unnamed), +# satisfying the `AbstractArray` contract that `axes` are `AbstractUnitRange{Int}`. +# Names appear on the elements (`getindex`, `first`, `last`, iteration), not here. +Base.axes(a::AbstractNamedArray) = axes(unnamed(a)) +Base.eachindex(a::AbstractNamedArray) = eachindex(unnamed(a)) +# `length` and `size` are plain counts: the name lives on the axes and on the named +# elements (`a[i]`, `first`, `last`, iteration), not on the scalar count. +Base.length(a::AbstractNamedArray) = length(unnamed(a)) function Base.getindex(a::AbstractNamedArray{<:Any, <:Any, N}, I::Vararg{Int, N}) where {N} return getindex_named(a, I...) end function Base.getindex(a::AbstractNamedArray, I::Int) return getindex_named(a, I) end -Base.isempty(a::AbstractNamedArray) = isempty(denamed(a)) +Base.isempty(a::AbstractNamedArray) = isempty(unnamed(a)) ## function Base.AbstractArray{Int}(a::AbstractNamedArray) -## return AbstractArray{Int}(denamed(a)) +## return AbstractArray{Int}(unnamed(a)) ## end ## ## Base.iterate(a::AbstractNamedArray) = isempty(a) ? nothing : (first(a), first(a)) ## function Base.iterate(a::AbstractNamedArray, i) ## i == last(a) && return nothing -## next = named(denamed(i) + denamed(step(a)), name(a)) +## next = named(unnamed(i) + unnamed(step(a)), name(a)) ## return (next, next) ## end function uniquename(rng::AbstractRNG, a::AbstractNamedArray) - return named(denamed(a), uniquename(rng, name(a))) + return named(unnamed(a), uniquename(rng, name(a))) end function Base.show(io::IO, a::AbstractNamedArray) - print(io, "named(", denamed(a), ", ", repr(name(a)), ")") + print(io, "named(", unnamed(a), ", ", repr(name(a)), ")") return nothing end function Base.show(io::IO, mime::MIME"text/plain", a::AbstractNamedArray) print(io, "named(\n") - show(io, mime, denamed(a)) + show(io, mime, unnamed(a)) print(io, ",\n ", repr(name(a)), ")") return nothing end diff --git a/src/broadcast.jl b/src/broadcast.jl index 2087c8a..f6ad56a 100644 --- a/src/broadcast.jl +++ b/src/broadcast.jl @@ -1,5 +1,5 @@ -using ..ITensorBase: AbstractITensor, ITensorBase, NamedUnitRange, dename, denamed, getperm, - inds, name, named, nameddims +using ..ITensorBase: AbstractITensor, ITensorBase, NamedUnitRange, getperm, inds, name, + named, nameddims, unname, unnamed using Base.Broadcast: Broadcast as BC, Broadcasted, broadcast_shape, broadcasted, check_broadcast_shape, combine_axes using TensorAlgebra: TensorAlgebra as TA @@ -75,7 +75,7 @@ function set_promote_shape( ) where {N} perm = getperm(ax2, ax1) ax2_aligned = map(i -> ax2[i], perm) - ax_promoted = promote_shape(denamed.(ax1), denamed.(ax2_aligned)) + ax_promoted = promote_shape(unnamed.(ax1), unnamed.(ax2_aligned)) return named.(ax_promoted, name.(ax1)) end @@ -110,30 +110,30 @@ function set_check_broadcast_shape( ) where {N} perm = getperm(ax2, ax1) ax2_aligned = map(i -> ax2[i], perm) - check_broadcast_shape(denamed.(ax1), denamed.(ax2_aligned)) + check_broadcast_shape(unnamed.(ax1), unnamed.(ax2_aligned)) return nothing end set_check_broadcast_shape(ax1::Tuple{}, ax2::Tuple{}) = nothing -broadcasted_denamed(x::Number, inds) = x -broadcasted_denamed(a::AbstractITensor, inds) = denamed(a, inds) -function broadcasted_denamed(bc::Broadcasted, inds) - return broadcasted(bc.f, Base.Fix2(broadcasted_denamed, inds).(bc.args)...) +broadcasted_unnamed(x::Number, inds) = x +broadcasted_unnamed(a::AbstractITensor, inds) = unnamed(a, inds) +function broadcasted_unnamed(bc::Broadcasted, inds) + return broadcasted(bc.f, Base.Fix2(broadcasted_unnamed, inds).(bc.args)...) end # A bare (unnamed) array operand, used as an allocation prototype so a broadcast # result inherits the operands' backend (e.g. graded) rather than a lazy permuted # wrapper's `similar` (which can drop the backend). -denamed_prototype(bc::Broadcasted) = denamed_prototype(bc.args...) -denamed_prototype(arg::AbstractITensor, args...) = denamed(arg) -denamed_prototype(arg::Broadcasted, args...) = denamed_prototype(arg.args..., args...) -denamed_prototype(arg, args...) = denamed_prototype(args...) +unnamed_prototype(bc::Broadcasted) = unnamed_prototype(bc.args...) +unnamed_prototype(arg::AbstractITensor, args...) = unnamed(arg) +unnamed_prototype(arg::Broadcasted, args...) = unnamed_prototype(arg.args..., args...) +unnamed_prototype(arg, args...) = unnamed_prototype(args...) function Base.similar(bc::Broadcasted{<:AbstractITensorStyle}, elt::Type, ax) inds_a = name.(ax) - bc_denamed = broadcasted_denamed(bc, inds_a) - a_denamed = similar(bc_denamed, elt) - return nameddims(a_denamed, inds_a) + bc_unnamed = broadcasted_unnamed(bc, inds_a) + a_unnamed = similar(bc_unnamed, elt) + return nameddims(a_unnamed, inds_a) end inds(bc::Broadcasted) = name.(axes(bc)) @@ -144,36 +144,36 @@ function Base.copy(bc::Broadcasted{<:AbstractITensorStyle}) # copyto!(similar(bc, elt), bc) # ``` # but `combine_eltypes` is based on type inference, which might fail. - # Calling broadcasted on the denamed arrays reuses the code logic in + # Calling broadcasted on the unnamed arrays reuses the code logic in # Base.Broadcast for handling cases where type inference fails by determining # the output element type at runtime with widening. inds_dest = inds(bc) - bc_denamed = broadcasted_denamed(bc, inds_dest) - lb = TA.tryflattenlinear(bc_denamed) + bc_unnamed = broadcasted_unnamed(bc, inds_dest) + lb = TA.tryflattenlinear(bc_unnamed) if isnothing(lb) # Not a linear combination: ordinary fused broadcast. - dest_denamed = copy(bc_denamed) + dest_unnamed = copy(bc_unnamed) else # Linear: lower to bipermutedimsopadd!. Allocate from an operand so the # result keeps the backend, using the backend's result axes (not `lb`'s). - dest_axes = denamed.(Tuple(axes(bc))) - dest_denamed = similar(denamed_prototype(bc), eltype(lb), dest_axes) - copyto!(dest_denamed, lb) + dest_axes = unnamed.(Tuple(axes(bc))) + dest_unnamed = similar(unnamed_prototype(bc), eltype(lb), dest_axes) + copyto!(dest_unnamed, lb) end - return nameddims(dest_denamed, inds_dest) + return nameddims(dest_unnamed, inds_dest) end function Base.copyto!(dest::AbstractITensor, bc::Broadcasted{<:AbstractITensorStyle}) - dest_denamed = denamed(dest) + dest_unnamed = unnamed(dest) inds_dest = inds(dest) - bc_denamed = broadcasted_denamed(bc, inds_dest) - lb = TA.tryflattenlinear(bc_denamed) + bc_unnamed = broadcasted_unnamed(bc, inds_dest) + lb = TA.tryflattenlinear(bc_unnamed) if isnothing(lb) # Not a linear combination: ordinary fused broadcast. - copyto!(dest_denamed, bc_denamed) + copyto!(dest_unnamed, bc_unnamed) else # Linear: lower to bipermutedimsopadd! into the existing dest. - copyto!(dest_denamed, lb) + copyto!(dest_unnamed, lb) end return dest end @@ -221,8 +221,8 @@ end # Reinterpret an operator-style `Broadcasted` under `ITensorStyle`, the broadcast # over the operators' states, so the shared `ITensorStyle` implementation runs (its -# `broadcasted_denamed` already peels each operator operand to its `state` via -# `denamed`). +# `broadcasted_unnamed` already peels each operator operand to its `state` via +# `unnamed`). function statebroadcasted(bc::Broadcasted{<:ITensorOperatorStyle}) return Broadcasted{ITensorStyle{Any}}(bc.f, bc.args, bc.axes) end diff --git a/src/index.jl b/src/index.jl index 18d0ef3..17a9e0e 100644 --- a/src/index.jl +++ b/src/index.jl @@ -125,7 +125,7 @@ function primestring(plev) end function Base.show(io::IO, i::Index) - lenstr = "length=$(denamed(length(i)))" + lenstr = "length=$(length(i))" idstr = "|id=$(shortid(id(i)))" tagsstr = !isempty(tags(i)) ? "|$(tagsstring(tags(i)))" : "" primestr = primestring(plev(i)) diff --git a/src/itensor.jl b/src/itensor.jl index 57ba9f8..a2af537 100644 --- a/src/itensor.jl +++ b/src/itensor.jl @@ -1,30 +1,30 @@ # TODO: Check `allunique(dimnames)`? struct ITensor{DimName} <: AbstractITensor{DimName} - denamed::AbstractArray + unnamed::AbstractArray dimnames::Vector{DimName} end # TODO: Check `allunique(dimnames)`? -function ITensor(denamed::AbstractArray, dims) - ndims(denamed) == length(dims) || +function ITensor(unnamed::AbstractArray, dims) + ndims(unnamed) == length(dims) || throw(ArgumentError("Number of named dims must match ndims.")) dimnames = collect(dims) - return ITensor{eltype(dimnames)}(denamed, dimnames) + return ITensor{eltype(dimnames)}(unnamed, dimnames) end ITensor(a::AbstractITensor, inds) = throw(ArgumentError("Already named.")) -ITensor(a::AbstractITensor) = ITensor(denamed(a), dimnames(a)) +ITensor(a::AbstractITensor) = ITensor(unnamed(a), dimnames(a)) # Minimal interface. The dimnames are stored as (and returned as) a `Vector`. dimnames(a::ITensor) = a.dimnames -denamed(a::ITensor) = a.denamed -Base.parent(a::ITensor) = denamed(a) +unnamed(a::ITensor) = a.unnamed +Base.parent(a::ITensor) = unnamed(a) dimnametype(::Type{<:ITensor{DimName}}) where {DimName} = DimName # The parent array is erased at the field level, so its concrete type is not part # of `ITensor`'s signature. An instance still carries the parent, so the instance # methods recover the concrete type while the type methods report `AbstractArray`. -denamedtype(a::ITensor) = typeof(denamed(a)) -denamedtype(::Type{<:ITensor}) = AbstractArray +unnamedtype(a::ITensor) = typeof(unnamed(a)) +unnamedtype(::Type{<:ITensor}) = AbstractArray parenttype(a::ITensor) = typeof(parent(a)) parenttype(::Type{<:ITensor}) = AbstractArray diff --git a/src/itensoroperator.jl b/src/itensoroperator.jl index c1f0b41..aa6dfd5 100644 --- a/src/itensoroperator.jl +++ b/src/itensoroperator.jl @@ -107,7 +107,7 @@ end state(a::AbstractITensor) = a state(a::ITensorOperator) = a.parent Base.parent(a::ITensorOperator) = state(a) -denamed(a::ITensorOperator) = denamed(state(a)) +unnamed(a::ITensorOperator) = unnamed(state(a)) dimnames(a::ITensorOperator) = dimnames(state(a)) function ITensorOperator(a::AbstractITensor, codomainnames, domainnames) @@ -151,7 +151,7 @@ Base.:*(a::AbstractITensor, b::ITensorOperator) = state(a) * state(b) # `2 .* op`, etc. carry `ITensorOperatorStyle`; `+` / `-` / scalar `*` inherit # preservation since they lower to broadcasting. `copy` / `similar` unwrap each # operator operand to its `state` (the shared `ITensorStyle` machinery does this via -# `denamed`), build the `ITensor` result, then rewrap as an operator using the +# `unnamed`), build the `ITensor` result, then rewrap as an operator using the # codomain/domain split recovered from the operands. function BC.BroadcastStyle(arraytype::Type{<:ITensorOperator}) return ITensorOperatorStyle{ndims(arraytype)}() @@ -217,7 +217,7 @@ end # don't share enough structure to warrant `$($f)`-interpolation. const _gram_eigh_full_operator_docstring = """ - TensorAlgebra.gram_eigh_full(a::ITensorOperator; kwargs...) -> x + TensorAlgebra.MatrixAlgebra.gram_eigh_full(a::ITensorOperator; kwargs...) -> x Gram factorization of a Hermitian positive semi-definite named operator `a`, returning `x` such that `x * x_cod ≈ state(a)`, where `x_cod` is @@ -226,7 +226,7 @@ codomain names of `a`. `x` carries `a`'s domain dimension names and a fresh trailing rank name. The codomain and domain partition is taken from `codomainnames(a)` and `domainnames(a)`. -`kwargs` are forwarded to `TensorAlgebra.gram_eigh_full` on the +`kwargs` are forwarded to `TensorAlgebra.MatrixAlgebra.gram_eigh_full` on the underlying named array (e.g. `atol`, `rtol`). # Examples @@ -234,7 +234,7 @@ underlying named array (e.g. `atol`, `rtol`). ```jldoctest julia> using ITensorBase: namedoneto, operator, replacedimnames, state -julia> using TensorAlgebra: gram_eigh_full +julia> using TensorAlgebra.MatrixAlgebra: gram_eigh_full julia> i, j, k, l, aux = namedoneto.((2, 2, 2, 2, 8), ("i", "j", "k", "l", "aux")); @@ -250,9 +250,9 @@ true """ const _gram_eigh_full_with_pinv_operator_docstring = """ - TensorAlgebra.gram_eigh_full_with_pinv(a::ITensorOperator; kwargs...) -> x, y + TensorAlgebra.MatrixAlgebra.gram_eigh_full_with_pinv(a::ITensorOperator; kwargs...) -> x, y -Like `TensorAlgebra.gram_eigh_full`, but additionally returns a +Like `TensorAlgebra.MatrixAlgebra.gram_eigh_full`, but additionally returns a named array `y` that is a left inverse of `x`: `y * x ≈ I` on the rank subspace (equal to the identity when `a` is full rank). The codomain and domain partition is taken from `codomainnames(a)` and @@ -263,9 +263,9 @@ codomain and domain partition is taken from `codomainnames(a)` and ```jldoctest julia> using LinearAlgebra: I -julia> using ITensorBase: dename, dimnames, namedoneto, operator, replacedimnames +julia> using ITensorBase: unname, dimnames, namedoneto, operator, replacedimnames -julia> using TensorAlgebra: gram_eigh_full_with_pinv +julia> using TensorAlgebra.MatrixAlgebra: gram_eigh_full_with_pinv julia> i, j, k, l, aux = namedoneto.((2, 2, 2, 2, 8), ("i", "j", "k", "l", "aux")); @@ -277,8 +277,8 @@ julia> x, y = gram_eigh_full_with_pinv(a); julia> rname = only(setdiff(dimnames(x), ("j", "l"))); -julia> reshape(dename(y, (rname, "j", "l")), :, 4) * - reshape(dename(x, ("j", "l", rname)), 4, :) ≈ I +julia> reshape(unname(y, (rname, "j", "l")), :, 4) * + reshape(unname(x, ("j", "l", rname)), 4, :) ≈ I true ``` """ @@ -286,8 +286,8 @@ true for f in (:gram_eigh_full, :gram_eigh_full_with_pinv) doc_sym = Symbol("_", f, "_operator_docstring") @eval begin - @doc $doc_sym function TA.$f(a::ITensorOperator; kwargs...) - return TA.$f(state(a), codomainnames(a), domainnames(a); kwargs...) + @doc $doc_sym function MA.$f(a::ITensorOperator; kwargs...) + return MA.$f(state(a), codomainnames(a), domainnames(a); kwargs...) end end end @@ -362,7 +362,7 @@ function similar_operator( end function similar_operator(prototype, ::Type{T}, named_domain_axes) where {T} return similar_operator( - prototype, T, denamed.(named_domain_axes), name.(named_domain_axes) + prototype, T, unnamed.(named_domain_axes), name.(named_domain_axes) ) end function similar_operator(prototype, unnamed_domain_axes, codomain_names, domain_names) diff --git a/src/lazyitensors/evaluation_order.jl b/src/lazyitensors/evaluation_order.jl index e34ec22..40c28c9 100644 --- a/src/lazyitensors/evaluation_order.jl +++ b/src/lazyitensors/evaluation_order.jl @@ -16,16 +16,16 @@ end function time_complexity( ::typeof(*), t1::AbstractITensor, t2::AbstractITensor ) - return prod(length ∘ denamed, (inds(t1) ∪ inds(t2))) + return prod(length, (inds(t1) ∪ inds(t2))) end function time_complexity( ::typeof(+), t1::AbstractITensor, t2::AbstractITensor ) @assert issetequal(dimnames(t1), dimnames(t2)) - return prod(denamed, size(t1)) + return prod(size(t1)) end function time_complexity(::typeof(*), c::Number, t::AbstractITensor) - return prod(denamed, size(t)) + return prod(size(t)) end function time_complexity(::typeof(*), t::AbstractITensor, c::Number) return time_complexity(*, c, t) diff --git a/src/lazyitensors/itensorbaseextensions.jl b/src/lazyitensors/itensorbaseextensions.jl index 34886d0..b31c656 100644 --- a/src/lazyitensors/itensorbaseextensions.jl +++ b/src/lazyitensors/itensorbaseextensions.jl @@ -4,7 +4,7 @@ # independent of the order of dimensions. function _hash(a::ITensor, h::UInt64) h = hash(:ITensor, h) - h = hash(denamed(a), h) + h = hash(unnamed(a), h) for i in inds(a) h = hash(i, h) end diff --git a/src/lazyitensors/lazyinterface.jl b/src/lazyitensors/lazyinterface.jl index 111ca18..ed56db8 100644 --- a/src/lazyitensors/lazyinterface.jl +++ b/src/lazyitensors/lazyinterface.jl @@ -203,10 +203,10 @@ function inds_lazy(a) return error("Variant not supported.") end end -function denamed_lazy(a) +function unnamed_lazy(a) u = unwrap(a) if !iscall(u) - return denamed(u) + return unnamed(u) else return error("Variant not supported.") end diff --git a/src/lazyitensors/lazyitensor.jl b/src/lazyitensors/lazyitensor.jl index c440bef..274c088 100644 --- a/src/lazyitensors/lazyitensor.jl +++ b/src/lazyitensors/lazyitensor.jl @@ -22,7 +22,7 @@ lazy(a::Mul{<:LazyITensor}) = LazyITensor(a) dimnames(a::LazyITensor) = dimnames_lazy(a) inds(a::LazyITensor) = inds_lazy(a) -denamed(a::LazyITensor) = denamed_lazy(a) +unnamed(a::LazyITensor) = unnamed_lazy(a) # Broadcasting function Base.BroadcastStyle(::Type{<:LazyITensor}) diff --git a/src/lazyitensors/symbolicitensor.jl b/src/lazyitensors/symbolicitensor.jl index 1dff729..d987c54 100644 --- a/src/lazyitensors/symbolicitensor.jl +++ b/src/lazyitensors/symbolicitensor.jl @@ -1,4 +1,4 @@ -# Expression leaf with no array payload, so it defines no `denamed`/`getindex`. +# 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 # `dimnames` and the index `size`s (the cost model uses lengths). `inds` is @@ -13,7 +13,7 @@ end function SymbolicITensor(symname, inds) dnames = collect(name.(inds)) DimName = isempty(inds) ? typeof(symname) : eltype(dnames) - sizes = Int[length(denamed(i)) for i in inds] + sizes = Int[length(i) for i in inds] return SymbolicITensor{DimName, typeof(symname)}(symname, sizes, dnames) end diff --git a/src/linearalgebra.jl b/src/linearalgebra.jl index 7584e5f..f20aa8e 100644 --- a/src/linearalgebra.jl +++ b/src/linearalgebra.jl @@ -7,7 +7,7 @@ using LinearAlgebra: LinearAlgebra as LA # This implicitly helps with defining `LA.normalize[!]` as well (though note that # uses `LinearAlgebra.rmul!` as well). function LA.norm(a::AbstractITensor, p::Real = 2; kwargs...) - return LA.norm(denamed(a), p; kwargs...) + return LA.norm(unnamed(a), p; kwargs...) end # We overload these because the LinearAlgebra.jl AbstractArray definitions of `rmul!`, @@ -19,11 +19,11 @@ for f! in [:mul!, :div!] rf! = Symbol(:r, f!) @eval begin function LA.$rf!(a::AbstractITensor, α::Number) - LA.$rf!(denamed(a), α) + LA.$rf!(unnamed(a), α) return a end function LA.$lf!(α::Number, a::AbstractITensor) - LA.$lf!(α, denamed(a)) + LA.$lf!(α, unnamed(a)) return a end end diff --git a/src/named.jl b/src/named.jl index 6d2f2e7..9d4593c 100644 --- a/src/named.jl +++ b/src/named.jl @@ -4,18 +4,18 @@ # named/unnamed arithmetic and operations like `i1 * i2` are not cleanly definable # under the numeric contract, and inherited fallbacks risk silently dropping the # name. So it supplies the integer-like surface it needs directly. -struct Named{Name, Denamed} - value::Denamed +struct Named{Name, Unnamed} + value::Unnamed name::Name end # A named integer is just the integer case of `Named`. The alias gives it a # readable name for dispatch (`NamedInteger`, `NamedInteger{IndexName}`, ...) # without being a separate type. -const NamedInteger{Name, Denamed <: Integer} = Named{Name, Denamed} +const NamedInteger{Name, Unnamed <: Integer} = Named{Name, Unnamed} # Minimal interface. -denamed(i::Named) = i.value +unnamed(i::Named) = i.value name(i::Named) = i.name # Shorthand. Attaching a name to a scalar produces a `Named`; arrays and unit @@ -23,59 +23,59 @@ name(i::Named) = i.name named(value, name) = Named(value, name) # Derived interface. -setname(i::Named, name) = named(denamed(i), name) +setname(i::Named, name) = named(unnamed(i), name) setvalue(i::Named, value) = named(value, name(i)) -denamedtype(::Type{<:Named{<:Any, Denamed}}) where {Denamed} = Denamed +unnamedtype(::Type{<:Named{<:Any, Unnamed}}) where {Unnamed} = Unnamed nametype(::Type{<:Named{Name}}) where {Name} = Name # Traits. isnamed(::Type{<:Named}) = true function Base.:(==)(i1::Named, i2::Named) - return name(i1) == name(i2) && denamed(i1) == denamed(i2) + return name(i1) == name(i2) && unnamed(i1) == unnamed(i2) end -# Hash under a literal tag plus the denamed value and name. The tag is shared by an +# Hash under a literal tag plus the unnamed value and name. The tag is shared by an # entire equality class (one for the scalar `Named`, one for all `AbstractNamedArray` # types), not per concrete type, so `a == b => hash(a) == hash(b)` holds the way it # does in Base (`[1, 2, 3] == 1:3` and they hash equally). function hash_named(typetag::Symbol, x, h::UInt) h = hash(typetag, h) - h = hash(denamed(x), h) + h = hash(unnamed(x), h) return hash(name(x), h) end Base.hash(i::Named, h::UInt) = hash_named(:Named, i, h) function uniquename(rng::AbstractRNG, i::Named) - return named(denamed(i), uniquename(name(i))) + return named(unnamed(i), uniquename(name(i))) end function Base.string(i::Named; kwargs...) - return "named($(string(denamed(i); kwargs...)), $(repr(name(i))))" + return "named($(string(unnamed(i); kwargs...)), $(repr(name(i))))" end function Base.show(io::IO, i::Named) - print(io, "named(", denamed(i), ", ", repr(name(i)), ")") + print(io, "named(", unnamed(i), ", ", repr(name(i)), ")") return nothing end # Integer interface, for the named-integer case `NamedInteger`. -Base.:-(i::NamedInteger) = setvalue(i, -denamed(i)) +Base.:-(i::NamedInteger) = setvalue(i, -unnamed(i)) ## TODO: Support this, we need to define `NamedFloat`, `NamedReal`, `NamedNumber`, etc. ## This is used in `LinearAlgebra.norm`, for now we just overload that directly. ## Here, named numbers are treated as unitful, so multiplying them -## with denamed numbers means the result inherits the name. +## with unnamed numbers means the result inherits the name. ## function Base.:*(i1::NamedInteger, i2::Number) -## return named(denamed(i1) * i2, name(i1)) +## return named(unnamed(i1) * i2, name(i1)) ## end -Base.zero(i::NamedInteger) = setvalue(i, zero(denamed(i))) -Base.one(i::NamedInteger) = setvalue(i, one(denamed(i))) -Base.signbit(i::NamedInteger) = signbit(denamed(i)) -Base.unsigned(i::NamedInteger) = setvalue(i, unsigned(denamed(i))) +Base.zero(i::NamedInteger) = setvalue(i, zero(unnamed(i))) +Base.one(i::NamedInteger) = setvalue(i, one(unnamed(i))) +Base.signbit(i::NamedInteger) = signbit(unnamed(i)) +Base.unsigned(i::NamedInteger) = setvalue(i, unsigned(unnamed(i))) # Used in bounds checking when indexing with named dimensions. function Base.:<(i1::NamedInteger, i2::NamedInteger) name(i1) == name(i2) || throw(NameMismatch("Mismatched names $(name(i1)), $(name(i2))")) - return denamed(i1) < denamed(i2) + return unnamed(i1) < unnamed(i2) end diff --git a/src/namedarray.jl b/src/namedarray.jl index 400b911..8b9874d 100644 --- a/src/namedarray.jl +++ b/src/namedarray.jl @@ -1,10 +1,10 @@ -struct NamedArray{Name, DenamedT, N, Denamed <: AbstractArray{DenamedT, N}} <: - AbstractNamedArray{Name, DenamedT, N} - value::Denamed +struct NamedArray{Name, UnnamedT, N, Unnamed <: AbstractArray{UnnamedT, N}} <: + AbstractNamedArray{Name, UnnamedT, N} + value::Unnamed name::Name end # Minimal interface. -denamed(a::NamedArray) = a.value +unnamed(a::NamedArray) = a.value name(a::NamedArray) = a.name -denamedtype(::Type{<:NamedArray{<:Any, <:Any, <:Any, Denamed}}) where {Denamed} = Denamed +unnamedtype(::Type{<:NamedArray{<:Any, <:Any, <:Any, Unnamed}}) where {Unnamed} = Unnamed diff --git a/src/namedunitrange.jl b/src/namedunitrange.jl index 41b5604..64c993c 100644 --- a/src/namedunitrange.jl +++ b/src/namedunitrange.jl @@ -1,13 +1,13 @@ -struct NamedUnitRange{Name, DenamedT <: Integer, Denamed <: AbstractUnitRange{DenamedT}} <: - AbstractNamedVector{Name, DenamedT} - value::Denamed +struct NamedUnitRange{Name, UnnamedT <: Integer, Unnamed <: AbstractUnitRange{UnnamedT}} <: + AbstractNamedVector{Name, UnnamedT} + value::Unnamed name::Name end # Minimal interface. -denamed(i::NamedUnitRange) = i.value +unnamed(i::NamedUnitRange) = i.value name(i::NamedUnitRange) = i.name -denamedtype(::Type{<:NamedUnitRange{<:Any, <:Any, Denamed}}) where {Denamed} = Denamed +unnamedtype(::Type{<:NamedUnitRange{<:Any, <:Any, Unnamed}}) where {Unnamed} = Unnamed # Construct from a range or length, minting a fresh name of the requested flavor. # Generic over the name type via `uniquename`, so `Index(3)` (with `Index` a @@ -27,23 +27,23 @@ named(r::AbstractUnitRange, name) = namedunitrange(r, name) # Derived interface. `setname` differs from the `AbstractNamedArray` method: it # rebuilds through `named` so the result stays a named unit range, not a named -# array. The rest of the named interface (`==`, `hash`, `isnamed`, `denamedtype`, +# array. The rest of the named interface (`==`, `hash`, `isnamed`, `unnamedtype`, # `nametype`, `uniquename`, `show`, `isempty`) is inherited from `AbstractNamedArray`. # TODO: Use `Accessors.@set`? -setname(r::NamedUnitRange, name) = named(denamed(r), name) +setname(r::NamedUnitRange, name) = named(unnamed(r), name) # Forward `conj` to the underlying range so graded axes flip their sector # arrows. The `Base.conj(::AbstractArray{<:Real}) = x` fallback would # otherwise short-circuit before the inner range is touched. -Base.conj(r::NamedUnitRange) = named(conj(denamed(r)), name(r)) +Base.conj(r::NamedUnitRange) = named(conj(unnamed(r)), name(r)) # Unit range functionality. -Base.first(r::NamedUnitRange) = named(first(denamed(r)), name(r)) -Base.last(r::NamedUnitRange) = named(last(denamed(r)), name(r)) -# `length` is inherited from the `AbstractNamedArray` generic (identical definition). -Base.size(r::NamedUnitRange) = (named(length(denamed(r)), name(r)),) -Base.axes(r::NamedUnitRange) = (named(only(axes(denamed(r))), name(r)),) -Base.step(r::NamedUnitRange) = named(step(denamed(r)), name(r)) +Base.first(r::NamedUnitRange) = named(first(unnamed(r)), name(r)) +Base.last(r::NamedUnitRange) = named(last(unnamed(r)), name(r)) +# `length`, `size`, and `axes` are inherited from the `AbstractNamedArray` generic: +# the count and the positional axes are plain (unnamed). The element-layer methods +# (`first`, `last`, `step`, indexing, iteration) stay named. +Base.step(r::NamedUnitRange) = named(step(unnamed(r)), name(r)) Base.getindex(r::NamedUnitRange, I::Int) = getindex_named(r, I) # Fix ambiguity error. function Base.getindex(r::NamedUnitRange, I::AbstractUnitRange{<:Integer}) @@ -60,38 +60,38 @@ end # returned named indices. function Base.getindex(r::NamedUnitRange, I::NamedInteger) @assert name(r) == name(I) - return getindex_named(r, denamed(I)) + return getindex_named(r, unnamed(I)) end # Named ranges are not `AbstractUnitRange`s, so `CartesianIndices` over a tuple of -# them has no Base method; dename to the parent ranges so `CartesianIndices` of a +# them has no Base method; unname to the parent ranges so `CartesianIndices` of a # named tensor matches the parent's. function Base.CartesianIndices( rs::Tuple{NamedUnitRange, Vararg{NamedUnitRange}} ) - return CartesianIndices(denamed.(rs)) + return CartesianIndices(unnamed.(rs)) end # Show compactly; the inherited `AbstractNamedArray` text/plain show is multiline. Base.show(io::IO, ::MIME"text/plain", r::NamedUnitRange) = show(io, r) function Base.AbstractUnitRange{Int}(r::NamedUnitRange) - return AbstractUnitRange{Int}(denamed(r)) + return AbstractUnitRange{Int}(unnamed(r)) end -Base.oneto(length::NamedInteger) = named(Base.OneTo(denamed(length)), name(length)) +Base.oneto(length::NamedInteger) = named(Base.OneTo(unnamed(length)), name(length)) namedoneto(length::Integer, name) = Base.oneto(named(length, name)) Base.iterate(r::NamedUnitRange) = isempty(r) ? nothing : (first(r), first(r)) function Base.iterate(r::NamedUnitRange, i) i == last(r) && return nothing - next = named(denamed(i) + denamed(step(r)), name(r)) + next = named(unnamed(i) + unnamed(step(r)), name(r)) return (next, next) end struct NamedColon{Name} <: Function name::Name end -denamed(c::NamedColon) = Colon() +unnamed(c::NamedColon) = Colon() name(c::NamedColon) = c.name named(::Colon, name) = NamedColon(name) @@ -99,13 +99,13 @@ struct FirstIndex{Arr, Dim} array::Arr dim::Dim end -Base.to_index(i::FirstIndex) = denamed(first(axes(i.array, i.dim))) +Base.to_index(i::FirstIndex) = unnamed(first(axes(i.array, i.dim))) struct LastIndex{Arr, Dim} array::Arr dim::Dim end -Base.to_index(i::LastIndex) = denamed(last(axes(i.array, i.dim))) +Base.to_index(i::LastIndex) = unnamed(last(axes(i.array, i.dim))) function Base.getindex(r::NamedUnitRange, I::FirstIndex) return first(r) diff --git a/src/tensoralgebra.jl b/src/tensoralgebra.jl index b6ddd96..689e7b2 100644 --- a/src/tensoralgebra.jl +++ b/src/tensoralgebra.jl @@ -1,4 +1,6 @@ using LinearAlgebra: LinearAlgebra as LA +using MatrixAlgebraKit: MatrixAlgebraKit as MAK +using TensorAlgebra.MatrixAlgebra: MatrixAlgebra as MA using TensorAlgebra: TensorAlgebra as TA using TupleTools: TupleTools @@ -8,7 +10,7 @@ dimnames_setdiff(s1, s2) = setdiff(s1, s2) Base.:*(a1::AbstractITensor, a2::AbstractITensor) = mul_nameddims(a1, a2) function mul_nameddims(a1::AbstractITensor, a2::AbstractITensor) a_dest, dimnames_dest = TA.contract( - denamed(a1), dimnames(a1), denamed(a2), dimnames(a2) + unnamed(a1), dimnames(a1), unnamed(a2), dimnames(a2) ) return nameddims(a_dest, dimnames_dest) end @@ -46,9 +48,9 @@ function mul!_nameddims( α::Number, β::Number ) TA.contractadd!( - denamed(a_dest), dimnames(a_dest), - denamed(a1), dimnames(a1), - denamed(a2), dimnames(a2), + unnamed(a_dest), dimnames(a_dest), + unnamed(a1), dimnames(a1), + unnamed(a2), dimnames(a2), α, β ) return a_dest @@ -65,9 +67,9 @@ function mul!_nameddims( a1::AbstractITensor, a2::AbstractITensor ) TA.contract!( - denamed(a_dest), dimnames(a_dest), - denamed(a1), dimnames(a1), - denamed(a2), dimnames(a2) + unnamed(a_dest), dimnames(a_dest), + unnamed(a1), dimnames(a1), + unnamed(a2), dimnames(a2) ) return a_dest end @@ -106,7 +108,7 @@ function matricize_nameddims(na::AbstractITensor, fusions::Vararg{Pair, 2}) ) end perm = TA.blockedperm(na, dimnames_fuse...) - a_fused = TA.matricize(denamed(na), perm) + a_fused = TA.matricize(unnamed(na), perm) return nameddims(a_fused, dimnames_fused) end @@ -116,14 +118,14 @@ end function unmatricize_nameddims(na::AbstractITensor, splitters::Vararg{Pair, 2}) splitters = name.(first.(splitters)) .=> last.(splitters) split_namedlengths = last.(splitters) - splitters_denamed = map(splitters) do splitter + splitters_unnamed = map(splitters) do splitter fused_name, split_namedlengths = splitter fused_dim = findfirst(isequal(fused_name), dimnames(na)) - split_lengths = denamed.(split_namedlengths) + split_lengths = unnamed.(split_namedlengths) return fused_dim => split_lengths end - blocked_axes = last.(TupleTools.sort(splitters_denamed; by = first)) - a_split = TA.unmatricize(denamed(na), blocked_axes...) + blocked_axes = last.(TupleTools.sort(splitters_unnamed; by = first)) + a_split = TA.unmatricize(unnamed(na), blocked_axes...) names_split = Any[tuple.(dimnames(na))...] for splitter in splitters fused_name, split_namedlengths = splitter @@ -136,12 +138,12 @@ function unmatricize_nameddims(na::AbstractITensor, splitters::Vararg{Pair, 2}) end for f in [ - :left_orth, :left_polar, :lq, :orth, :polar, :qr, :right_orth, - :right_polar, + :left_orth, :left_polar, :lq_compact, :lq_full, :qr_compact, :qr_full, + :right_orth, :right_polar, ] f_nameddims = Symbol(f, "_nameddims") @eval begin - function TA.$f( + function MAK.$f( a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... ) return $f_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) @@ -151,87 +153,85 @@ for f in [ ) codomain = name.(dimnames_codomain) domain = name.(dimnames_domain) - x_denamed, y_denamed = - TA.$f(denamed(a), dimnames(a), codomain, domain; kwargs...) + x_unnamed, y_unnamed = + TA.$f(unnamed(a), dimnames(a), codomain, domain; kwargs...) name_x = uniquename(dimnames(a, 1)) name_y = name_x dimnames_x = (codomain..., name_x) dimnames_y = (name_y, domain...) - x = nameddims(x_denamed, dimnames_x) - y = nameddims(y_denamed, dimnames_y) + x = nameddims(x_unnamed, dimnames_x) + y = nameddims(y_unnamed, dimnames_y) return x, y end - function TA.$f(a::AbstractITensor, dimnames_codomain; kwargs...) + function MAK.$f(a::AbstractITensor, dimnames_codomain; kwargs...) return $f_nameddims(a, dimnames_codomain; kwargs...) end function $f_nameddims(a::AbstractITensor, dimnames_codomain; kwargs...) codomain = name.(dimnames_codomain) domain = dimnames_setdiff(dimnames(a), codomain) - return TA.$f(a, codomain, domain; kwargs...) + return MAK.$f(a, codomain, domain; kwargs...) end end end -# Overload LinearAlgebra functions where relevant. -function LA.qr(a::AbstractITensor, args...; kwargs...) - return TA.qr(a, args...; kwargs...) -end -function LA.lq(a::AbstractITensor, args...; kwargs...) - return TA.lq(a, args...; kwargs...) -end - # -# Non-binary factorizations. +# SVD (three-output). # -function TA.svd( - a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... - ) - return svd_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) -end -function svd_nameddims( - a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... - ) - codomain = name.(dimnames_codomain) - domain = name.(dimnames_domain) - u_denamed, s_denamed, v_denamed = TA.svd( - denamed(a), dimnames(a), codomain, domain; kwargs... - ) - name_u = uniquename(dimnames(a, 1)) - name_v = uniquename(dimnames(a, 1)) - dimnames_u = (codomain..., name_u) - dimnames_s = (name_u, name_v) - dimnames_v = (name_v, domain...) - u = nameddims(u_denamed, dimnames_u) - s = nameddims(s_denamed, dimnames_s) - v = nameddims(v_denamed, dimnames_v) - return u, s, v -end -function TA.svd(a::AbstractITensor, dimnames_codomain; kwargs...) - return svd_nameddims(a, dimnames_codomain; kwargs...) -end -function svd_nameddims(a::AbstractITensor, dimnames_codomain; kwargs...) - return TA.svd( - a, - dimnames_codomain, - dimnames_setdiff(dimnames(a), name.(dimnames_codomain)); - kwargs... - ) -end -function LA.svd(a::AbstractITensor, args...; kwargs...) - return TA.svd(a, args...; kwargs...) +for f in [:svd_compact, :svd_full, :svd_trunc] + f_nameddims = Symbol(f, "_nameddims") + @eval begin + function MAK.$f( + a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... + ) + return $f_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) + end + function $f_nameddims( + a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... + ) + codomain = name.(dimnames_codomain) + domain = name.(dimnames_domain) + u_unnamed, s_unnamed, v_unnamed = TA.$f( + unnamed(a), dimnames(a), codomain, domain; kwargs... + ) + name_u = uniquename(dimnames(a, 1)) + name_v = uniquename(dimnames(a, 1)) + dimnames_u = (codomain..., name_u) + dimnames_s = (name_u, name_v) + dimnames_v = (name_v, domain...) + u = nameddims(u_unnamed, dimnames_u) + s = nameddims(s_unnamed, dimnames_s) + v = nameddims(v_unnamed, dimnames_v) + return u, s, v + end + function MAK.$f(a::AbstractITensor, dimnames_codomain; kwargs...) + return $f_nameddims(a, dimnames_codomain; kwargs...) + end + function $f_nameddims(a::AbstractITensor, dimnames_codomain; kwargs...) + return MAK.$f( + a, + dimnames_codomain, + dimnames_setdiff(dimnames(a), name.(dimnames_codomain)); + kwargs... + ) + end + end end -function TA.svdvals( +# +# Singular values. +# + +function MAK.svd_vals( a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... ) - return svdvals_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) + return svd_vals_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) end -function svdvals_nameddims( +function svd_vals_nameddims( a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... ) - return TA.svdvals( - denamed(a), + return TA.svd_vals( + unnamed(a), dimnames(a), name.(dimnames_codomain), name.(dimnames_domain); @@ -239,62 +239,70 @@ function svdvals_nameddims( ) end -function TA.svdvals(a::AbstractITensor, dimnames_codomain; kwargs...) - return svdvals_nameddims(a, dimnames_codomain; kwargs...) +function MAK.svd_vals(a::AbstractITensor, dimnames_codomain; kwargs...) + return svd_vals_nameddims(a, dimnames_codomain; kwargs...) end -function svdvals_nameddims(a::AbstractITensor, dimnames_codomain; kwargs...) +function svd_vals_nameddims(a::AbstractITensor, dimnames_codomain; kwargs...) codomain = name.(dimnames_codomain) domain = dimnames_setdiff(dimnames(a), codomain) - return TA.svdvals(a, codomain, domain; kwargs...) -end - -function LA.svdvals(a::AbstractITensor, args...; kwargs...) - return TA.svdvals(a, args...; kwargs...) + return MAK.svd_vals(a, codomain, domain; kwargs...) end -function TA.eigen( - a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... - ) - return eigen_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) -end -function eigen_nameddims( - a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... - ) - codomain = name.(dimnames_codomain) - domain = name.(dimnames_domain) - d_denamed, v_denamed = TA.eigen(denamed(a), dimnames(a), codomain, domain; kwargs...) - name_d = uniquename(dimnames(a, 1)) - name_d′ = uniquename(name_d) - name_v = name_d - dimnames_d = (name_d′, name_d) - dimnames_v = (domain..., name_v) - d = nameddims(d_denamed, dimnames_d) - v = nameddims(v_denamed, dimnames_v) - return d, v -end +# +# Eigendecomposition (two-output). +# -function LA.eigen(a::AbstractITensor, args...; kwargs...) - return TA.eigen(a, args...; kwargs...) +for f in [:eigh_full, :eig_full, :eigh_trunc, :eig_trunc] + f_nameddims = Symbol(f, "_nameddims") + @eval begin + function MAK.$f( + a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... + ) + return $f_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) + end + function $f_nameddims( + a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... + ) + codomain = name.(dimnames_codomain) + domain = name.(dimnames_domain) + d_unnamed, v_unnamed = TA.$f( + unnamed(a), dimnames(a), codomain, domain; kwargs... + ) + name_d = uniquename(dimnames(a, 1)) + name_d′ = uniquename(name_d) + name_v = name_d + dimnames_d = (name_d′, name_d) + dimnames_v = (domain..., name_v) + d = nameddims(d_unnamed, dimnames_d) + v = nameddims(v_unnamed, dimnames_v) + return d, v + end + end end -function TA.eigvals( - a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... - ) - return eigvals_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) -end -function eigvals_nameddims( - a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... - ) - codomain = name.(dimnames_codomain) - domain = name.(dimnames_domain) - return TA.eigvals(denamed(a), dimnames(a), codomain, domain; kwargs...) -end +# +# Eigenvalues. +# -function LA.eigvals(a::AbstractITensor, args...; kwargs...) - return TA.eigvals(a, args...; kwargs...) +for f in [:eigh_vals, :eig_vals] + f_nameddims = Symbol(f, "_nameddims") + @eval begin + function MAK.$f( + a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... + ) + return $f_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) + end + function $f_nameddims( + a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... + ) + codomain = name.(dimnames_codomain) + domain = name.(dimnames_domain) + return TA.$f(unnamed(a), dimnames(a), codomain, domain; kwargs...) + end + end end -function TA.left_null( +function MAK.left_null( a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... ) return left_null_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) @@ -304,22 +312,22 @@ function left_null_nameddims( ) codomain = name.(dimnames_codomain) domain = name.(dimnames_domain) - n_denamed = TA.left_null(denamed(a), dimnames(a), codomain, domain; kwargs...) + n_unnamed = TA.left_null(unnamed(a), dimnames(a), codomain, domain; kwargs...) name_n = uniquename(dimnames(a, 1)) dimnames_n = (codomain..., name_n) - return nameddims(n_denamed, dimnames_n) + return nameddims(n_unnamed, dimnames_n) end -function TA.left_null(a::AbstractITensor, dimnames_codomain; kwargs...) +function MAK.left_null(a::AbstractITensor, dimnames_codomain; kwargs...) return left_null_nameddims(a, dimnames_codomain; kwargs...) end function left_null_nameddims(a::AbstractITensor, dimnames_codomain; kwargs...) codomain = name.(dimnames_codomain) domain = dimnames_setdiff(dimnames(a), codomain) - return TA.left_null(a, codomain, domain; kwargs...) + return MAK.left_null(a, codomain, domain; kwargs...) end -function TA.right_null( +function MAK.right_null( a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... ) return right_null_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) @@ -329,23 +337,23 @@ function right_null_nameddims( ) codomain = name.(dimnames_codomain) domain = name.(dimnames_domain) - n_denamed = TA.right_null(denamed(a), dimnames(a), codomain, domain; kwargs...) + n_unnamed = TA.right_null(unnamed(a), dimnames(a), codomain, domain; kwargs...) name_n = uniquename(dimnames(a, 1)) dimnames_n = (name_n, domain...) - return nameddims(n_denamed, dimnames_n) + return nameddims(n_unnamed, dimnames_n) end -function TA.right_null(a::AbstractITensor, dimnames_codomain; kwargs...) +function MAK.right_null(a::AbstractITensor, dimnames_codomain; kwargs...) return right_null_nameddims(a, dimnames_codomain; kwargs...) end function right_null_nameddims(a::AbstractITensor, dimnames_codomain; kwargs...) codomain = name.(dimnames_codomain) domain = dimnames_setdiff(dimnames(a), codomain) - return TA.right_null(a, codomain, domain; kwargs...) + return MAK.right_null(a, codomain, domain; kwargs...) end """ - TensorAlgebra.gram_eigh_full(a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs...) -> x + TensorAlgebra.MatrixAlgebra.gram_eigh_full(a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs...) -> x Gram factorization of a Hermitian positive semi-definite named array `a`, returning `x` such that `a ≈ x * x_cod`, where `x_cod` is `conj(x)` with @@ -362,7 +370,7 @@ unnamed array (e.g. `atol`, `rtol`). ```jldoctest julia> using ITensorBase: dimnames, namedoneto, replacedimnames -julia> using TensorAlgebra: gram_eigh_full +julia> using TensorAlgebra.MatrixAlgebra: gram_eigh_full julia> i, j, k, l, aux = namedoneto.((2, 2, 2, 2, 8), ("i", "j", "k", "l", "aux")); @@ -376,7 +384,7 @@ julia> replacedimnames(x, "j" => "i", "l" => "k") * conj(x) ≈ a true ``` """ -function TA.gram_eigh_full( +function MA.gram_eigh_full( a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... ) return gram_eigh_full_nameddims(a, dimnames_codomain, dimnames_domain; kwargs...) @@ -386,16 +394,16 @@ function gram_eigh_full_nameddims( ) codomain = name.(dimnames_codomain) domain = name.(dimnames_domain) - x_denamed = TA.gram_eigh_full(denamed(a), dimnames(a), codomain, domain; kwargs...) + x_unnamed = TA.gram_eigh_full(unnamed(a), dimnames(a), codomain, domain; kwargs...) name_x = uniquename(dimnames(a, 1)) dimnames_x = (domain..., name_x) - return nameddims(x_denamed, dimnames_x) + return nameddims(x_unnamed, dimnames_x) end """ - TensorAlgebra.gram_eigh_full_with_pinv(a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs...) -> x, y + TensorAlgebra.MatrixAlgebra.gram_eigh_full_with_pinv(a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs...) -> x, y -Like `TensorAlgebra.gram_eigh_full`, but additionally returns a +Like `TensorAlgebra.MatrixAlgebra.gram_eigh_full`, but additionally returns a named array `y` that is a left inverse of `x`: `y * x ≈ I` on the rank subspace (equal to the identity when `a` is full rank). `x` has the rank-name last, `y` has it first, both sharing the domain dimension @@ -406,9 +414,9 @@ names of `a`. ```jldoctest julia> using LinearAlgebra: I -julia> using ITensorBase: dename, dimnames, namedoneto, replacedimnames +julia> using ITensorBase: unname, dimnames, namedoneto, replacedimnames -julia> using TensorAlgebra: gram_eigh_full_with_pinv +julia> using TensorAlgebra.MatrixAlgebra: gram_eigh_full_with_pinv julia> i, j, k, l, aux = namedoneto.((2, 2, 2, 2, 8), ("i", "j", "k", "l", "aux")); @@ -423,12 +431,12 @@ true julia> rname = only(setdiff(dimnames(x), ("j", "l"))); -julia> reshape(dename(y, (rname, "j", "l")), :, 4) * - reshape(dename(x, ("j", "l", rname)), 4, :) ≈ I +julia> reshape(unname(y, (rname, "j", "l")), :, 4) * + reshape(unname(x, ("j", "l", rname)), 4, :) ≈ I true ``` """ -function TA.gram_eigh_full_with_pinv( +function MA.gram_eigh_full_with_pinv( a::AbstractITensor, dimnames_codomain, dimnames_domain; kwargs... ) return gram_eigh_full_with_pinv_nameddims( @@ -440,13 +448,13 @@ function gram_eigh_full_with_pinv_nameddims( ) codomain = name.(dimnames_codomain) domain = name.(dimnames_domain) - x_denamed, y_denamed = TA.gram_eigh_full_with_pinv( - denamed(a), dimnames(a), codomain, domain; kwargs... + x_unnamed, y_unnamed = TA.gram_eigh_full_with_pinv( + unnamed(a), dimnames(a), codomain, domain; kwargs... ) name_xy = uniquename(dimnames(a, 1)) dimnames_x = (domain..., name_xy) dimnames_y = (name_xy, domain...) - return nameddims(x_denamed, dimnames_x), nameddims(y_denamed, dimnames_y) + return nameddims(x_unnamed, dimnames_x), nameddims(y_unnamed, dimnames_y) end """ @@ -487,7 +495,7 @@ function one_nameddims( ) codomain = name.(dimnames_codomain) domain = name.(dimnames_domain) - raw = TA.one(denamed(a), dimnames(a), codomain, domain) + raw = TA.one(unnamed(a), dimnames(a), codomain, domain) return nameddims(raw, (codomain..., domain...)) end @@ -512,10 +520,10 @@ for f in MATRIX_FUNCTIONS ) codomain = name.(dimnames_codomain) domain = name.(dimnames_domain) - fa_denamed = TA.$f( - denamed(a), dimnames(a), codomain, domain; kwargs... + fa_unnamed = TA.$f( + unnamed(a), dimnames(a), codomain, domain; kwargs... ) - return nameddims(fa_denamed, (codomain..., domain...)) + return nameddims(fa_unnamed, (codomain..., domain...)) end end end diff --git a/test/Project.toml b/test/Project.toml index 6088dc5..5186c3e 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -8,6 +8,7 @@ ITensorBase = "4795dd04-0d67-49bb-8f44-b89c448a1dc7" ITensorPkgSkeleton = "3d388ab1-018a-49f4-ae50-18094d5f71ea" JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +MatrixAlgebraKit = "6c742aac-3347-4629-af66-fc926824e5e4" Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" @@ -30,16 +31,17 @@ Adapt = "4" Aqua = "0.8.9" BlockArrays = "1" Combinatorics = "1" -ITensorBase = "0.6" +ITensorBase = "0.7" 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" Random = "1.10" SafeTestsets = "0.1" StableRNGs = "1" Suppressor = "0.2" -TensorAlgebra = "0.9.5" +TensorAlgebra = "0.10" TensorOperations = "5.3.1" TermInterface = "2" Test = "1.10" diff --git a/test/test_basics.jl b/test/test_basics.jl index c954046..587fd22 100644 --- a/test/test_basics.jl +++ b/test/test_basics.jl @@ -1,5 +1,5 @@ -using ITensorBase: ITensorBase, ITensor, Index, IndexName, dename, denamed, dimnametype, - gettag, hastag, id, inds, mapinds, name, named, plev, prime, setplev, settag, tags, +using ITensorBase: ITensorBase, ITensor, Index, IndexName, dimnametype, gettag, hastag, id, + inds, mapinds, name, named, plev, prime, setplev, settag, tags, unname, unnamed, unsettag using Test: @test, @test_broken, @test_throws, @testset using UUIDs: UUID @@ -52,14 +52,14 @@ using UUIDs: UUID @test !hastag(i, "Y") i = Index(Base.OneTo(2)) - @test length(i) == named(2, name(i)) - @test denamed(length(i)) == 2 - @test denamed(i) == 1:2 + @test length(i) == 2 + @test length(i) isa Int + @test unnamed(i) == 1:2 @test plev(i) == 0 @test length(tags(i)) == 0 i = settag(Index(2), "X", "Y") - @test denamed(length(i)) == 2 + @test length(i) == 2 @test hastag(i, "X") @test gettag(i, "X") == "Y" @test plev(i) == 0 @@ -70,12 +70,12 @@ using UUIDs: UUID i, j = Index.((2, 2)) x = randn(elt, 2, 2) a = x[i, j] - @test denamed(a) == x + @test unnamed(a) == x @test plev(i) == 0 @test plev(prime(i)) == 1 @test length(tags(i)) == 0 a′ = mapinds(prime, a) - @test denamed(a′) == x + @test unnamed(a′) == x @test issetequal(inds(a′), (prime(i), prime(j))) # The number of dimnames must match the array's `ndims`, and the dimnames are @@ -88,14 +88,14 @@ using UUIDs: UUID a′ = Array(a) @test eltype(a′) === elt @test a′ isa Matrix{elt} - @test a′ == denamed(a) + @test a′ == unnamed(a) i, j = Index.((3, 4)) a = randn(elt, i, j) for a′ in (Array{Float32}(a), Matrix{Float32}(a)) @test eltype(a′) === Float32 @test a′ isa Matrix{Float32} - @test a′ == Float32.(denamed(a)) + @test a′ == Float32.(unnamed(a)) end i, j, k = Index.((2, 2, 2)) @@ -103,8 +103,8 @@ using UUIDs: UUID b = randn(elt, k, i, j) copyto!(a, b) @test a == b - @test denamed(a) == dename(b, (i, j, k)) - @test denamed(a) == permutedims(denamed(b), (2, 3, 1)) + @test unnamed(a) == unname(b, (i, j, k)) + @test unnamed(a) == permutedims(unnamed(b), (2, 3, 1)) end @testset "dimnametype" begin i, j = Index.((2, 3)) diff --git a/test/test_blockarraysext.jl b/test/test_blockarraysext.jl index 9873642..30e8ea0 100644 --- a/test/test_blockarraysext.jl +++ b/test/test_blockarraysext.jl @@ -1,5 +1,5 @@ using BlockArrays: Block, BlockArray -using ITensorBase: dename, denamed, inds, nameddims +using ITensorBase: inds, nameddims, unname, unnamed using Test: @test, @testset @testset "ITensorBaseBlockArraysExt" begin @@ -12,14 +12,14 @@ using Test: @test, @testset a[Block(2, 2)] = randn(elt, 3, 3) n = nameddims(a, ("i", "j")) i, j = inds(n) - @test denamed(n[i[Block(2)], j[Block(1)]]) == a[Block(2, 1)] - @test denamed(n[Block(2), Block(1)]) == a[Block(2, 1)] - @test denamed(n[Block(2, 1)]) == a[Block(2, 1)] - @test denamed(n[i[Block(2)], j[Block.(1:2)]]) == a[Block(2), Block.(1:2)] - @test denamed(n[Block(2), Block.(1:2)]) == a[Block(2), Block.(1:2)] - @test denamed(n[i[Block.(1:2)], j[Block(1)]]) == a[Block.(1:2), Block(1)] - @test denamed(n[Block.(1:2), Block(1)]) == a[Block.(1:2), Block(1)] - @test denamed(n[Block.(1:2), Block.(1:2)]) == a[Block.(1:2), Block.(1:2)] + @test unnamed(n[i[Block(2)], j[Block(1)]]) == a[Block(2, 1)] + @test unnamed(n[Block(2), Block(1)]) == a[Block(2, 1)] + @test unnamed(n[Block(2, 1)]) == a[Block(2, 1)] + @test unnamed(n[i[Block(2)], j[Block.(1:2)]]) == a[Block(2), Block.(1:2)] + @test unnamed(n[Block(2), Block.(1:2)]) == a[Block(2), Block.(1:2)] + @test unnamed(n[i[Block.(1:2)], j[Block(1)]]) == a[Block.(1:2), Block(1)] + @test unnamed(n[Block.(1:2), Block(1)]) == a[Block.(1:2), Block(1)] + @test unnamed(n[Block.(1:2), Block.(1:2)]) == a[Block.(1:2), Block.(1:2)] a = BlockArray{elt}(undef, [2, 3], [2, 3]) a[Block(1, 1)] = randn(elt, 2, 2) @@ -35,5 +35,5 @@ using Test: @test, @testset nb = nameddims(b, ("j", "i")) nc = na .+ 2 .* nb c = a + 2 * permutedims(b, (2, 1)) - @test dename(nc, ("i", "j")) ≈ c + @test unname(nc, ("i", "j")) ≈ c end diff --git a/test/test_linearalgebra.jl b/test/test_linearalgebra.jl index 5bbc50f..c292760 100644 --- a/test/test_linearalgebra.jl +++ b/test/test_linearalgebra.jl @@ -1,5 +1,5 @@ import LinearAlgebra as LA -using ITensorBase: denamed, dimnames, named +using ITensorBase: dimnames, named, unnamed using Test: @test, @testset @testset "LinearAlgebra (eltype=$(elt))" for elt in @@ -7,12 +7,12 @@ using Test: @test, @testset i, j = named.(2, (:i, :j)) a = randn(elt, i, j) b = randn(elt, j, i) - @test LA.norm(a) ≈ LA.norm(denamed(a)) - @test denamed(LA.normalize(a)) ≈ LA.normalize(denamed(a)) - @test denamed(LA.normalize!(copy(a))) ≈ LA.normalize(denamed(a)) - @test denamed(LA.rmul!(copy(a), 2)) ≈ 2 * denamed(a) - @test denamed(LA.lmul!(2, copy(a))) ≈ 2 * denamed(a) - @test denamed(LA.rdiv!(copy(a), 2)) ≈ denamed(a) / 2 - @test denamed(LA.ldiv!(2, copy(a))) ≈ 2 \ denamed(a) - @test LA.dot(a, b) ≈ LA.dot(denamed(a), denamed(b, dimnames(a))) + @test LA.norm(a) ≈ LA.norm(unnamed(a)) + @test unnamed(LA.normalize(a)) ≈ LA.normalize(unnamed(a)) + @test unnamed(LA.normalize!(copy(a))) ≈ LA.normalize(unnamed(a)) + @test unnamed(LA.rmul!(copy(a), 2)) ≈ 2 * unnamed(a) + @test unnamed(LA.lmul!(2, copy(a))) ≈ 2 * unnamed(a) + @test unnamed(LA.rdiv!(copy(a), 2)) ≈ unnamed(a) / 2 + @test unnamed(LA.ldiv!(2, copy(a))) ≈ 2 \ unnamed(a) + @test LA.dot(a, b) ≈ LA.dot(unnamed(a), unnamed(b, dimnames(a))) end diff --git a/test/test_nameddims_basics.jl b/test/test_nameddims_basics.jl index 4ce6de9..c7537b1 100644 --- a/test/test_nameddims_basics.jl +++ b/test/test_nameddims_basics.jl @@ -1,8 +1,8 @@ using Combinatorics: Combinatorics using ITensorBase: @names, AbstractITensor, ITensor, Name, NameMismatch, - NamedDimsCartesianIndex, NamedDimsCartesianIndices, aligndims, aligneddims, apply, - dename, denamed, denamedtype, dim, dimnames, dimnametype, dims, inds, isnamed, mapinds, - name, named, nameddims, namedoneto, product, replacedimnames, replaceinds, setdimnames + NamedDimsCartesianIndex, NamedDimsCartesianIndices, aligndims, aligneddims, apply, dim, + dimnames, dimnametype, dims, inds, isnamed, mapinds, name, named, nameddims, namedoneto, + product, replacedimnames, replaceinds, setdimnames, unname, unnamed, unnamedtype using LinearAlgebra: LinearAlgebra using Test: @test, @test_throws, @testset using VectorInterface: scalartype @@ -20,16 +20,16 @@ end @test na isa AbstractITensor{String} @test eltype(na) === elt @test ndims(na) == 2 - @test_throws MethodError denamed(a) - @test_throws MethodError dename(a, ("i", "j")) - @test_throws MethodError denamed(a, ("i", "j")) - @test denamed(na) == a + @test_throws MethodError unnamed(a) + @test_throws MethodError unname(a, ("i", "j")) + @test_throws MethodError unnamed(a, ("i", "j")) + @test unnamed(na) == a si, sj = size(na) ai, aj = axes(na) i = namedoneto(3, "i") j = namedoneto(4, "j") - @test name(si) == "i" - @test name(sj) == "j" + @test si == 3 + @test sj == 4 @test name(ai) == "i" @test name(aj) == "j" @test isnamed(na) @@ -45,8 +45,8 @@ end @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. - @test denamedtype(na) === typeof(a) - @test denamedtype(typeof(na)) === AbstractArray + @test unnamedtype(na) === typeof(a) + @test unnamedtype(typeof(na)) === AbstractArray @test dimnametype(typeof(na)) === String @test dimnametype(na) === String @@ -98,8 +98,8 @@ end nb = nameddims(b, ("k", "i", "j")) copyto!(na, nb) @test na == nb - @test denamed(na) == dename(nb, ("i", "j", "k")) - @test denamed(na) == permutedims(denamed(nb), (2, 3, 1)) + @test unnamed(na) == unname(nb, ("i", "j", "k")) + @test unnamed(na) == permutedims(unnamed(nb), (2, 3, 1)) a = randn(elt, 3, 4) na = nameddims(a, ("i", "j")) @@ -150,15 +150,15 @@ end na = a[i] @test na isa ITensor{String} @test dimnames(na) == ["i"] - @test denamed(na) == a + @test unnamed(na) == a # slicing a = randn(elt, 3, 3) na = ITensor(a, ("i", "j")) for na′ in (na[named(2:3, "i"), named(2:3, "j")], na["i" => 2:3, "j" => 2:3]) @test inds(na′) == (named(1:2, "i"), named(1:2, "j")) - @test denamed(na′) == a[2:3, 2:3] - @test denamed(na′) isa typeof(a) + @test unnamed(na′) == a[2:3, 2:3] + @test unnamed(na′) isa typeof(a) end # view slicing @@ -167,9 +167,9 @@ end for na′ in (@view(na[named(2:3, "i"), named(2:3, "j")]), @view(na["i" => 2:3, "j" => 2:3])) @test inds(na′) == (named(1:2, "i"), named(1:2, "j")) - @test copy(denamed(na′)) == a[2:3, 2:3] - @test denamed(na′) ≡ @view(a[2:3, 2:3]) - @test denamed(na′) isa SubArray{elt, 2} + @test copy(unnamed(na′)) == a[2:3, 2:3] + @test unnamed(na′) ≡ @view(a[2:3, 2:3]) + @test unnamed(na′) isa SubArray{elt, 2} end # aliasing @@ -201,35 +201,35 @@ end a = randn(elt, 3, 4) na = nameddims(a, ("i", "j")) - a′ = denamed(na) + a′ = unnamed(na) @test a′ isa Matrix{elt} @test a′ == a - a′ = dename(na, ("j", "i")) + a′ = unname(na, ("j", "i")) @test a′ isa Matrix{elt} @test a′ == transpose(a) - a′ = denamed(na, ("j", "i")) + a′ = unnamed(na, ("j", "i")) @test a′ isa PermutedDimsArray{elt} @test a′ == transpose(a) nb = setdimnames(na, ("k", "j")) @test inds(nb) == (named(1:3, "k"), named(1:4, "j")) - @test denamed(nb) == a + @test unnamed(nb) == a nb = replacedimnames(na, "i" => "k") @test inds(nb) == (named(1:3, "k"), named(1:4, "j")) - @test denamed(nb) == a + @test unnamed(nb) == a nb = replaceinds(na, named(1:3, "i") => named(1:3, "k")) @test inds(nb) == (named(1:3, "k"), named(1:4, "j")) - @test denamed(nb) == a + @test unnamed(nb) == a nb = replaceinds(n -> n == named(1:3, "i") ? named(1:3, "k") : n, na) @test inds(nb) == (named(1:3, "k"), named(1:4, "j")) - @test denamed(nb) == a + @test unnamed(nb) == a nb = mapinds(n -> n == named(1:3, "i") ? named(1:3, "k") : n, na) @test inds(nb) == (named(1:3, "k"), named(1:4, "j")) - @test denamed(nb) == a + @test unnamed(nb) == a na[1, 1] = 11 @test na[1, 1] == 11 - @test Tuple(size(na)) == (named(3, "i"), named(4, "j")) - # An ITensor has named, unordered dims, so `length` (a linearization) errors. - @test_throws MethodError length(na) + @test size(na) == (3, 4) + # An ITensor's `length` is the plain element count (product of its size). + @test length(na) == 12 @test Tuple(axes(na)) == (named(1:3, "i"), named(1:4, "j")) @test randn(named.((3, 4), ("i", "j"))) isa ITensor @test na["i" => 1, "j" => 2] == a[1, 2] @@ -240,17 +240,17 @@ end na[j => 1, i => 2] = 21 @test na[2, 1] == 21 na′ = aligndims(na, ("j", "i")) - @test denamed(na′) isa Matrix{elt} - @test a == permutedims(denamed(na′), (2, 1)) + @test unnamed(na′) isa Matrix{elt} + @test a == permutedims(unnamed(na′), (2, 1)) na′ = aligneddims(na, ("j", "i")) - @test denamed(na′) isa PermutedDimsArray{elt} - @test a == permutedims(denamed(na′), (2, 1)) + @test unnamed(na′) isa PermutedDimsArray{elt} + @test a == permutedims(unnamed(na′), (2, 1)) na′ = aligndims(na, (j, i)) - @test denamed(na′) isa Matrix{elt} - @test a == permutedims(denamed(na′), (2, 1)) + @test unnamed(na′) isa Matrix{elt} + @test a == permutedims(unnamed(na′), (2, 1)) na′ = aligneddims(na, (j, i)) - @test denamed(na′) isa PermutedDimsArray{elt} - @test a == permutedims(denamed(na′), (2, 1)) + @test unnamed(na′) isa PermutedDimsArray{elt} + @test a == permutedims(unnamed(na′), (2, 1)) na = nameddims(randn(elt, 2, 3), (:i, :j)) nb = nameddims(randn(elt, 3, 2), (:j, :i)) @@ -263,24 +263,24 @@ end @test issetequal(name.(Tuple(I)), (:i, :j)) nc[I] = na[I] + nb[I] end - @test dename(nc, (:i, :j)) ≈ dename(na, (:i, :j)) + dename(nb, (:i, :j)) + @test unname(nc, (:i, :j)) ≈ unname(na, (:i, :j)) + unname(nb, (:i, :j)) a = nameddims(randn(elt, 2, 3), (:i, :j)) b = nameddims(randn(elt, 3, 2), (:j, :i)) c = a + b - @test dename(c, (:i, :j)) ≈ dename(a, (:i, :j)) + dename(b, (:i, :j)) + @test unname(c, (:i, :j)) ≈ unname(a, (:i, :j)) + unname(b, (:i, :j)) c = a .+ b - @test dename(c, (:i, :j)) ≈ dename(a, (:i, :j)) + dename(b, (:i, :j)) + @test unname(c, (:i, :j)) ≈ unname(a, (:i, :j)) + unname(b, (:i, :j)) c = map(+, a, b) - @test dename(c, (:i, :j)) ≈ dename(a, (:i, :j)) + dename(b, (:i, :j)) + @test unname(c, (:i, :j)) ≈ unname(a, (:i, :j)) + unname(b, (:i, :j)) c = nameddims(Array{elt}(undef, 2, 3), (:i, :j)) c = map!(+, c, a, b) - @test dename(c, (:i, :j)) ≈ dename(a, (:i, :j)) + dename(b, (:i, :j)) + @test unname(c, (:i, :j)) ≈ unname(a, (:i, :j)) + unname(b, (:i, :j)) c = a .+ 2 .* b - @test dename(c, (:i, :j)) ≈ dename(a, (:i, :j)) + 2 * dename(b, (:i, :j)) + @test unname(c, (:i, :j)) ≈ unname(a, (:i, :j)) + 2 * unname(b, (:i, :j)) c = nameddims(Array{elt}(undef, 2, 3), (:i, :j)) c .= a .+ 2 .* b - @test dename(c, (:i, :j)) ≈ dename(a, (:i, :j)) + 2 * dename(b, (:i, :j)) + @test unname(c, (:i, :j)) ≈ unname(a, (:i, :j)) + 2 * unname(b, (:i, :j)) # Regression test for proper permutations. a = nameddims(randn(elt, 2, 3, 4), (:i, :j, :k)) @@ -307,13 +307,13 @@ end # arrows on the axes flip. For plain ranges the axis-level `conj` is a # no-op and the test reduces to element-wise conjugation. ca = conj(a) - @test denamed(ca) == conj(denamed(a)) + @test unnamed(ca) == conj(unnamed(a)) @test dimnames(ca) == dimnames(a) # `fill!` forwards to the underlying storage. b = randn(elt, i, j) @test fill!(b, zero(elt)) === b - @test all(iszero, denamed(b)) + @test all(iszero, unnamed(b)) end @testset "promote_leaf_eltypes (eltype=$elt)" for elt in TestBasicsUtils.elts # `LinearAlgebra.promote_leaf_eltypes` is called from `isapprox`; the @@ -323,17 +323,17 @@ end i, j = namedoneto.((2, 3), ("i", "j")) a = randn(elt, i, j) @test LinearAlgebra.promote_leaf_eltypes(a) === - LinearAlgebra.promote_leaf_eltypes(denamed(a)) + LinearAlgebra.promote_leaf_eltypes(unnamed(a)) end @testset "sum/mapreduce (eltype=$elt)" for elt in TestBasicsUtils.elts # Reductions delegate to the underlying storage. `sum` is routed directly # rather than left to the generic `mapreduce` fallback because some backends # (such as graded arrays) define `Base.sum` without the general `mapreduce`, - # so summing the denamed data is the path that works for them. + # so summing the unnamed data is the path that works for them. i, j = namedoneto.((2, 3), ("i", "j")) a = randn(elt, i, j) - @test sum(a) == sum(denamed(a)) - @test mapreduce(identity, +, a) == mapreduce(identity, +, denamed(a)) + @test sum(a) == sum(unnamed(a)) + @test mapreduce(identity, +, a) == mapreduce(identity, +, unnamed(a)) end @testset "begin/end (eltype=$elt)" for elt in TestBasicsUtils.elts i, j = namedoneto.((2, 3), ("i", "j")) diff --git a/test/test_namedinteger.jl b/test/test_namedinteger.jl index 6972618..0f6b8d0 100644 --- a/test/test_namedinteger.jl +++ b/test/test_namedinteger.jl @@ -1,18 +1,18 @@ -using ITensorBase: Named, NamedInteger, denamed, name, named, namedoneto +using ITensorBase: Named, NamedInteger, name, named, namedoneto, unnamed using Test: @test, @testset @testset "Named integer" begin i = named(3, :i) @test i isa Named @test i isa NamedInteger - @test denamed(i) ≡ 3 + @test unnamed(i) ≡ 3 @test name(i) ≡ :i end @testset "Named equality and hash invariant" begin # Equality and hashing are type-agnostic across named array types, following # Base's array convention (`[1, 2, 3] == 1:3` and they hash equally). A named - # array and a named unit range with equal denamed values and names are equal, so + # array and a named unit range with equal unnamed values and names are equal, so # they must hash equally too. na = named([1, 2, 3], "x") nr = namedoneto(3, "x") diff --git a/test/test_operator.jl b/test/test_operator.jl index d397a4c..7f585f3 100644 --- a/test/test_operator.jl +++ b/test/test_operator.jl @@ -1,10 +1,11 @@ using ITensorBase: ITensorBase as NDA, ITensor, ITensorOperator, apply, codomainnames, - dename, denamed, dimnames, domainnames, nameddims, namedoneto, operator, product, - replacedimnames, similar_operator, state + dimnames, domainnames, nameddims, namedoneto, operator, product, replacedimnames, + similar_operator, state, unname, unnamed using LinearAlgebra: I, norm using Random: Random using StableRNGs: StableRNG -using TensorAlgebra: gram_eigh_full, gram_eigh_full_with_pinv, matricize +using TensorAlgebra.MatrixAlgebra: gram_eigh_full, gram_eigh_full_with_pinv +using TensorAlgebra: matricize using Test: @test, @testset @testset "operator" begin @@ -54,7 +55,7 @@ end @test codomainnames(Id) == codomainnames(op) @test domainnames(Id) == domainnames(op) Id_mat = matricize(state(Id), (i, j) => "row", (k, l) => "col") - @test dename(Id_mat, ("row", "col")) ≈ I(6) + @test unname(Id_mat, ("row", "col")) ≈ I(6) end @testset "one(::AbstractITensor, codomain, domain)" begin @@ -63,7 +64,7 @@ end a = randn(i, j, k, l) Id = one(a, (i, j), (k, l)) Id_mat = matricize(Id, (i, j) => "row", (k, l) => "col") - @test dename(Id_mat, ("row", "col")) ≈ I(6) + @test unname(Id_mat, ("row", "col")) ≈ I(6) # Non-trivial axis ordering: codomain/domain are interleaved in `a`. p, q, r, s = namedoneto.((2, 4, 2, 4), ("p", "q", "r", "s")) @@ -71,7 +72,7 @@ end Id = one(a, (p, q), (r, s)) @test issetequal(dimnames(Id), ("p", "r", "q", "s")) Id_mat = matricize(Id, (p, q) => "row", (r, s) => "col") - @test dename(Id_mat, ("row", "col")) ≈ I(8) + @test unname(Id_mat, ("row", "col")) ≈ I(8) end @testset "similar_operator" begin @@ -102,11 +103,11 @@ end op = operator(zeros(3, 3), ("i'",), ("i",)) rng = StableRNG(123) Random.randn!(rng, op) - @test !all(iszero, denamed(state(op))) + @test !all(iszero, unnamed(state(op))) Random.rand!(rng, op) - @test !all(iszero, denamed(state(op))) - @test all(0 .≤ denamed(state(op)) .≤ 1) + @test !all(iszero, unnamed(state(op))) + @test all(0 .≤ unnamed(state(op)) .≤ 1) end @testset "operator-preserving broadcasting" begin @@ -124,14 +125,14 @@ end @test issetequal(domainnames(r), ("i",)) end - @test dename(state(o + o), nms) ≈ 2 .* dename(s, nms) - @test all(iszero, dename(state(o - o), nms)) - @test dename(state(-o), nms) ≈ -dename(s, nms) - @test dename(state(2 * o), nms) ≈ 2 .* dename(s, nms) - @test dename(state(o * 2), nms) ≈ 2 .* dename(s, nms) - @test dename(state(2 .* o), nms) ≈ 2 .* dename(s, nms) - @test dename(state(o .* 2), nms) ≈ 2 .* dename(s, nms) - @test dename(state(o ./ 2), nms) ≈ dename(s, nms) ./ 2 + @test unname(state(o + o), nms) ≈ 2 .* unname(s, nms) + @test all(iszero, unname(state(o - o), nms)) + @test unname(state(-o), nms) ≈ -unname(s, nms) + @test unname(state(2 * o), nms) ≈ 2 .* unname(s, nms) + @test unname(state(o * 2), nms) ≈ 2 .* unname(s, nms) + @test unname(state(2 .* o), nms) ≈ 2 .* unname(s, nms) + @test unname(state(o .* 2), nms) ≈ 2 .* unname(s, nms) + @test unname(state(o ./ 2), nms) ≈ unname(s, nms) ./ 2 # `*` (contraction) still decays to a plain tensor. @test !((o * o) isa ITensorOperator) diff --git a/test/test_tensoralgebra.jl b/test/test_tensoralgebra.jl index ee1d435..835eabd 100644 --- a/test/test_tensoralgebra.jl +++ b/test/test_tensoralgebra.jl @@ -1,10 +1,11 @@ using ITensorBase: - ITensorBase, dename, denamed, dimnames, inds, namedoneto, replacedimnames, uniquename -using LinearAlgebra: LinearAlgebra, lq, norm, qr, svd + ITensorBase, dimnames, inds, namedoneto, replacedimnames, uniquename, unname, unnamed +using LinearAlgebra: LinearAlgebra, norm +using MatrixAlgebraKit: left_null, left_orth, left_polar, lq_compact, lq_full, qr_compact, + qr_full, right_null, right_orth, right_polar, svd_compact, svd_trunc using StableRNGs: StableRNG -using TensorAlgebra: TensorAlgebra, contract, gram_eigh_full, gram_eigh_full_with_pinv, - left_null, left_orth, left_polar, matricize, orth, polar, right_null, right_orth, - right_polar, unmatricize +using TensorAlgebra.MatrixAlgebra: gram_eigh_full, gram_eigh_full_with_pinv +using TensorAlgebra: TensorAlgebra, contract, matricize, unmatricize using Test: @test, @test_broken, @testset @testset "TensorAlgebra (eltype=$(elt))" for elt in @@ -22,18 +23,18 @@ using Test: @test, @test_broken, @testset na2 = randn(elt, j, k) na_dest = na1 * na2 @test eltype(na_dest) ≡ elt - @test dename(na_dest, (i, k)) ≈ denamed(na1) * denamed(na2) + @test unname(na_dest, (i, k)) ≈ unnamed(na1) * unnamed(na2) end @testset "matricize" begin i, j, k, l = namedoneto.((2, 3, 4, 5), ("i", "j", "k", "l")) na = randn(elt, i, j, k, l) na_fused = matricize(na, (k, i) => "a", (j, l) => "b") # Fuse all dimensions. - @test dename(na_fused, ("a", "b")) ≈ reshape( - dename(na, (k, i, j, l)), + @test unname(na_fused, ("a", "b")) ≈ reshape( + unname(na, (k, i, j, l)), ( - denamed(length(k)) * denamed(length(i)), - denamed(length(j)) * denamed(length(l)), + length(k) * length(i), + length(j) * length(l), ) ) end @@ -43,10 +44,10 @@ using Test: @test, @test_broken, @testset na = randn(elt, a, b) # Split all dimensions. na_split = unmatricize(na, "a" => (k, i), "b" => (j, l)) - @test dename(na_split, ("k", "i", "j", "l")) ≈ + @test unname(na_split, ("k", "i", "j", "l")) ≈ reshape( - dename(na, ("a", "b")), - (denamed(k), denamed(i), denamed(j), denamed(l)) + unname(na, ("a", "b")), + (unnamed(k), unnamed(i), unnamed(j), unnamed(l)) ) end @testset "Matrix functions" begin @@ -58,8 +59,8 @@ using Test: @test, @test_broken, @testset rng = StableRNG(123) a = randn(rng, $elt, (i, j, k, l)) fa = $f(a, (j, l), (k, i)) - m = dename(matricize(a, (j, l) => "a", (k, i) => "b"), ("a", "b")) - fm = dename(matricize(fa, (j, l) => "a", (k, i) => "b"), ("a", "b")) + m = unname(matricize(a, (j, l) => "a", (k, i) => "b"), ("a", "b")) + fm = unname(matricize(fa, (j, l) => "a", (k, i) => "b"), ("a", "b")) @test fm ≈ $f(m) end end @@ -71,16 +72,20 @@ using Test: @test, @test_broken, @testset a = randn(elt, i, j) # TODO: Should this be allowed? # TODO: Add support for specifying new name. - for f in - (left_orth, left_polar, lq, orth, polar, qr, right_orth, right_polar) + for f in ( + left_orth, left_polar, lq_compact, lq_full, qr_compact, qr_full, + right_orth, right_polar, + ) x, y = f(a, (i,)) @test x * y ≈ a end a = randn(elt, i, j, k, l) # TODO: Add support for specifying new name. - for f in - (left_orth, left_polar, lq, orth, polar, qr, right_orth, right_polar) + for f in ( + left_orth, left_polar, lq_compact, lq_full, qr_compact, qr_full, + right_orth, right_polar, + ) x, y = f(a, (i, k), (j, l)) @test x * y ≈ a end @@ -92,19 +97,19 @@ using Test: @test, @test_broken, @testset a = randn(elt, i, j) # TODO: Should this be allowed? # TODO: Add support for specifying new name. - u, s, v = svd(a, (i,)) + u, s, v = svd_compact(a, (i,)) @test u * s * v ≈ a a = randn(elt, i, j, k, l) # TODO: Add support for specifying new name. - u, s, v = svd(a, (i, k), (j, l)) + u, s, v = svd_compact(a, (i, k), (j, l)) @test u * s * v ≈ a # Test truncation. a = randn(elt, i, j, k, l) - u, s, v = svd(a, (i, k), (j, l); trunc = (; maxrank = 2)) + u, s, v = svd_trunc(a, (i, k), (j, l); trunc = (; maxrank = 2)) @test u * s * v ≉ a - @test denamed.(Tuple(size(s))) == (2, 2) + @test size(s) == (2, 2) end @testset "left_null/right_null" begin dims = (2, 2, 2, 2) @@ -147,7 +152,7 @@ using Test: @test, @test_broken, @testset # (rank × rank) named identity. fresh_rank = uniquename(rank_name) X_fresh = replacedimnames(X, rank_name => fresh_rank) - YXmat = dename(Y * X_fresh, (rank_name, fresh_rank)) + YXmat = unname(Y * X_fresh, (rank_name, fresh_rank)) @test YXmat ≈ LinearAlgebra.I(size(YXmat, 1)) end end