From 71bc0a54ce249e08edbd3738a144338b81be5ad0 Mon Sep 17 00:00:00 2001 From: Matthew Fishman Date: Thu, 23 Jul 2026 20:59:52 -0400 Subject: [PATCH] Add `Matrix`/`Vector` conversion for named tensors ## Summary Adds `Matrix(::AbstractNamedTensor)` and `Vector(::AbstractNamedTensor)` for densifying a named tensor whose rank is fixed by its leg count (e.g. the two-leg result of `matricize`), which reads more clearly at the call site than the generic `Array`. Both are handled by a single `Array{<:Any, N}` method that defaults the eltype and forwards to the existing `Array{T, N}` conversion, so a rank mismatch (a non-two-leg tensor into `Matrix`, a non-one-leg tensor into `Vector`) errors as expected. Also removes the `AbstractArray{T}` / `AbstractArray{T, N}` constructors, and the `_checkaxs` / `copyto_axcheck!` helpers they used: `AbstractNamedTensor` is not an `AbstractArray`, so those constructors returned a named tensor from an `AbstractArray` constructor, and nothing called them. --- Project.toml | 2 +- src/abstractnamedtensor.jl | 19 ++----------------- test/test_nameddims_basics.jl | 9 +++++++++ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/Project.toml b/Project.toml index 30cd9eb..c1a0f85 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "ITensorBase" uuid = "4795dd04-0d67-49bb-8f44-b89c448a1dc7" -version = "0.13.3" +version = "0.13.4" authors = ["ITensor developers and contributors"] [workspace] diff --git a/src/abstractnamedtensor.jl b/src/abstractnamedtensor.jl index 8ed058b..99d2c6f 100644 --- a/src/abstractnamedtensor.jl +++ b/src/abstractnamedtensor.jl @@ -271,17 +271,6 @@ end # Conversion -# Copied from `Base` (defined in abstractarray.jl). -@noinline function _checkaxs(axd, axs) - axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs")) - return nothing -end -function copyto_axcheck!(dest, src) - _checkaxs(axes(dest), axes(src)) - copyto!(dest, src) - return dest -end - # These are defined since the Base versions assume the eltype and ndims are known # at compile time, which isn't true for ITensors. # Workaround: `Array(::TensorKit.AbstractTensorMap)` is not defined yet (it should be), so a @@ -295,12 +284,8 @@ function Base.Array(a::AbstractNamedTensor) end Base.Array{T}(a::AbstractNamedTensor) where {T} = Array{T}(unnamed(a)) Base.Array{T, N}(a::AbstractNamedTensor) where {T, N} = Array{T, N}(unnamed(a)) -Base.AbstractArray{T}(a::AbstractNamedTensor) where {T} = AbstractArray{T, ndims(a)}(a) -function Base.AbstractArray{T, N}(a::AbstractNamedTensor) where {T, N} - dest = similar(a, T) - copyto_axcheck!(unnamed(dest), unnamed(a)) - return dest -end +# Catches the bare `Matrix`/`Vector` (`Array{T, N} where T`, ndims fixed), defaulting the eltype. +Base.Array{<:Any, N}(a::AbstractNamedTensor) where {N} = Array{eltype(a), N}(a) # Read the parent's axes through TensorAlgebra's interface (not `Base.axes`) so a non-array # backend like a TensorMap, whose axes are its native spaces, is supported. diff --git a/test/test_nameddims_basics.jl b/test/test_nameddims_basics.jl index 1b53bc3..d78a824 100644 --- a/test/test_nameddims_basics.jl +++ b/test/test_nameddims_basics.jl @@ -89,6 +89,15 @@ end @test eltype(a′) ≡ elt @test a′ isa Matrix{elt} @test a′ == a + # `Matrix`/`Vector` densify when the rank matches the leg count. + m = Matrix(na) + @test m isa Matrix{elt} + @test m == a + @test_throws Exception Vector(na) # two legs, not a vector + v = nameddims(randn(elt, 4), ("i",)) + @test Vector(v) isa Vector{elt} + @test Vector(v) == unnamed(v) + @test_throws Exception Matrix(v) # one leg, not a matrix if elt <: Real a = randn(elt, 3, 4)