Skip to content

[NDTensors] Unvendor TypeParameterAccessors#1729

Merged
mtfishman merged 4 commits into
mainfrom
mf/unvendor-tpa
Apr 27, 2026
Merged

[NDTensors] Unvendor TypeParameterAccessors#1729
mtfishman merged 4 commits into
mainfrom
mf/unvendor-tpa

Conversation

@mtfishman

@mtfishman mtfishman commented Apr 26, 2026

Copy link
Copy Markdown
Member

Replace the vendored TypeParameterAccessors snapshot (in NDTensors/src/vendored/) with a real package dependency on TypeParameterAccessors v0.4.23. Removes the standalone module Vendored wrapper in NDTensors.jl and the module Vendored ... include(...) blocks in each
NDTensorsXxxExt, and switches every using .Vendored.TypeParameterAccessors import to the registered package across src/, ext/, lib/, and tests.

Two API adjustments are required by upstream's redesigned similartype:

  1. set_indstype(::Type{<:Tensor}, ::Tuple) — upstream no longer exports set_indstype. The single-site overload + single-site call inside similartype(::Type{<:Tensor}, ::Tuple) is folded by inlining the body directly.

  2. Wrapper-aware similartype for arbitrary AbstractArrays — upstream's fallback uses Base.promote_op(similar, ...), which gives Any for wrapper types (SubArray, ReshapedArray, Adjoint, ...) where Base.similar is not type-stable, and recurses to Union{} for non-wrapped arrays whose similar is overloaded by NDTensors.

    Defining the missing fallback as overloads on TypeParameterAccessors.similartype(::Type{<:AbstractArray}, ...) would be type piracy. Instead, this PR introduces an NDTensors-owned helper recursive_similartype (in abstractarray/similar.jl) that reproduces the trait-based wrapper-unwrap dispatch the vendored copy provided. The helper is used at the small number of call sites that pass a non-NDTensors-owned AbstractArray type to similartype: NDTensors's similar(::Type{<:AbstractArray}, ...) internals, tensorstorage/similar.jl's similartype overloads (recursing into datatype(...)), and dense/dense.jl's promote_rule for Dense. NDTensors-owned types (Tensor, TensorStorage) and AbstractMappedArray (in NDTensorsMappedArraysExt) get explicit recursive_similartype delegation overloads, since their parenttype classifies them as wrapped under IsWrappedArray and the trait-based fallback would otherwise strip them down to a plain Array — that incorrect unwrap was the root cause of the _fill!!(::EmptyTensor, ...) materialization breakage hit during iteration.

    A previously missing 3-arg similartype(::Type{<:Tensor}, ::Type, ::Tuple) is also added (composing the 2-arg eltype and dims forms) — this was the shape vendored TPA provided generically.

Verified locally: Pkg.test("NDTensors") passes with 2845 passing, 0 failing, 4 broken (pre-existing unrelated JLArray @test_broken items in Expose/test/runtests.jl). The NDTensorsMappedArraysExt test passes 7/7. The 2-thread ITensors run that originally surfaced this passes 18590, with 40 pre-existing broken.

Patch bump: NDTensors 0.4.26 -> 0.4.27.

Replace the vendored TypeParameterAccessors snapshot (in
`NDTensors/src/vendored/`) with a real package dependency on
`TypeParameterAccessors` v0.4.23. Removes the standalone
`module Vendored` wrapper in `NDTensors.jl` and the
`module Vendored ... include(...)` blocks in each
`NDTensorsXxxExt`, and switches every `using .Vendored.TypeParameterAccessors`
import to the registered package across `src/`, `ext/`, `lib/`, and tests.

Two API adjustments are required by upstream's redesigned
`similartype`:

1. `set_indstype(::Type{<:Tensor}, ::Tuple)` — upstream no longer
   exports `set_indstype`. The single-site overload + single-site
   call inside `similartype(::Type{<:Tensor}, ::Tuple)` is folded
   by inlining the body directly.
