Compute the determinant without dividing by its pivots (#992) - #998
Merged
Conversation
Matrix.Determinant was computed by Gaussian elimination, which leaves the pivots as literal divisions, so the expression it returned was undefined wherever a pivot vanishes -- at points where the determinant itself is perfectly well defined. Substituting [[0, 1, 2], [3, 4, 5], [6, 7, 8]] into the general 3x3 determinant gave NaN, which asserts the value does not exist; it is 0. The determinant of a matrix over a commutative ring is a polynomial in its entries, so Laplace expansion needs no condition at all. It is also what the property's own documentation and the comment above it already claimed was in use. It is not a performance trade either way. Property only, both arms built from source: Laplace returns a smaller expression at every size measured (5021 against 13673 nodes at 6x6), and on numeric matrices it is the faster of the two by a wide margin -- 8x8 returns in 358 ms where the elimination does not return inside 120 s. The practical ceiling on a numeric matrix moves from 7x7 to 10x10. A fraction-free elimination would raise it further, and is worth having separately. Suite 7375 passed, 0 failed. Corpus unchanged at 116/119 with 0 wrong, no case's verdict or answer altered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbKcbJP266A3EGyQ5kq7Ru
Collaborator
Author
|
Filed the follow-up I offered above: #999, for a fraction-free (Bareiss) elimination to raise the practical size ceiling. It carries the same measured table and is explicit that this PR is not blocked on it — #998 makes every size that previously worked work better and adds three usable sizes on top, and #999 is about extending the range rather than repairing it. |
This was referenced Aug 22, 2026
…ision-free-992 # Conflicts: # BREAKING-CHANGES.md
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.
Closes #992.
The defect
Matrix.Determinantis computed by Gaussian elimination, which leaves the pivots as literal divisions. The expression it returns is therefore undefined wherever a pivot vanishes — at points where the determinant itself is perfectly well defined.x = 0is an ordinary point of that matrix. At 3×3 it stops being an edge case, because the denominator isa ^ 4 * (a * e - b * d)and two separate conditions have to miss:[[a, b, c], [d, e, f], [g, h, i]].Determinant[[0, 1, 2], [3, 4, 5], [6, 7, 8]]NaN0[[1, 2, 3], [2, 4, 6], [1, 1, 1]]NaN0[[1, 2, 3], [4, 5, 6], [7, 8, 10]]-3-3[[2, 1, 0], [1, 2, 1], [0, 1, 2]]44Two of four ordinary matrices, and the first is the singular example every linear-algebra course opens with. Both wrong answers are silent: the call succeeds and returns
NaN, which is exactly what a caller checking for singularity was looking for.AGENTS.mdis explicit thatNaNmeans this does not exist, and the determinant does exist.The fix
The determinant of a matrix over a commutative ring is a polynomial in its entries, so Laplace expansion — which never divides — needs no condition at all. One call site changes.
It is also what the property already claimed. Its
<summary>says "Finds the symbolical determinant via Laplace's method" and the comment above it says "We do not need to use Gaussian elimination here since we anyway get N! memory use"; only the call disagreed, and has since#404.This is not a performance trade
That was the thing worth checking before proposing it, so I measured rather than assumed. Property only — no
Simplifyon top — both arms built from source on the same machine:Laplace returns a smaller expression at every size, and is dramatically faster on numeric matrices — the elimination builds a symbolic quotient that
InnerSimplifiedthen has to grind down, which is why an 8×8 of small integers does not return inside two minutes today.Laplace is
O(n!), and that is real, but a fully symbolicn × ndeterminant hasn!terms however it is computed, so it is the size of the answer rather than an overhead. The practical ceiling on a numeric matrix moves from 7×7 to 10×10 — 11×11 does not return, where under the elimination 8×8 already did not.A fraction-free elimination (Bareiss) is
O(n^3)and would raise that ceiling further. It is worth having, but it is a separate change and the correctness fix is not blocked on it — I am happy to open an issue for it.Measured
MatrixTest. Controlled: with the call reverted toDeterminantGaussianSafeDivisionthey are 5 failed, 4 passed, the four being the controls that should pass either way.BREAKING-CHANGES.mdentry with both values measured on a build of each arm.Against the other open PRs
Derived with
git merge-tree --write-tree, not assumed:fix/bound-name-must-be-symbolicBREAKING-CHANGES.mdonlyconstant-node-984BREAKING-CHANGES.mdonlyfix/special-set-membership-995BREAKING-CHANGES.mdonlyNo source file conflicts with any of them — this touches
Entity.Matrix.cs, which none of the others do. Whichever merges last takes the mechanicalBREAKING-CHANGES.mdround and I will do it.🤖 Generated with Claude Code
https://claude.ai/code/session_01KbKcbJP266A3EGyQ5kq7Ru