Skip to content

Fix #359: inv() skew guard only rejects rank-2 matrix products - #435

Merged
petlenz merged 1 commit into
mainfrom
fix-359-inv-skew-guard
Sep 16, 2026
Merged

petlenz merged 1 commit into
mainfrom
fix-359-inv-skew-guard

Conversation

@petlenz

@petlenz petlenz commented Sep 15, 2026

Copy link
Copy Markdown
Member

Closes #359.

The inv() singularity guard rejected operands that are generically invertible.

  • is_provably_skew matched any inner_product with P_skew on the left. It now requires the exact skew() projection: inner_product(P_skew, {3,4}, X, {1,2}) with rank-2 X (via as_projector_contraction). inner_product(P_skew, {1,3}, X, {1,2}) is not skew in general.
  • contains_skew_factor recursed through every tensor_mul and inner_product. The determinant argument det(M1·M2) = det(M1)·det(M2) = 0 only holds for products of rank-2 matrices, so it now recurses only through tensor_mul chains whose children are all rank-2, and single-index contractions of two rank-2 operands (a product of the operands or their transposes). Scalar multiples and negations are unchanged.

inv(inner_product(C, {3,4}, skew(A), {1,2})) with rank-4 C is no longer rejected. inv() is the only caller of the classifier.

Tests (TensorSpacePropagationTest):

  • InvAllowsRank4ContractionOfSkew: C4:skew(X) and C4:W (annotated skew) are accepted.
  • SkewProjectorWithOtherIndicesIsNotSkew: P_skew{1,3}:X is not classified skew and inv accepts it.
  • SkewClassificationMatchesNumerics: with random data in 3D, det(C4:skew(A)) != 0 and inv evaluates to its inverse, P_skew{1,3}:A is not skew, skew(A) is skew, and B·skew(A) and inner(B{1}, skew(A){2}) are singular.
  • InvRejectsMatrixProductsWithSkewFactor: skew(X), skew(X)·B and a single-index contraction with skew(X) are still rejected.

Negative control: against the classifier on main, the first three fail; the rejection test passes on both. No existing test encoded the over-general rejection. Full suite 2350/2350 (gcc-14 Debug, -Werror except the pedantic/deprecated-declarations warnings already on main).

is_provably_skew now matches only the skew() projection itself,
inner_product(P_skew, {3,4}, X, {1,2}) with rank-2 X, instead of any
contraction with P_skew on the left.

contains_skew_factor only recurses where det(M1·M2) = det(M1)·det(M2)
applies: tensor_mul chains whose children are all rank-2, and
single-index contractions of two rank-2 operands. inv(C:skew(A)) with
rank-4 C is generically invertible and no longer rejected.

Tests in TensorSpacePropagationTest: rank-4 contraction and other P_skew
contraction patterns are accepted, rank-2 products with a skew factor
are still rejected, and a numerical check confirms det(C:skew(A)) != 0,
P_skew{1,3}:A is not skew, and B·skew(A) is singular.

Signed-off-by: petlenz <peterlenz89.pl@gmail.com>
@petlenz
petlenz merged commit 55e8294 into main Sep 16, 2026
27 checks passed
@petlenz
petlenz deleted the fix-359-inv-skew-guard branch September 16, 2026 22:21
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.

inv() skew-singularity guard false positives: inv(C : skew(A)) rejected though generically invertible; is_provably_skew ignores contraction indices

1 participant