2. Wrapper-aware `similartype` for arbitrary `AbstractArray`s —
   upstream's fallback uses `Base.promote_op(similar, ...)`, which
   gives `Any` for wrapper types (`SubArray`, `ReshapedArray`,
   `Adjoint`, ...) where `Base.similar` is not type-stable, and
   recurses to `Union{}` for non-wrapped arrays whose `similar` is
   overloaded by NDTensors.

   Defining the missing fallback as overloads on
   `TypeParameterAccessors.similartype(::Type{<:AbstractArray}, ...)`
   would be type piracy. Instead, this PR introduces an NDTensors-owned
   helper `array_similartype` (in `abstractarray/similar.jl`) that
   reproduces the trait-based wrapper-unwrap dispatch the vendored
   copy provided. The helper is used at the small number of call
   sites that pass a non-NDTensors-owned `AbstractArray` type to
   `similartype`: NDTensors's `similar(::Type{<:AbstractArray}, ...)`
   internals, `tensorstorage/similar.jl`'s `similartype` overloads
   (recursing into `datatype(...)`), and `dense/dense.jl`'s
   `promote_rule` for `Dense`. NDTensors-owned types continue to use
   `TypeParameterAccessors.similartype` directly via their existing
   overloads (which are not piracy since the types are NDTensors's).

Verified locally: `Pkg.test("NDTensors")` passes with 2845
passing, 0 failing, 4 broken (pre-existing unrelated JLArray
`@test_broken` items in `Expose/test/runtests.jl`).

Patch bump: NDTensors 0.4.26 -> 0.4.27.
The wrapper-aware `array_similartype` introduced in the previous
commit treats `Type{<:Tensor}` and `Type{<:TensorStorage}` as
wrapped arrays (their `parenttype` differs from themselves), and
the trait-based fallback unwraps them down to a plain `Array`.
That breaks the call site at
`abstractarray/similar.jl:similar(::Type{<:AbstractArray}, ::Type, ::Tuple)`,
which is invoked by
`empty/EmptyTensor.jl:_fill!!(::EmptyTensor, ...)` to materialize
an `EmptyTensor` into a `DenseTensor` on first assignment. With
the unwrap, the materialization returns a plain `Array` instead
of a `Tensor`, leaving the ITensor's `tensor` field
mistyped — surfaces as
`MethodError: no method matching _contract!!(::Array, ::Tensor, ::Tensor)`
on subsequent contractions.

Fix:
1. Add explicit `array_similartype` overloads on `Type{<:Tensor}`
   and `Type{<:TensorStorage}` that delegate to
   `TypeParameterAccessors.similartype`, which has NDTensors's own
   overloads for these types.
2. Add the previously missing 3-arg
   `similartype(::Type{<:Tensor}, ::Type, ::Tuple)`, composing the
   2-arg eltype and dims forms (this was the form vendored TPA
   provided generically as a wrapper-aware fallback).

Manually verified the original failure is resolved: an
`EmptyTensor`-backed `ITensor` materializes correctly to a
`DenseTensor` after `R .= NaN; R .= A .* B`. NDTensors `Pkg.test`
still passes 2845/2845.
…lartype

The MappedArrays extension overloads `NDTensors.similartype` (=
`TypeParameterAccessors.similartype`) to short-circuit
`AbstractMappedArray` types into a plain `Array` rather than
recursing through the trait-based wrapper-unwrap. Those overloads
fired in NDTensors's `similar` paths under the vendored TPA setup
because every recursion went through `similartype`.

The previous unvendoring commits route the recursive
`AbstractArray` lookups through `array_similartype` (the
NDTensors-internal wrapper-aware helper) instead. The
MappedArrays-specific overloads on `similartype` therefore no
longer fire on those paths, and `ReadonlyMappedArray` falls into
the trait-based fallback, which doesn't return a useful concrete
type and breaks contraction allocation.

Mirror the two relevant `similartype` overloads on
`array_similartype`. Verified locally:
`test/ext/NDTensorsMappedArraysExt/runtests.jl` now passes 7/7.
@codecov

codecov Bot commented Apr 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.09%. Comparing base (e6d2480) to head (e7efc2e).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1729   +/-   ##
=======================================
  Coverage   81.09%   81.09%           
=======================================
  Files          59       59           
  Lines        4676     4676           
=======================================
  Hits         3792     3792           
  Misses        884      884           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Mechanical rename. The previous name read as "similartype for
arrays", which is a tautology (`similartype` is already an
array operation). The new name describes the distinctive
behavior: this version of `similartype` recursively unwraps
wrapper types (`SubArray`, `ReshapedArray`, `Adjoint`,
`AbstractMappedArray`, ...) via `IsWrappedArray` /
`unwrap_array_type`, where upstream's `Base.promote_op`-based
fallback would either return `Any` (because `Base.similar` is
not type-stable for the wrapper) or recurse to `Union{}`.
@mtfishman mtfishman enabled auto-merge (squash) April 27, 2026 17:15
@mtfishman mtfishman merged commit 0cfaf4f into main Apr 27, 2026
18 checks passed
@mtfishman mtfishman deleted the mf/unvendor-tpa branch April 27, 2026 17:17
ipasichnyk pushed a commit to ipasichnyk/ITensors.jl that referenced this pull request May 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant