Skip to content

Balanced gram_eigh_full convention, add one and operator-construction primitives#177

Open
mtfishman wants to merge 7 commits into
mainfrom
mf/gram-eigh-balanced
Open

Balanced gram_eigh_full convention, add one and operator-construction primitives#177
mtfishman wants to merge 7 commits into
mainfrom
mf/gram-eigh-balanced

Conversation

@mtfishman
Copy link
Copy Markdown
Member

@mtfishman mtfishman commented Jun 2, 2026

Summary

Flips gram_eigh_full from the right-Gram (A ≈ X' * X) convention to the balanced left form (A ≈ X * X'), where X = V * sqrt(D) is the symmetric eigendecomposition with the square-root absorbed into the eigenvector matrix. The returned factor X now carries the codomain axes followed by a trailing rank axis, matching the layout of the eigendecomposition's V and the SVD's U, and parallel to the L-form of Cholesky. The companion gram_eigh_full_with_pinv now returns a left inverse Y such that Y * X ≈ I on the rank subspace.

Also adds TensorAlgebra.one(A, codomain, domain) for constructing an identity operator tensor with the same shape as A, with the layered dispatch chain (labels, perm tuples, biperms, Val{ndims_codomain}) used by the other factorizations. Not exported because exporting would clash with Base.one. Qualify as TensorAlgebra.one(...).

Adds TensorAlgebra.similar_map(prototype, [T,] codomain_axes, domain_axes) for allocating an array shaped as a linear map with axes (codomain_axes..., domain_axes...). This is the primitive NamedDimsArrays.similar_operator will route through (ITensor/NamedDimsArrays.jl#229), so a backend only needs to overload similar_map to plug into the named-axis wrapper.

Adds projectto!(dest, src) and checked_projectto!(dest, src; atol, rtol) for orthogonal projection of a source array into the representable subspace of dest. projectto! drops the non-representable component without looking at its size. checked_projectto! runs the projection and verifies the discarded weight via isapprox, throwing on tolerance violations. The default projectto! falls through to copyto!, correct for dense backends where everything is representable. AbelianGradedArray (in GradedArrays.jl) overloads it to copy only symmetry-allowed entries.

Pairs similar_map with projectto! as project_map(raw, cod, dom) = projectto!(similar_map(raw, cod, dom), raw), the data-bearing sibling of the _map allocator family. checked_project_map is the same on top of checked_projectto!. Operator constructors call the checked variant by default.

The gram_eigh_full convention change is technically breaking, but the function was introduced very recently and has no known downstream users, so this lands as a patch bump (0.9.5).

mtfishman added 2 commits June 1, 2026 23:56
Switch gram_eigh_full and gram_eigh_full_with_pinv from A ≈ X' * X
to A ≈ X * X', i.e. X = V * sqrt(D) instead of sqrt(D) * V'.
This matches the convention used by eigh and SVD (factor on the
left, with codomain axes leading and a trailing rank axis), so the
output of gram_eigh_full can be right-multiplied into a tensor in
the operator's input space without an axis-order swap.

The companion left inverse Y from gram_eigh_full_with_pinv now
satisfies Y * X ≈ I on the rank subspace (it was a right inverse
under the old convention).
Mirrors the existing factorization API (qr/svd/eigen/gram_eigh_full):
a layered dispatch chain accepting labels, perm-tuples, biperms, or
Val{ndims_codomain}, all funneling into a canonical worker that
matricizes, calls MatrixAlgebraKit.one!, and unmatricizes. The
result sits in canonical (codomain, domain) order.

Not exported, since exporting would clash with the implicit Base.one.
Qualify as `TensorAlgebra.one(A, ...)`.
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 2, 2026

Codecov Report

❌ Patch coverage is 65.62500% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.03%. Comparing base (0895aa9) to head (8409c0d).

Files with missing lines Patch % Lines
src/projectto.jl 0.00% 9 Missing ⚠️
src/factorizations.jl 88.23% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #177      +/-   ##
==========================================
- Coverage   80.61%   80.03%   -0.58%     
==========================================
  Files          24       26       +2     
  Lines        1011     1037      +26     
==========================================
+ Hits          815      830      +15     
- Misses        196      207      +11     
Flag Coverage Δ
docs 26.47% <53.12%> (+0.74%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ 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.

@mtfishman mtfishman changed the title Balanced gram_eigh_full convention; add TensorAlgebra.one Balanced gram_eigh_full convention, add one and similar_map Jun 2, 2026
Allows callers to supply codomain and domain axes in the same direction. Storage axes become `(codomain..., conj.(domain)...)`, baking the bra/ket flip into the primitive instead of pushing it onto every caller.
mtfishman added a commit to ITensor/NamedDimsArrays.jl that referenced this pull request Jun 2, 2026
`TensorAlgebra.similar_map` now flips the domain direction itself when laying out storage (ITensor/TensorAlgebra.jl#177), so the wrapper passes both sides in the same direction and lets the primitive handle the bra/ket flip.
mtfishman and others added 2 commits June 2, 2026 17:12
`projectto!(dest, src) -> dest` orthogonally projects `src` onto the representable subspace of `dest`, in place. Magnitude-blind and tolerance-free: the non-representable component is dropped unconditionally. `checked_projectto!(dest, src; atol, rtol) -> dest` runs the projection and then verifies via `isapprox(src, dest)`, throwing on tolerance violations.

The default `projectto!` falls through to `copyto!`, which is correct for dense backends where the representable subspace is everything. Block-structured backends (`AbelianGradedArray`, `FusionTensor`) overload it to copy only the symmetry-allowed entries.

This pairs with `similar_map` to give a uniform "allocate then project" idiom for operator constructors across backends, mirroring the standard `copyto!(similar(...), src)` pattern but with backend-aware projection in place of faithful copy.

Co-authored-by: Claude <noreply@anthropic.com>
…ppers

The data-bearing sibling of `similar_map` / `zeros_map`: allocate via `similar_map` and project `raw` in via `projectto!`. `checked_project_map` is the same on top of `checked_projectto!`, throwing if the discarded weight exceeds the tolerance.

Co-authored-by: Claude <noreply@anthropic.com>
@mtfishman mtfishman changed the title Balanced gram_eigh_full convention, add one and similar_map Balanced gram_eigh_full convention, add one and operator-construction primitives Jun 2, 2026
Unmatricize `S` so all three SVD outputs share one backend. Previously `S` came back as the matricized form from `MatrixAlgebra.svd!!`, while `U` and `Vᴴ` went through `unmatricize`, leaving downstream consumers with mixed backends (`FusedGradedMatrix` for `S`, the unmatricized backend for the others). `S` now uses `tuplemortar(((axes(U, 2),), (axes(Vᴴ, 1),)))` as its 1+1 axis pair.
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