Skip to content

Fix #350: tensor_pow contract — rank-2 only, integer exponents, working negative powers - #408

Open
petlenz wants to merge 3 commits into
fix-353-t2s-contraction-sequencesfrom
fix-350-tensor-pow-contract
Open

Fix #350: tensor_pow contract — rank-2 only, integer exponents, working negative powers#408
petlenz wants to merge 3 commits into
fix-353-t2s-contraction-sequencesfrom
fix-350-tensor-pow-contract

Conversation

@petlenz

@petlenz petlenz commented Jul 24, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #350. Stacked on #407.

Before After
eval(pow(X,-1)) returned X itself (no inversion) inverts: 0.5 for diag entry 2
pow(X, 0.5) evaluated to the identity (int truncation) factory rejects; evaluator throws on non-integer values
diff(pow(X,-2), X) → silent 0{4} not_implemented_error pointing at inv(pow(A,n)) (which differentiates correctly today)
pow(C4, 0)rank-2 identity for a rank-4 operand rank gate at the factory (invalid_expression_error)

Design

Construct-early philosophy per the #383 ceilings epic: the factory gates rank (2 only — matching dev/sym/trans and #192's inv fix) and integer-constant exponents; the evaluator and diff visitors keep defense-in-depth guards for trees built by other paths. Negative integer powers now evaluate correctly (invert the accumulated power); their differentiation stays explicit-unsupported rather than silently wrong — the inv(pow(A,n)) spelling covers that need (lock-in included).

Tests

3 lock-ins: gates, numeric inverse evaluation (n=−1, −2), diff throw + supported spelling. Full suite: 2449/2449 pass. gcc-14 clean.

@petlenz
petlenz force-pushed the fix-353-t2s-contraction-sequences branch from 2b561b2 to c0f0110 Compare July 25, 2026 12:35
@petlenz
petlenz force-pushed the fix-350-tensor-pow-contract branch from d0f0dd4 to c7756aa Compare July 25, 2026 12:38
@petlenz
petlenz force-pushed the fix-353-t2s-contraction-sequences branch from c0f0110 to 84530ed Compare July 25, 2026 13:38
@petlenz
petlenz force-pushed the fix-350-tensor-pow-contract branch from c7756aa to 74296dc Compare July 25, 2026 13:43
@petlenz
petlenz force-pushed the fix-353-t2s-contraction-sequences branch from 84530ed to 2a4b143 Compare July 25, 2026 14:16
@petlenz
petlenz force-pushed the fix-350-tensor-pow-contract branch from 74296dc to 7558c86 Compare July 25, 2026 14:16
@petlenz
petlenz force-pushed the fix-353-t2s-contraction-sequences branch from 2a4b143 to c0cd24e Compare July 25, 2026 22:33
@petlenz
petlenz force-pushed the fix-350-tensor-pow-contract branch 2 times, most recently from fcb5cac to b0e62eb Compare July 26, 2026 12:14
@petlenz
petlenz force-pushed the fix-353-t2s-contraction-sequences branch from 3d0c609 to c8fb55c Compare July 26, 2026 12:43
@petlenz
petlenz force-pushed the fix-350-tensor-pow-contract branch 2 times, most recently from 1a53367 to 30e5326 Compare July 26, 2026 17:18
@petlenz
petlenz force-pushed the fix-353-t2s-contraction-sequences branch 2 times, most recently from 1a17e02 to 3a5ad33 Compare July 26, 2026 17:42
@petlenz
petlenz force-pushed the fix-350-tensor-pow-contract branch 2 times, most recently from 1d32d14 to 7a2fa03 Compare July 26, 2026 18:16
@petlenz
petlenz force-pushed the fix-353-t2s-contraction-sequences branch 2 times, most recently from 05cdfad to c4a3309 Compare July 26, 2026 18:40
@petlenz
petlenz force-pushed the fix-350-tensor-pow-contract branch from 7a2fa03 to 679576e Compare July 26, 2026 18:40
petlenz added 3 commits July 26, 2026 20:58
…ng negative powers

tensor_pow was broken beyond positive-integer/rank-2 use, each layer
failing differently and silently: the evaluator cast the exponent with
static_cast<int> (pow(X, 0.5) truncated to the identity) and looped
k < abs(n) with no inversion (pow(X, -1) evaluated to X itself); both
diff visitors' product-rule loops never ran for n < 0, silently
coercing the tangent to zero; and the factory accepted any rank while
hard-coding a rank-2 identity for pow(C4, 0).

- Factory: rank-2 gate and integer-constant exponent gate
  (invalid_expression_error; fractional powers belong to the isotropic
  function API, #227).
- Evaluator: non-integer exponent value throws evaluation_error;
  n < 0 inverts the accumulated power via tmech::inv.
- Both diff visitors: n < 0 throws not_implemented_error pointing at
  the inv(pow(A, n)) spelling, which differentiates correctly today.

Signed-off-by: petlenz <peterlenz89.pl@gmail.com>
…nstants

- The rank gate was factory-only: tensor_rebuild_visitor recreates
  tensor_pow ungated, so substitute(pow(X,2), X, C_rank4) evaluated
  into heap corruption (rank-6 contraction written into a rank-4
  buffer). The evaluator now throws on rank != 2.
- The exponent round-check gains a range bound so the int cast stays
  defined for huge/inf exponent values (would abort under the fatal
  UBSan leg).
- The factory's integer gate now also sees negation-wrapped constants
  (pow(X, neg(0.5)) previously slipped to evaluation).
Regression test covers the substitution route and the wrapped
exponent.

Signed-off-by: petlenz <peterlenz89.pl@gmail.com>
… bound

The factory's integer gate unwrapped only one scalar_negative layer,
so pow(X, neg(neg(0.5))) constructed and failed only at evaluation;
the gate now strips any negation depth before the literal check,
matching try_int_constant. The evaluator's exponent bound tightens
from 1e9 to 1e6: the cast was defined at 1e9 but admitted a ~4-minute
single-expression evaluation.

Signed-off-by: petlenz <peterlenz89.pl@gmail.com>
@petlenz
petlenz force-pushed the fix-350-tensor-pow-contract branch from 679576e to 9fa3067 Compare July 26, 2026 19:03
@petlenz
petlenz force-pushed the fix-353-t2s-contraction-sequences branch from c4a3309 to 3eb5bf3 Compare July 26, 2026 19:03
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