Skip to content

Rank-4 tensor_inv in scalar-arg diff visitor (#287) - #291

Merged
petlenz merged 3 commits into
mainfrom
287-scalar-arg-diff-rank4-inv
Jun 10, 2026
Merged

Rank-4 tensor_inv in scalar-arg diff visitor (#287)#291
petlenz merged 3 commits into
mainfrom
287-scalar-arg-diff-rank4-inv

Conversation

@petlenz

@petlenz petlenz commented Jun 9, 2026

Copy link
Copy Markdown
Member

Summary

Closes part of #287. The scalar-arg diff visitor (tensor_differentiation_wrt_scalar) now handles rank-4 tensor_inv via the symbolic Magnus formula:

```
d(C^{-1})/ds = -C^{-1} : (dC/ds) : C^{-1}
```

The formula's shape doesn't change between rank 2 and rank 4 — only the contraction layout (1-index ↔ 2-index). Unlike the tensor-arg visitor, which needs separate sym/skew/Magnus kernel variants because differentiating w.r.t. a rank-2 X expands the rank, the scalar-arg derivative dA/ds has the same rank as A, so the same formula applies regardless of algebraic class. The evaluator already dispatches on annotation at evaluation time via the inner tensor_inv's space tag.

What's NOT in this PR

The companion tensor_pow case in #287 (non-integer / non-constant exponent) requires log(A) for a tensor A, which is on the #227 wishlist. The throw remains; comment in the visitor body sharpened to point at #227.

Test plan

  • TensorDiffWrtScalarTest.InvRank4ZeroDerivativeWhenSIndependent — singleton-aware zero-suppression still fires (parity with rank 2).
  • TensorDiffWrtScalarTest.InvRank4ExercisedDirectly — non-zero diff path, rank/dim lock-in via make_expression<tensor_inv>(s * D) to bypass the inv(α·A) → inv(A)/α factory fold.
  • TensorDiffWrtScalarTest.InvRank3ThrowsNotImplemented — belt-and-braces guard for direct make_expression<tensor_inv> constructions at unsupported rank.
  • Full suite: 1321/1321 passing (+3 from prior 1318).

No numerical lock-in is added: rank-4 tmech::inv requires the post-Sep-2025 inverse_wrapper_base rewrite which is being enforced by #289 (parallel work) — evaluating rank-4 inv against the stale system tmech would NaN. The tests verify structure (rank, dim, non-zero); end-to-end numerical verification rides on #289.

petlenz added 3 commits June 10, 2026 19:40
The Magnus formula `d(C^{-1})/ds = -C^{-1} : (dC/ds) : C^{-1}` extends
naturally from rank 2 to rank 4 in the scalar-arg setting:

  rank 2:  -invA_{im} · dA_{mn} · invA_{nj}
           two single-index contractions on (2)↔(1)
  rank 4:  -invA_{ijmn} · dA_{mnpq} · invA_{pqkl}
           two two-index contractions on (3,4)↔(1,2)

Unlike the tensor-arg visitor — which has sym/skew/Magnus kernel
variants because differentiating w.r.t. a rank-2 X expands the rank —
the scalar-arg derivative dA/ds has the SAME rank as A, so the same
Magnus formula applies independent of algebraic class. The evaluator
dispatches on annotation at evaluation time via the inner tensor_inv's
space tag; the symbolic AST is the same either way.

Rank-2 path unchanged. Rank != 2 and != 4 keep the not_implemented
throw — the inv() factory rejects them already, so the visitor's guard
catches only direct `make_expression<tensor_inv>` constructions.

3 new tests in TensorDiffWrtScalarTest:
- InvRank4ZeroDerivativeWhenSIndependent — pass-5 singleton-aware
  guard still fires (zero-suppression on s-independent inner).
- InvRank4ExercisedDirectly — non-zero diff path, rank/dim lock-in.
- InvRank3ThrowsNotImplemented — belt-and-braces guard.

The companion deferred case in #287 (non-integer / non-constant
tensor_pow exponent) remains blocked on tensor log() from #227.

Full suite: 1321/1321 passing (+3 from prior 1318).

Signed-off-by: petlenz <peterlenz89.pl@gmail.com>
Add the structural hash-equality lock-in the reviewer flagged as a
MEDIUM gap (`InvRank4StructuralLockIn`): rebuild the expected Magnus
formula `-invA : dA : invA` by hand and assert hash equality with the
visitor's output. This protects against silent reordering of the
contraction layout — e.g. swapping `{3,4}↔{1,2}` to `{1,2}↔{3,4}`,
both legal inner-product calls for unsymmetric inputs but producing a
structurally different AST. Numerical eval is intentionally NOT added
here: rank-4 `tmech::inv` requires the post-`db5d8aa` rewrite, which
is being enforced by parallel work in #289; once #289 lands the rank-4
inv eval becomes safe to lock numerically and we can add a separate
end-to-end test then.

The rank-3 wrapper-silence finding from the reviewer (`tensor_inv`
wrapper ctor accepts any rank, factory rejects only rank ∉ {2,4})
is filed as separate issue #292 — out of scope for this PR.

Full suite: 1322/1322 passing (+1 from prior 1321).

Signed-off-by: petlenz <peterlenz89.pl@gmail.com>
Signed-off-by: petlenz <peterlenz89.pl@gmail.com>
@petlenz
petlenz force-pushed the 287-scalar-arg-diff-rank4-inv branch from 6c3f75c to 59551f2 Compare June 10, 2026 17:41
@petlenz
petlenz merged commit f3e799e into main Jun 10, 2026
23 checks passed
@petlenz
petlenz deleted the 287-scalar-arg-diff-rank4-inv branch June 10, 2026 17:43
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