Skip to content

Make det, transpose, trace and an entry nodes that apply to a matrix argument - #2436

Open
Rafael-SOWNet wants to merge 1 commit into
masterfrom
feature/matrix-operation-nodes
Open

Rafael-SOWNet wants to merge 1 commit into
masterfrom
feature/matrix-operation-nodes

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

Closes #2427.

det, transpose, trace and an entry A[k, l] are now nodes. They can be written of a name, such as det(A), transpose(A) * B, trace(A * B) or A[1, 2], and are carried out once the name is a matrix: by substitution, simplification, evaluation, and compilation over T[,] (#2429).

  • Parsing: det, transpose and trace of a name were read as products on 2.6.0, so det(A) was det * A.

  • Indices count from 1, as a_ij does, and as in Mathematica, Maple, Maxima, MATLAB and Julia. The C# Matrix indexer still counts from 0, as C# does, so M[k, l] in an expression is matrix[k - 1, l - 1] in code. The syntax page says so.

  • No value is invented: a non-square matrix has no determinant or trace, and an index out of range or not whole names no entry. Each stays unevaluated.

  • Rewrites: transpose(transpose(A)) → A, det(transpose(A)) → det(A), trace(transpose(A)) → trace(A) and transpose(A)[k, l] → A[l, k].

  • Derivatives are taken through the matrix for transpose, trace and an entry. The determinant keeps its derivative node, since Jacobi's formula needs an adjugate.

  • Compiled:

    • transpose as a new array;
    • the determinant by Bareiss elimination, exact over long;
    • the trace;
    • an entry, with its indices checked to be whole and in range when the delegate is called.

    Known shapes are checked at Compile.

  • API: MathS.Matrices.Determinant, Transpose, Trace and Entry. They are recorded in PublicApi.txt with the four node records and the compiled helpers.

Two wrong answers that these nodes would have made easy to reach are fixed. Both come from a name having no type yet (#1237):

  • Matrices were treated as commuting.
    • transpose(A) * A - A * transpose(A) simplified to 0, and transpose(A) * B to B * transpose(A).
    • A product with a transpose in it is now set aside while the rest is simplified, then put back in the order written.
    • One cost: transpose(A)*B + transpose(A)*C is no longer factored.
    • Plain A*B - B*A still gives 0, since nothing yet says A is a matrix. That waits for Typed variables #1237.
  • A name beside a written matrix was read as a number.
    • det(A * [[2, 0], [0, 3]]) came out as 6 * A^2.
    • Such an argument is now carried out only once the name is a matrix.
    • A name used only as an entry is unchanged: det([[x, 1], [2, x]]) is still x^2 - 2.
Input 2.6.0 now
"det(A)" the product det * A det(A), a Determinantf
"det(A)" with A = [[1, 2], [3, 4]], evaluated [[det, det * 2], [det * 3, det * 4]] -2
"transpose(A) * B" transpose * A * B transpose(A) * B
"trace([[1, 2], [3, 4]])" trace * [[1, 2], [3, 4]] 1 + 4
"A[1, 2]", "[[1, 2], [3, 4]][2, 1]" throw UnhandledParseException A[1, 2]; 3
"det(5)" det * 5 throws InvalidArgumentParseException
"det(x * [[1, 2], [3, 4]])" det * x * [[1, 2], [3, 4]] left as written: x may stand for a matrix

The rows are in BREAKING-CHANGES.md, measured on the 2.6.0 package. #2180's unshipped transpose(x) row, which no longer throws, is updated. The parser was regenerated with the vendored ANTLR; regenerating the unmodified grammar first gave an empty diff.

Checked on this branch:

  • Tests: UnitTests 19497 passed, plus the MCP, Terminal, InteractiveWrapper and F# wrapper suites, and the AOT smoke test. 60 new tests check values against a determinant expanded by definition, at real, negative and complex 2×2 and 3×3 matrices, and compiled values against evaluation.
  • Harnesses: BoundCheck, RootCheck, CasBench, PropCheck, SimpSweep, RuleCheck, CanonCheck and Confluence all pass. limitcheck is not run, since nothing here touches limits.

🤖 Generated with Claude Code

…argument

det(A) of a symbol was refused at parsing, transpose(x) too, trace(A) was the product
trace * A, and A[i, j] did not parse. Each of the four is now a node over what it is
applied to, carried out once that is a matrix: by Substitute, Simplify, Evaled and a
compiled delegate taking T[,]. Of a matrix written out each is still computed as it is
parsed, as det and transpose were, so nothing #2180 answered moves but transpose(x).

- Determinantf, Transposef, Tracef and MatrixEntryf, with printing that parses back,
  LaTeX (\det, ^{\mathrm{T}}, \operatorname{tr}, a subscript), SymPy, substitution,
  sorting, serialization, and MathS.Matrices.Determinant, Transpose, Trace and Entry.
- An entry counts its row and column from 1, as a_ij does: [[1, 2], [3, 4]][2, 1] is 3.
  The brackets follow an atom directly, which did not parse before.
- A non-square matrix has no determinant and no trace, and an index out of range or not
  whole names no entry: the node is left as it is, never a number. Written out, each is
  refused at parsing, as det of a non-square matrix was. A number, a statement or a set
  is no matrix and is refused.
- det(transpose(A)) is det(A), trace(transpose(A)) is trace(A), transpose(transpose(A))
  is A and transpose(A)[k, l] is A[l, k].
- The transpose, the trace and an entry are differentiated through the matrix; the
  determinant keeps its derivative node, Jacobi's formula needing the adjugate.
- Compiled: the transpose, Bareiss' fraction-free determinant with the largest pivot
  where the elements have a size (exact over long and int), the trace, and the entry
  with its indices checked whole and in range when called. Shapes written into the
  expression are checked at Compile.
- A product with a transpose in it is a product of matrices, and Simplify read it as
  commutative: transpose(A) * A - A * transpose(A) simplified to 0, and transpose(A) * B
  printed as B * transpose(A). Such a product is set aside as a name of its own while
  the rest is simplified, and put back with each factor simplified in place; the
  canonical sort and the print order leave it as written.
- A name beside a written matrix may stand for a matrix, and simplification reads it as
  a number: det(A [[2, 0], [0, 3]]) was 6 A^2 at parsing, and a compiled delegate
  computed that. Such an argument is not carried out, at parsing, in evaluation or by
  Simplify, until the name is a matrix; det([[x, 1], [2, x]]), whose names are entries,
  is x^2 - 2 as before.

Measured: the new MatrixOperationNodesTest compares every value with one computed from
the entries, at real, negative and non-real matrices, 2x2 and 3x3, and every compiled
value with evaluation, including a matrix argument beside a written matrix, which the
base commit's SimplifiedAroundMatrixArguments leaves to these nodes. The 2.6.0 values in BREAKING-CHANGES.md are measured on the
2.6.0 package.

Closes #2427.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.70968% with 35 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.88%. Comparing base (ff72b6f) to head (e11037a).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...luation/Evaluation.Omni/Evaluation.Omni.Classes.cs 85.41% 5 Missing and 2 partials ⚠️
...unctions/Compilation/IntoLinq/TensorCompilation.cs 94.44% 1 Missing and 4 partials ⚠️
...AngouriMath/Functions/TreeAnalyzer/Sort.Classes.cs 0.00% 4 Missing ⚠️
Sources/AngouriMath/Core/Antlr/ParsingHelpers.cs 91.42% 1 Missing and 2 partials ⚠️
...ngouriMath/Functions/Continuous/Differentiation.cs 40.00% 0 Missing and 3 partials ⚠️
...ath/Functions/Simplification/ProductsOfMatrices.cs 94.23% 1 Missing and 2 partials ⚠️
Sources/AngouriMath/Functions/Substitute.cs 25.00% 0 Missing and 3 partials ⚠️
.../AngouriMath/Core/Antlr/AngouriMathBaseListener.cs 0.00% 2 Missing ⚠️
...Math/Functions/Simplification/Patterns/Patterns.cs 66.66% 1 Missing and 1 partial ⚠️
...ouriMath/Functions/Simplification/Simplificator.cs 50.00% 1 Missing and 1 partial ⚠️
... and 1 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2436      +/-   ##
==========================================
+ Coverage   86.85%   86.88%   +0.02%     
==========================================
  Files         312      314       +2     
  Lines       69709    70086     +377     
  Branches    20378    20476      +98     
==========================================
+ Hits        60543    60891     +348     
- Misses       4923     4936      +13     
- Partials     4243     4259      +16     
Flag Coverage Δ
cpp 37.77% <ø> (ø)
csharp 87.41% <88.70%> (+0.02%) ⬆️
fsharp 32.97% <ø> (ø)
interactive 39.81% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
Sources/AngouriMath/Convenience/MathS.cs 90.63% <100.00%> (+0.11%) ⬆️
Sources/AngouriMath/Core/Antlr/AngouriMathLexer.cs 99.21% <ø> (+<0.01%) ⬆️
...ources/AngouriMath/Core/Antlr/AngouriMathParser.cs 87.61% <ø> (-0.22%) ⬇️
Sources/AngouriMath/Core/Domains.Classes.cs 100.00% <100.00%> (ø)
...ore/Entity/Omni/Entity.MatrixOperations.Classes.cs 100.00% <100.00%> (ø)
...Math/Core/Transformations/Matching/MatchPattern.cs 86.45% <100.00%> (+0.08%) ⬆️
...Math/Core/Transformations/Matching/MatchedRules.cs 99.55% <100.00%> (-0.01%) ⬇️
...ctions/Compilation/IntoLinq/CompilationProtocol.cs 94.00% <100.00%> (+0.02%) ⬆️
...iMath/Functions/Output/Latex/Latex.Omni.Classes.cs 98.24% <100.00%> (+0.13%) ⬆️
...Functions/Output/ToString/ToString.Omni.Classes.cs 98.57% <100.00%> (+0.18%) ⬆️
... and 12 more

... and 9 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

det, transpose, trace and an entry of a name for a matrix

1 participant