Repository navigation
Add the Modulus option to RowReduce, NullSpace, MatrixRank, Inverse and LinearSolve - #2010
Conversation
…nd LinearSolve With Modulus -> p for a prime p, these compute over the integers mod p with plain Gaussian elimination on Python ints. Entries may be integers or rationals whose denominator is invertible mod p. Modulus -> 0 keeps ordinary arithmetic; a modulus that is not a prime, or a symbolic entry, leaves the expression unevaluated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Strickland's LambdaAlgebra.m, run in WMA, shows that NullSpace with Modulus gives the vectors in decreasing order of their free column, so do the same. The random tests assigned x, m and p in the shared test session, which broke later tests that use x as a symbol; use Module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| from mathics.core.list import ListExpression | ||
| from mathics.core.symbols import SymbolList | ||
|
|
||
| ModMatrix = List[List[int]] |
There was a problem hiding this comment.
This name seems specialized, but the concept isn't - it is a matrix in nested list form.
BTW, whenever you see List or Tuple, that should now be list and tuple since we no longer support Python 3.9 where it had to be List, and Tuple.
There was a problem hiding this comment.
Done in d141405. The type is now NestedListMatrix = list[list[Any]] in mathics.core.convert.matrix, and List/Tuple are now list/tuple.
| return rows | ||
|
|
||
|
|
||
| def to_mathics_matrix(rows: ModMatrix) -> ListExpression: |
There was a problem hiding this comment.
Given that this is really a matrix in list-of-lists form, this conversion function, which is also generic, should be moved under mathics.core.convert somewhere.
There was a problem hiding this comment.
Moved to mathics.core.convert.matrix as to_mathics_matrix(rows, elements_conversion_fn=from_python). It is built on to_mathics_list, and the entry conversion is a parameter, so it is not tied to integers.
…rsion As suggested in review: the matrix type is a matrix in nested list form, not something modular, so it is now NestedListMatrix in mathics.core.convert.matrix, together with to_mathics_matrix(), which turns such a matrix into a Mathics3 List of Lists. Use list and tuple instead of typing.List and typing.Tuple. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RowReduce,NullSpace,MatrixRank,InverseandLinearSolvedid not accept theModulusoption, so for exampleNullSpace[{{1, 1}, {1, 1}}, Modulus -> 2]stayed unevaluated. This adds it for a prime modulus, as described in the WMA docs ("If p is zero, ordinary arithmetic is used").What it does. With
Modulus -> pthe matrix entries are reduced modpand the computation is plain Gaussian elimination on Python ints (new modulemathics/eval/numbers/linalg_modular.py). Entries may be integers, or rationals whose denominator is invertible modp. Results are integers in0..p-1:Conventions:
RowReducegives the reduced row echelon form, as withoutModulus.NullSpacegives one vector per non-pivot column, with 1 in that column and 0 in the other non-pivot columns, in decreasing order of that column. That order is what WMA gives: running Strickland'sLambdaAlgebra.m(below) reproduces his WMA-computed homology bases exactly only with this order. The exactNullSpace(withoutModulus) currently lists them in increasing order; I left that alone here.LinearSolvesets the free variables to 0.Inverse::singandLinearSolve::nosolmessages.What it does not do. A modulus that is not a prime (WMA says the computation "may fail" then), a non-integer modulus, a symbolic entry, or a denominator divisible by
pleave the expression unevaluated.Modulus -> 0keeps the current code path.Tests. Doc examples, plus
test_linalg_modulusandtest_linalg_modulus_randomintest/builtin/numbers/test_linalg.py; the random test checks the defining properties (rank + nullity,m . ns == 0,m . x == b,m . Inverse[m] == 1mod p) on 60 random matrices. pytest and the doctests give the same results as on master; the only failures are environmental ones that also fail on master. mypy is clean.Motivation and a larger check: Strickland's
LambdaAlgebra.m(https://strickland1.org/toda/) computes the homology of the mod-2 lambda algebra with all five functions andModulus -> 2, and hisLambdaData.mstores the results computed in WMA. With this PR (and theTransposeandMapAtfixes in #2007 and #2008) Mathics3 reproduces exactly, in the same order, his homology, boundary and non-boundary bases and his canonical forms: 218 of the 296 tridegrees inLambdaData.m(4225 canonical forms), with no difference. The remaining 78 are too slow to finish under Mathics3 in reasonable time; the largest would take days. For comparison, under Wolfram Engine 15 the same script computes all 296 in under a minute and matchesLambdaData.mexactly.🤖 Generated with Claude Code