Skip to content

Commit 14da417

Browse files
author
Release Manager
committed
gh-37497: remove zombie code We remove zombie code for solving linear systems over a finite field, which was (likely accidentally) created in #23214, but leads to errors when solving sparse linear equations over finite fields. This does not quite fix the issue, because we now fall back to generic code. Fixes #28586 URL: #37497 Reported by: Martin Rubey Reviewer(s): Matthias Köppe
2 parents 59ced5e + 1e66857 commit 14da417

File tree

2 files changed

+7
-299
lines changed

2 files changed

+7
-299
lines changed

src/sage/matrix/matrix2.pyx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,13 @@ cdef class Matrix(Matrix1):
871871
Traceback (most recent call last):
872872
...
873873
ValueError: matrix equation has no solutions
874+
875+
Check that :issue:`28586` is fixed::
876+
877+
sage: m = matrix(GF(3), 2, 2, [1,2,2,0], sparse=True)
878+
sage: v = vector(GF(3), [1,1])
879+
sage: m.solve_right(v)
880+
(2, 1)
874881
"""
875882
try:
876883
L = B.base_ring()

src/sage/matrix/matrix_modn_sparse.pyx

Lines changed: 0 additions & 299 deletions
Original file line numberDiff line numberDiff line change
@@ -870,302 +870,3 @@ cdef class Matrix_modn_sparse(Matrix_sparse):
870870
return d
871871
else:
872872
raise ValueError("no algorithm '%s'"%algorithm)
873-
874-
def _solve_right_nonsingular_square(self, B, algorithm=None, check_rank=False):
875-
r"""
876-
If self is a matrix `A`, then this function returns a
877-
vector or matrix `X` such that `A X = B`. If
878-
`B` is a vector then `X` is a vector and if
879-
`B` is a matrix, then `X` is a matrix.
880-
881-
.. NOTE::
882-
883-
DEPRECATED. In Sage one can also write ``A \ B`` for
884-
``A.solve_right(B)``, i.e., Sage implements the "the
885-
MATLAB/Octave backslash operator".
886-
887-
INPUT:
888-
889-
890-
- ``B`` - a matrix or vector
891-
892-
- ``algorithm`` - one of the following:
893-
894-
- ``'linbox'`` or ``'linbox_default'`` - (default) use LinBox
895-
and let it chooses the appropriate algorithm
896-
897-
- ``linbox_dense_elimination'`` - use LinBox dense elimination
898-
899-
- ``'linbox_sparse_elimination'`` - use LinBox sparse elimination
900-
901-
- ``'linbox_ blackbox'`` - LinBox via a Blackbox algorithm
902-
903-
- ``'linbox_wiedemann'`` - use LinBox implementation of
904-
Wiedemann's algorithm
905-
906-
- ``'generic'`` - use the Sage generic implementation
907-
(via inversion)
908-
909-
- ``check_rank`` - whether to check that the rank is maximal
910-
911-
OUTPUT: a matrix or vector
912-
913-
EXAMPLES::
914-
915-
sage: A = matrix(ZZ, 3, [1,2,3,-1,2,5,2,3,1], sparse=True)
916-
sage: b = vector(ZZ, [1,2,3])
917-
sage: x = A.solve_right(b)
918-
sage: x
919-
(-13/12, 23/12, -7/12)
920-
sage: A * x
921-
(1, 2, 3)
922-
923-
sage: u = matrix(ZZ, 3, 2, [0,1,1,1,0,2])
924-
sage: x = A.solve_right(u)
925-
sage: x
926-
[-7/12 -1/6]
927-
[ 5/12 5/6]
928-
[-1/12 -1/6]
929-
sage: A * x
930-
[0 1]
931-
[1 1]
932-
[0 2]
933-
"""
934-
if check_rank and self.rank() < self.nrows():
935-
from sage.matrix.matrix2 import NotFullRankError
936-
raise NotFullRankError
937-
938-
if self.base_ring() != B.base_ring():
939-
B = B.change_ring(self.base_ring())
940-
if self.nrows() != B.nrows():
941-
raise ValueError("input matrices must have the same number of rows.")
942-
943-
if algorithm == "generic":
944-
return Matrix_sparse.solve_right(self, B)
945-
else:
946-
if isinstance(B, Matrix):
947-
from sage.matrix.special import diagonal_matrix
948-
m, d = self._solve_matrix_linbox(B, algorithm)
949-
return m * diagonal_matrix([QQ((1,x)) for x in d])
950-
else:
951-
v, d = self._solve_vector_linbox(B, algorithm)
952-
return v / d
953-
954-
def _solve_vector_linbox(self, v, algorithm=None):
955-
r"""
956-
Return a pair ``(a, d)`` so that ``d * b = m * a``
957-
958-
If there is no solution a ``ValueError`` is raised.
959-
960-
INPUT:
961-
962-
- ``b`` -- a dense integer vector
963-
964-
- ``algorithm`` -- (optional) either ``None``, ``'dense_elimination'``,
965-
``'sparse_elimination'``, ``'wiedemann'`` or ``'blackbox'``.
966-
967-
OUTPUT: a pair ``(a, d)`` consisting of
968-
969-
- ``a`` -- a dense integer vector
970-
971-
- ``d`` -- an integer
972-
973-
EXAMPLES::
974-
975-
sage: m = matrix(ZZ, 4, sparse=True)
976-
sage: m[0,0] = m[1,2] = m[2,0] = m[3,3] = 2
977-
sage: m[0,2] = m[1,1] = -1
978-
sage: m[2,3] = m[3,0] = -3
979-
980-
sage: b0 = vector((1,1,1,1))
981-
sage: m._solve_vector_linbox(b0)
982-
((-1, -7, -3, -1), 1)
983-
sage: m._solve_vector_linbox(b0, 'dense_elimination')
984-
((-1, -7, -3, -1), 1)
985-
sage: m._solve_vector_linbox(b0, 'sparse_elimination')
986-
((-1, -7, -3, -1), 1)
987-
sage: m._solve_vector_linbox(b0, 'wiedemann')
988-
((-1, -7, -3, -1), 1)
989-
sage: m._solve_vector_linbox(b0, 'blackbox')
990-
((-1, -7, -3, -1), 1)
991-
992-
sage: b1 = vector((1,1,-1,1))
993-
sage: a1, d1 = m._solve_vector_linbox(b1)
994-
sage: d1 * b1 == m * a1
995-
True
996-
997-
TESTS::
998-
999-
sage: algos = ["default", "dense_elimination", "sparse_elimination",
1000-
....: "blackbox", "wiedemann"]
1001-
sage: for i in range(20):
1002-
....: dim = randint(1, 30)
1003-
....: M = MatrixSpace(ZZ, dim, sparse=True)
1004-
....: density = min(1, 4/dim)
1005-
....: m = M.random_element(density=density)
1006-
....: while m.rank() != dim:
1007-
....: m = M.random_element(density=density)
1008-
....: U = m.column_space().dense_module()
1009-
....: for algo in algos:
1010-
....: u, d = m._solve_vector_linbox(U.zero(), algorithm=algo)
1011-
....: assert u.is_zero()
1012-
....: b = U.random_element()
1013-
....: x, d = m._solve_vector_linbox(b, algorithm=algo)
1014-
....: assert m * x == d * b
1015-
"""
1016-
Vin = self.column_ambient_module(base_ring=None, sparse=False)
1017-
v = Vin(v)
1018-
1019-
if self._nrows == 0 or self._ncols == 0:
1020-
raise ValueError("not implemented for nrows=0 or ncols=0")
1021-
1022-
# LinBox "solve" is mostly broken for nonsquare or singular matrices.
1023-
# The conditions below could be removed once all LinBox issues has
1024-
# been solved.
1025-
if self._nrows != self._ncols or self.rank() != self._nrows:
1026-
raise ValueError("only available for full rank square matrices")
1027-
1028-
cdef givaro.ZRing givZZ
1029-
cdef linbox.SparseMatrix_integer * A = new_linbox_matrix_integer_sparse(givZZ, self)
1030-
cdef linbox.DenseVector_integer * b = new_linbox_vector_integer_dense(givZZ, v)
1031-
cdef linbox.DenseVector_integer * res = new linbox.DenseVector_integer(givZZ, <size_t> self._ncols)
1032-
cdef givaro.Integer D
1033-
1034-
method = get_method(algorithm)
1035-
1036-
if method == METHOD_DEFAULT:
1037-
linbox.solve(res[0], D, A[0], b[0])
1038-
elif method == METHOD_WIEDEMANN:
1039-
linbox.solve(res[0], D, A[0], b[0], linbox.Method.Wiedemann())
1040-
elif method == METHOD_DENSE_ELIMINATION:
1041-
linbox.solve(res[0], D, A[0], b[0], linbox.Method.DenseElimination())
1042-
elif method == METHOD_SPARSE_ELIMINATION:
1043-
linbox.solve(res[0], D, A[0], b[0], linbox.Method.SparseElimination())
1044-
elif method == METHOD_BLACKBOX:
1045-
linbox.solve(res[0], D, A[0], b[0], linbox.Method.Blackbox())
1046-
1047-
Vout = self.row_ambient_module(base_ring=None, sparse=False)
1048-
res_sage = new_sage_vector_integer_dense(Vout, res[0])
1049-
cdef Integer d = PY_NEW(Integer)
1050-
mpz_set(d.value, D.get_mpz_const())
1051-
1052-
del A
1053-
del b
1054-
del res
1055-
1056-
return (res_sage, d)
1057-
1058-
def _solve_matrix_linbox(self, mat, algorithm=None):
1059-
r"""
1060-
Solve the equation ``A x = mat`` where ``A`` is this matrix.
1061-
1062-
EXAMPLES::
1063-
1064-
sage: m = matrix(ZZ, [[1,2],[1,0]], sparse=True)
1065-
sage: b = matrix(ZZ, 2, 4, [1,0,2,0,1,1,2,0], sparse=False)
1066-
sage: u, d = m._solve_matrix_linbox(b)
1067-
sage: u
1068-
[ 1 2 2 0]
1069-
[ 0 -1 0 0]
1070-
sage: m * u == b * diagonal_matrix(d)
1071-
True
1072-
1073-
sage: u, d = m._solve_matrix_linbox([[1,3,4],[0,1,0]])
1074-
sage: u
1075-
[0 1 0]
1076-
[1 1 2]
1077-
sage: d
1078-
(2, 1, 1)
1079-
1080-
Test input::
1081-
1082-
sage: m = matrix(ZZ, [[1,2],[1,0]], sparse=True)
1083-
sage: b = matrix(ZZ, 3, 3, range(9))
1084-
sage: m._solve_matrix_linbox(b)
1085-
Traceback (most recent call last):
1086-
...
1087-
ValueError: wrong matrix dimension
1088-
1089-
sage: m._solve_matrix_linbox([[1,1],[2,3]], algorithm='hop')
1090-
Traceback (most recent call last):
1091-
...
1092-
ValueError: unknown algorithm
1093-
1094-
TESTS::
1095-
1096-
sage: algos = ["default", "dense_elimination", "sparse_elimination",
1097-
....: "blackbox", "wiedemann"]
1098-
1099-
sage: for _ in range(10):
1100-
....: dim = randint(2, 10)
1101-
....: M = MatrixSpace(ZZ, dim, sparse=True)
1102-
....: m = M.random_element(density=min(1,10/dim))
1103-
....: while m.rank() != dim:
1104-
....: m = M.random_element(density=min(1,10/dim))
1105-
....: b = random_matrix(ZZ, dim, 7)
1106-
....: Mb = b.parent()
1107-
....: for algo in algos:
1108-
....: u, d = m._solve_matrix_linbox(b, algo)
1109-
....: assert m * u == b * diagonal_matrix(d)
1110-
"""
1111-
if self._nrows == 0 or self._ncols == 0:
1112-
raise ValueError("not implemented for nrows=0 or ncols=0")
1113-
1114-
from sage.matrix.constructor import matrix
1115-
from sage.modules.free_module_element import vector
1116-
1117-
cdef Matrix_integer_dense B
1118-
if not isinstance(mat, Matrix2):
1119-
B = <Matrix_integer_dense?> matrix(ZZ, mat, sparse=False)
1120-
else:
1121-
B = <Matrix_integer_dense?> mat.change_ring(ZZ).dense_matrix()
1122-
if B._nrows != self._nrows:
1123-
raise ValueError("wrong matrix dimension")
1124-
1125-
# LinBox "solve" is mostly broken for singular matrices. The
1126-
# conditions below could be removed once all LinBox issues
1127-
# have been solved.
1128-
if self._nrows != self._ncols or self.rank() != self._nrows:
1129-
raise ValueError("only available for full rank square matrices")
1130-
1131-
cdef givaro.ZRing givZZ
1132-
cdef linbox.SparseMatrix_integer * A = new_linbox_matrix_integer_sparse(givZZ, self)
1133-
cdef linbox.DenseVector_integer * b = new linbox.DenseVector_integer(givZZ, <size_t> self._nrows)
1134-
cdef linbox.DenseVector_integer * res = new linbox.DenseVector_integer(givZZ, <size_t> self._ncols)
1135-
cdef givaro.Integer D
1136-
1137-
cdef int algo = get_method(algorithm)
1138-
1139-
cdef Matrix_integer_dense X = matrix(ZZ, A.coldim(), B.ncols(), sparse=False) # solution
1140-
cdef Vector_integer_dense d = vector(ZZ, X.ncols(), sparse=False) # multipliers
1141-
1142-
cdef size_t i, j
1143-
for i in range(X.ncols()):
1144-
# set b to the i-th column of B
1145-
for j in range(A.coldim()):
1146-
fmpz_get_mpz(<mpz_t> b.getEntry(j).get_mpz(), fmpz_mat_entry(B._matrix, j, i))
1147-
1148-
# solve the current row
1149-
if algo == METHOD_DEFAULT:
1150-
linbox.solve(res[0], D, A[0], b[0])
1151-
elif algo == METHOD_DENSE_ELIMINATION:
1152-
linbox.solve(res[0], D, A[0], b[0], linbox.Method.DenseElimination())
1153-
elif algo == METHOD_SPARSE_ELIMINATION:
1154-
linbox.solve(res[0], D, A[0], b[0], linbox.Method.SparseElimination())
1155-
elif algo == METHOD_BLACKBOX:
1156-
linbox.solve(res[0], D, A[0], b[0], linbox.Method.Blackbox())
1157-
elif algo == METHOD_WIEDEMANN:
1158-
linbox.solve(res[0], D, A[0], b[0], linbox.Method.Wiedemann())
1159-
1160-
# set i-th column of X to be res
1161-
for j in range(A.coldim()):
1162-
fmpz_set_mpz(fmpz_mat_entry(X._matrix, j, i), res[0].getEntry(j).get_mpz())
1163-
1164-
# compute common gcd
1165-
mpz_set(d._entries[i], D.get_mpz_const())
1166-
1167-
del A
1168-
del b
1169-
del res
1170-
1171-
return X, d

0 commit comments

Comments
 (0)