Add BP simple-update gate application#114
Draft
mtfishman wants to merge 29 commits into
Draft
Conversation
Introduces a layered gate-application API: - `apply_operator(op, init)` applies a single named-dims operator to a tensor network using simple-update-style local QR + balanced SVD. - `apply_operators(ops, init)` applies a sequence of operators via AlgorithmsInterface (`AI.Problem`, `AI.Algorithm`, `AI.State`, `AI.step!`, `AI.initialize_state`, `AI.is_finished!`), with the tensor network as the `iterate` and a BP message cache as auxiliary state. - `BPApplyOperator` is the default per-operator algorithm, carrying `trunc`, `pinv_alg`, and `normalize`. The cache lives entirely on the state and is constructed by `initialize_cache(iterate, op_alg)` (stub for `BPApplyOperator` currently returns `nothing`, giving env-free simple update). - New primitives `balanced_eigh_and_inv` and `balanced_svd` in `apply/tensoralgebra.jl`, layered matrix -> array -> named-dims in the TensorAlgebra style so they can later be promoted upstream. - Tikhonov regularization (`TikhonovPinv`) for pseudo-inverses used during environment absorption. Adds `MatrixAlgebraKit` as a dep for SVD / eigh kernels. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Use `@kwdef` for `ApplyOperatorsProblem`, `ApplyOperators`, `ApplyOperatorsState`, and `BPApplyOperator`; construct via keyword args at call sites. - Make `stopping_criterion::AI.StopAfterIteration` a hardcoded-type field on `ApplyOperators`, auto-set from `length(ops)` inside `apply_operators`. Drop the per-algorithm `AI.is_finished!` overload and inlined criterion construction in `initialize_state` / `initialize_state!` — the AI defaults now find it via `algorithm.stopping_criterion`. - Reorder `initialize_cache` arguments to `(algorithm, iterate)` and define an explicit catch-all method that throws `MethodError` (with a docstring on the canonical signature). No `BPApplyOperator` method is defined yet — a `MessageCache` constructor is future work. - Have the standalone `apply_operator(op, init; ..., cache)` default its `cache` to `initialize_cache(alg, init)`, matching the path taken by `apply_operators`. - Replace the in-tree `TikhonovPinv` / `regularized_inv` with `MatrixAlgebraKit.inv_regularized`. The user-visible knob becomes `pinv_kwargs::NamedTuple = (; tol = 0)`, threaded through `apply_operator_bp`, `_absorb_envs`, and `balanced_eigh_and_inv`. - Spell out `stopping_criterion` / `stopping_criterion_state` in full (no more `sc` shorthand). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- `apply_operator(algorithm, op, iterate; cache!)` is the non-mutating entry; it allocates the output buffer via `initialize_output(apply_operator, algorithm, op, iterate)` (default `copy(iterate)`) and calls the bang form. - `apply_operator!(algorithm, init, op, iterate; cache!)` is the in-place form (init is the output buffer; cache! is the cache that gets mutated in place — bang suffix on the kwarg name flags the mutation at call sites). - `apply_operator_bp!` mirrors the convention: takes `cache!` as a kwarg. - `AI.step!` now calls the non-bang form with `(cache!) = state.cache` so the cache mutation is visible at the call site. - A 2-arg convenience entry `apply_operator(op, iterate; alg, cache!)` keeps `alg`-as-kwarg ergonomics for ad hoc use. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- `apply_operators(ops, iterate; op_alg, cache!)` now accepts a `cache!` kwarg matching the per-operator `apply_operator` interface, defaulting to `initialize_cache(op_alg, iterate)`. The cache is threaded through `AI.initialize_state` onto the state and mutated in place per the bang-suffix convention. - `balanced_eigh_and_inv` takes `tol` directly (other MAK pinv knobs can be added later as kwargs); call sites splat `pinv_kwargs...` into it so the BPApplyOperator-level `pinv_kwargs` NamedTuple is genuinely a forward-compatible kwargs bag. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the monolithic `apply_operator_bp!` (single function juggling
1-site and 2-site logic with `Vector{Any}` scratch and inline dimname
bookkeeping) with a thin dispatcher plus per-n methods:
- `apply_operator_bp!(init, op, iterate; ...)` computes `vs`, validates
non-empty, then calls `apply_operator_bp_nsite!(Val(length(vs)), ...)`.
- `apply_operator_bp_nsite!(::Val{N}, ...)` is a generic fallback that
throws "N-site not implemented".
- `apply_operator_bp_nsite!(::Val{1}, ...)` is the 1-site path: apply
the gate locally; only absorb envs around the norm calc when
`normalize` is requested (BP-consistent norm).
- `apply_operator_bp_nsite!(::Val{2}, ...)` is the 2-site path: absorb
envs on each endpoint, QR-trim, contract op with R1*R2, balanced
SVD back, multiply Qs and inv envs back, optionally normalize.
A `_gate_split(ψ, site, bond)` helper computes the QR-trim. We rely on
`TensorAlgebra.qr` to return something multiplicatively-identity in the
degenerate (empty codomain) case, so the call site is uniformly
`Q * R_new` with no `isnothing` branch.
Drop the `_absorb_envs(ψ, ::Nothing, _)` method — `cache!` is now
always a real cache (`initialize_cache` errors otherwise).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the `_factor_envs`, `_apply_2site_gate`, `_gate_split`, `_touches`, `neighbor_vertices`, `boundary_envs`, and `sqrt_env_and_inv` helpers and inline their bodies inside `apply_operator_bp!` / `apply_operator_bp_nsite!`. Each method now reads top-to-bottom as: collect boundary envs, filter by which endpoint they touch, factor each env into (sqrt_env, inv_sqrt_env) via `balanced_eigh_and_inv`, gauge the endpoints with `prod([...])`, QR-trim, apply the operator, balanced-SVD back, undo the gauge, optionally normalize, write back. Mirrors the structure of `ITensorNetworks.simple_update_bp`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds an in-package NestedAlgorithm pattern (initialize_subproblem / finalize_substate!) so ApplyOperators delegates each step to the per-operator algorithm via AI.solve!. apply_operator splits into a non-bang / bang pair mirroring AI.solve / AI.solve!, with signature apply_operator!(dest, op, state; ...) capturing the X*Y≈Z output-buffer convention (dest doubles as a guess for variational algorithms). BPApplyOperator is non-iterative and overloads AI.solve_loop! directly. apply_operator_bp! / _nsite! variants take both dest and state, reading from state and writing into dest. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
apply_operator[s] and apply_operator! now forward kwargs... to AI.solve / AI.solve! / AI.initialize_state instead of computing the cache! default at the wrapper layer. Each algorithm's AI.initialize_state owns its own default via initialize_cache(problem, algorithm, iterate), which now takes problem as well and is restricted to (::AI.Problem, ::AI.Algorithm, iterate). ApplyOperators gets a method that builds a representative subproblem from the first operator. apply_operator_bp! and the Val-dispatched n-site variants now restrict dest/state to AbstractTensorNetwork and op to AbstractNamedDimsArray for self-documentation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- initialize_cache for BPApplyOperator builds a trivial Vidal-gauge MessageCache: an identity 2-leg matrix on each edge of the state graph, reducing the BP simple update to a no-op gauge plus QR/SVD-based gate apply. - Replace prod([t; envs]) with prod([[t]; envs]) — the bare-vcat form tried to treat ITensor as a multi-dim array and called tail() on its LittleSet of axes; wrapping the leading tensor as a 1-element Vector dispatches cleanly. - test_apply_operator.jl: call Random.seed!() at the top of each testset to break Test's deterministic reseeding, which was causing randname() to return the same UInt64 id as already-created indices and produce operator/state index collisions. Update the bond-dim and sequence-of-gates assertions to use axes / setdiff rather than the old .underlying field and filter-on-LittleSet that no longer work. - Add Random to test/Project.toml. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduces SqrtMessageCache (wrapper around MessageCache, dispatchable on its
own type) that stores √M rather than M on each directed edge — natural for
Vidal-gauge / simple-update style BP, where the singular values on each bond
are exactly the gauge factor. With sqrt-form caching the BP simple update
contracts the env directly into the state (no per-call eigh) and only needs
a pseudoinverse for the gauge-out side.
- `SqrtMessageCache` and `sqrt_messagecache(f, edges)` in messagecache.jl,
forwarding `DataGraphs` / `Base.{keys,keytype,valtype,copy}` to the inner
cache.
- `svd_compact_named` in tensoralgebra.jl: like `MatrixAlgebraKit.svd_compact`
but returns `(U, σ, V)` for `(Abstract)NamedDimsArray` inputs with a single
shared bond name (unlike `TensorAlgebra.svd`, which inserts a 2-leg singular-
value matrix between two distinct bond names). σ is exposed so the BP code
can absorb sqrt(σ) into R_v1/R_v2 explicitly and reuse it to build the
cache update — no need for `balanced_svd` to side-channel σ.
- `invert_diagonal_message` in tensoralgebra.jl: regularized pseudoinverse of
a 2-leg diagonal named array, used for the gauge-out factor in the
sqrt-message path.
- `gauge_factors(cache, env, codomain, domain; pinv_kwargs...)` dispatches on
cache type: `balanced_eigh_and_inv` for `MessageCache`, `env + inv` for
`SqrtMessageCache`.
- `apply_operator_bp_nsite!(::Val{2}, ...)` now uses `svd_compact_named` and
inline √σ absorption, and writes fresh sqrt-messages `diagm(sqrt.(σ))` to
`cache!` on both directed edges of `(v1, v2)` so the cache stays consistent
with the new bond name and weights in `dest`.
- `initialize_cache(::BPApplyOperator, ...)` returns a `SqrtMessageCache`
with identity messages (`√I = I`).
References Fig. 5 of Tindall & Fishman, arXiv:2306.17837 for the convention.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Make `SqrtMessageCache` a standalone struct (not a wrapper) under a new
`AbstractMessageCache{T, V}` supertype; share constructors and interface
methods between `MessageCache` and `SqrtMessageCache` via an `@eval` loop.
- Inline the sqrt-message gauge-in/gauge-out logic directly in
`apply_gate_bp_nsite!`; drop `gauge_factors` and
`update_sqrt_message_cache!` helpers.
- Rename `BPApplyOperator` → `BPApplyGate` and `apply_operator_bp[_nsite]!`
→ `apply_gate_bp[_nsite]!` to emphasize that the BP backend handles a
single dense few-site gate, not a generic operator (MPO/sum-of-terms).
- Rename `sqrt_messagecache` → `sqrtmessagecache`.
- Add a TODO at the identity-message constructor for symmetric-tensor
(GradedArrays) support.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Replace `svd_compact_named` with a direct `TensorAlgebra.svd` call plus a small inline bond-unification + symmetric `√S` absorption; the wrapper duplicated `NamedDimsArrays`/`TensorAlgebra`'s existing named SVD. - Drop the unused `balanced_eigh_and_inv` and `balanced_svd` primitives and their N-D / matrix / NamedDims overloads (no `src/` callers after the sqrt-message refactor). - Delete `src/apply/tensoralgebra.jl` and fold the remaining `invert_diagonal_message` helper into `apply_operators.jl`, next to its callers in the BP simple-update path. - Remove the now-orphaned `"apply_operator primitives"` testset. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add local stand-in `inv_regularized` at three layers in `src/apply/tensoralgebra.jl`: matrix adapter over `MatrixAlgebraKit.inv_regularized`, TensorAlgebra-style N-d / perm / labelled / `Val` overloads, and a NamedDimsArrays named overload. Modeled on the existing `TensorAlgebra.svd` overload set so the file can move upstream to TensorAlgebra.jl and NamedDimsArrays.jl in follow-up PRs before this branch merges. - Drop the local `invert_diagonal_message` helper in `apply_operators.jl`; the BP simple-update path now calls `inv_regularized(env, codomain, domain; pinv_kwargs...)`, which handles non-diagonal and multi-leg messages (e.g. block-BP) via the underlying SVD/eigh pseudo-inverse. - Make the generic `finalize_substate!` fallback for `NestedAlgorithm` default to `state.iterate = substate.iterate` (the natural lifting), and remove the now-redundant `ApplyOperatorsProblem`/`ApplyOperators` override. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #114 +/- ##
==========================================
- Coverage 75.81% 73.34% -2.48%
==========================================
Files 23 22 -1
Lines 980 1118 +138
==========================================
+ Hits 743 820 +77
- Misses 237 298 +61
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
- N-d unnamed `inv_regularized(::AbstractArray, ::Val; …)` stays in this
package's namespace (intended to land as `TensorAlgebra.inv_regularized`).
- Named overload is now defined as a method of
`MatrixAlgebraKit.inv_regularized(::AbstractNamedDimsArray, …)` —
matching the convention used by `BlockSparseArrays` (extending MAK
factorizations directly for its array types). Intended to move into
`NamedDimsArrays.jl`.
- Drop the redundant `inv_regularized(::AbstractMatrix; …)` adapter; the
`tol`-kwarg-to-positional conversion is inlined where the N-d Val{}
method calls `MAK.inv_regularized` instead.
- Update `apply_operators.jl` to call the named version as
`MatrixAlgebraKit.inv_regularized(env, …)`.
- Whitelist `MAK.inv_regularized` in the Aqua piracy check via
`treat_as_own` until the upstream NDA method lands. Add
`MatrixAlgebraKit` to `test/Project.toml`.
Resolves the Aqua method-ambiguity (the named and unnamed methods now
belong to different functions in different namespaces).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 1-site normalize path was gauging in, normalizing in the BP norm, then inverting the sqrt envs to gauge back out. `norm(ψ_gauge)` is a scalar, so dividing `ψv` by it directly gives the same result without ever forming the inverses — the pseudo-inverses are only needed when the gauge-out is contracted into a transformed state (i.e. the 2-site path), not for a pure norm rescaling. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- `Val{1}` normalize path: drop the no-op dimnames-intersect filter on
the env messages; `boundary_edges(cache!, [v]; dir = :in)` already
yields edges with `dst(e) == v`, so every entry is by construction a
sqrt-message attached to `state[v]`.
- `Val{2}` path: partition the joint `boundary_edges(cache!, vs; dir = :in)`
by edge endpoint (`dst(e) == v1` vs `== v2`) instead of dimnames
intersection — same result, one fewer indirection.
- `s_v1` / `s_v2`: use `intersect(dimnames.((ψ_v_i, op))...)` instead of
`sitenames(state, v_i)`, so only the site legs `op` actually acts on
end up in the qr domain (the gate may touch a strict subset).
- qr / svd block: drop the `bond` intermediate, drop redundant `Tuple`
wraps around `setdiff` / `intersect`, switch to the 2-arg
`TA.qr(a, codomain)` form. Rename the placeholder `blob` to
`op_R_v1v2`.
- Add a 2-arg short form `MAK.inv_regularized(a, dimnames_codomain)`
that infers the domain as the complement, matching the existing 2-arg
convention of `TA.qr` / `TA.lq` / `TA.factorize` / `TA.orth` /
`TA.polar` for named arrays.
- Tidy: `import MatrixAlgebraKit as MAK` and `import TensorAlgebra as TA`
(matches the existing `AI` / `NDA` alias style); kwarg shorthand
`(; state.iterate)` in place of `iterate = state.iterate`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`intersect(dimnames.((a, b))...)` and `setdiff(dimnames.((a, b))..., c)` are concise but obscure the underlying intent; switch back to the straightforward `intersect(dimnames(a), dimnames(b))` / `setdiff(dimnames(a), dimnames(b), c)` forms. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- `TA.svd(op_R_v1v2, codomain; trunc)`: use the 2-arg form (codomain only; domain is inferred as the complement). Express the codomain as `setdiff(dimnames(R_v1), dimnames(R_v2))` — R_v1's legs not contracted away in `R_v1 * R_v2`, the cleanest framing of "the v1-side of the bipartition". Robust to gates that rename site legs: `NDA.apply` (via `get_domain_name`) maps the codomain names back to the domain names, so `dimnames(op_R_v1v2) = symdiff(R_v1, R_v2)` regardless of whether the gate renames legs. - Drop `s_v1` / `s_v2` locals: `setdiff(dimnames(ψ_v1), dimnames(ψ_v2), dimnames(op))` already removes only the v1-side op legs that appear in ψ_v1 — set-difference is a no-op on absent elements. - Normalize in the fully-gauged basis: the previous `ψ_v_i / norm(ψ_v_i)` divided in the wrong basis (post-inverse messages, where Frobenius and BP norms diverge). Replace with `R_v_i / norm(S)` so the post-update tensors have unit BP norm. `S` is the singular-value matrix from the SVD; `norm(S) = sqrt(Σσᵢ²)` is the Frobenius norm of the fully-gauged tensor at v1 and v2 (which share the same Schmidt norm). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace `R_v_i /= norm(S)` with `S /= norm(S)` immediately after the SVD. Same per-vertex BP-norm-1 effect, but the normalized `sqrtσ` now flows uniformly into both the state tensors (via `sqrt_S_left` / `sqrt_S_right`) and the new (v1, v2) cache message — keeping the post-update state and cache mutually consistent across subsequent gates. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`setdiff` returns an iterable that the downstream `MAK.inv_regularized` 3-arg method broadcasts `name.()` over, so the `Tuple` conversion adds nothing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The cache write was rebuilding the same diagonal data from scratch via `diagm(sqrtσ)` after already constructing `sqrt_S_left` with that content. Replace with `replacedimnames(sqrt_S_left, name_u => …)` — a rebind of the existing factor — so the message inherits any structure the SVD's `sqrt_S_left` carries (incl. graded / block structure when the upstream `sqrt_factorization` story lands). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ation`
Introduce two local stand-ins in `src/apply/tensoralgebra.jl`:
- `identity_map(T, codomain_axes, domain_axes)` — 2k-leg identity map,
dense-only for now. Replaces the inline `Matrix{T}(I, n, n)` reshape
in `initialize_cache`. Future home: `TensorAlgebra.jl`, with axis-type
dispatch for graded / FusionTensor specializations.
- `sqrt_factorization(::FusionStyle, A, ndims_codomain::Val)` plus a
named overload — factor a PSD named array as `(X, Y)` with `X * Y ≈ a`,
sharing a fresh-named bond. Layered through `TA.matricize` → matrix
`sqrt` → `TA.unmatricize`, mirroring the `inv_regularized` shape in
the same file. Replaces the inline `diag` / `diagm` dance for the
balanced √S split in `apply_gate_bp_nsite!(::Val{2}, …)`. Future home:
`NamedDimsArrays.jl` for the named layer, `TensorAlgebra.jl` for the
N-d layer.
Net effect on the call sites: the call sites stop materializing dense
matrix shapes directly; the dispatch hook for graded / fermionic /
FusionTensor backings now sits at the abstraction layer rather than at
the call site.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`cache![v1 => v2]` and `cache![v2 => v1]` need shared-bond legs with opposite arrows (each contracts with a different `dest` tensor). The two factors from `sqrt_factorization` carry dual arrows on `new_bond` (out on `sqrt_S_v1`, in on `sqrt_S_v2`), so each direction picks the factor whose bond arrow contracts with the receiving tensor: v1 => v2 uses `sqrt_S_v1`, v2 => v1 uses `sqrt_S_v2`. Previously both used `sqrt_S_v1`, which gives the wrong arrow on one side. Invisible for dense PSD (matrix is symmetric, arrows untracked); matters for graded / fermionic axes. Also rename `name_u` / `name_v` → `name_v1` / `name_v2` and `sqrt_S_left` / `sqrt_S_right` → `sqrt_S_v1` / `sqrt_S_v2` so the v1/v2 correspondence reads directly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…_nsite! Matches the v1/v2 naming used for `sqrt_S_v1` / `sqrt_S_v2` and `name_v1` / `name_v2` in the same block, making the v1-side / v2-side correspondence read directly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…d-ins
A few related polish items in `src/apply/tensoralgebra.jl`:
- `import TensorAlgebra as TA` alias, matching `apply_operators.jl`.
- Drop `TA.tuplemortar` wraps in favor of `TA.unmatricize(style, m,
axes_codomain, axes_domain)` directly. Same shape used by both
`inv_regularized` and `balanced_eigh_factorization`.
- Drop the 2-arg codomain-only short form of `balanced_eigh_factorization`
— for PSD inputs, the codomain/domain pairing is part of the
square-map interpretation and shouldn't be inferred by set-complement.
- Restore the N-d 2-arg `balanced_eigh_factorization(A, ndims_codomain::Val)`
convenience that auto-derives `FusionStyle` (no longer ambiguous now
that the named 2-arg form is gone).
- `collect` codomain/domain names into `Vector`s and use vector
concatenation (`[codomain_names; [new_bond]]`) instead of tuple
splat — keeps the named-list construction type-stable for non-Tuple
inputs.
Rename `sqrt_factorization` → `balanced_eigh_factorization`. Same
semantics, more accurate name: conceptually `a = U Λ U†` via eigh,
then split Λ symmetrically as `√Λ · √Λ` between the two halves. For
diagonal-Hermitian-PSD input (the BP simple-update `S`-from-SVD case),
eigh is trivial and this reduces to the per-element √ split, which is
what the local stand-in currently does. The name parallels the
operator-design synthesis captured in
`ITensorDevelopmentPlans/Projects/ITensorNetworksNext.jl/gate_application/`
(single-factor `balanced_eigh_factor`, `cholesky_factor`,
`positive_factor` umbrella).
Caller in `apply_gate_bp_nsite!(::Val{2}, …)` updated to the explicit
3-arg form: `balanced_eigh_factorization(S, (name_v1,), (name_v2,))`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the local `balanced_eigh_factorization` stand-in in favor of using NamedDimsArrays' existing `Base.sqrt(::NDA, codomain, domain)` (single matrix-sqrt named array) directly, splitting the result into two factors at the call site via `replacedimnames`. The "transposition-via-relabel" on `cache![v1 => v2]` (swap the codomain/domain name slots, then fresh) ensures each directed sqrt-message has the correct arrow direction on its matching leg; for dense backings sqrt_S equals its transpose so the swap is numerically a no-op, but the distinction matters for graded / fermionic axes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the dense `identity_map` helper with two composable primitives:
* `similar_operator(prototype, codomain_axes)` — undef
`NamedDimsOperator` with codomain = input axes, domain = same axes
fresh-renamed. Backend / eltype propagates from `prototype` via
`Base.similar`.
* `Base.one(::AbstractNamedDimsOperator)` — identity operator via
matricize → fill with `I` → unmatricize → rewrap.
`initialize_cache` reduces to `state(one(similar_operator(factor,
linkaxes(iterate, edge))))` per edge.
Whitelist `Base.one` in `test_aqua.jl` as a stand-in extension that
will move upstream into NDA's `MATRIX_FUNCTIONS` operator-extensions
loop.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`MessageCache` and `SqrtMessageCache` now subtype `AbstractDataGraph` directly rather than going through a shared `AbstractMessageCache` abstract type. Shared methods are emitted per-type via the existing `for Cache in (:MessageCache, :SqrtMessageCache)` `@eval` loop, which already wrapped the constructors and now covers the rest of the interface: key/val types, `NamedGraphs.add_edge!` / `rem_edge!` / `induced_subgraph_from_vertices`, `DataGraphs` accessors, `==`, the four `copyto!` variants, and `Base.show`. The `copyto!_messagecache` helper drops its first-arg type constraint (was `::AbstractMessageCache`, now untyped — internal helper). Once `AbstractEdgeDataGraph` lands in DataGraphs.jl (PR #121), both types can subtype that and most of the `@eval` loop can collapse into shared methods on the new abstract type. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
apply_operator/apply_operatorsfor applying a gate (or sequence of gates) to aTensorNetwork, with a belief-propagation simple-update backend (BPApplyGate).SqrtMessageCachefor storing sqrt messages, which is a more convenient form for BP gate application.MatrixAlgebraKit.inv_regularizedto a TensorAlgebra-style N-d and NamedDimsArrays-named SVD-based pseudo-inverse (local stand-in; intended to move upstream before merge).Test plan
Pkg.test()).inv_regularizedPRs againstTensorAlgebra.jlandNamedDimsArrays.jl, then drop the local stand-in.GradedArrays).🤖 Generated with Claude Code