passagemath-linbox 10.6.32__cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-linbox might be problematic. Click here for more details.
- passagemath_linbox-10.6.32.dist-info/METADATA +100 -0
- passagemath_linbox-10.6.32.dist-info/RECORD +73 -0
- passagemath_linbox-10.6.32.dist-info/WHEEL +6 -0
- passagemath_linbox-10.6.32.dist-info/top_level.txt +2 -0
- passagemath_linbox.libs/libfflas-d452d784.so.1.0.0 +0 -0
- passagemath_linbox.libs/libffpack-32579c9b.so.1.0.0 +0 -0
- passagemath_linbox.libs/libflint-66e12231.so.21.0.0 +0 -0
- passagemath_linbox.libs/libgd-76eb082b.so.3.0.11 +0 -0
- passagemath_linbox.libs/libgfortran-83c28eba.so.5.0.0 +0 -0
- passagemath_linbox.libs/libgivaro-fc554fc9.so.9.2.1 +0 -0
- passagemath_linbox.libs/libgmp-6e109695.so.10.5.0 +0 -0
- passagemath_linbox.libs/libgmpxx-ecb9d6e3.so.4.7.0 +0 -0
- passagemath_linbox.libs/libiml-aeb1d147.so.0.1.1 +0 -0
- passagemath_linbox.libs/liblinbox-f1d24fc1.so.0.0.0 +0 -0
- passagemath_linbox.libs/libm4ri-9da2b874.so.1.0.0 +0 -0
- passagemath_linbox.libs/libm4rie-cf8cc058.so.1.0.0 +0 -0
- passagemath_linbox.libs/libmpfr-82690d50.so.6.2.1 +0 -0
- passagemath_linbox.libs/libopenblasp-r0-6dcb67f9.3.29.so +0 -0
- passagemath_linbox.libs/libpng16-b4a91cd1.so.16.43.0 +0 -0
- passagemath_linbox.libs/libquadmath-2284e583.so.0.0.0 +0 -0
- sage/all__sagemath_linbox.py +2 -0
- sage/geometry/all__sagemath_linbox.py +1 -0
- sage/geometry/integral_points.pxi +1426 -0
- sage/geometry/integral_points_integer_dense.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/geometry/integral_points_integer_dense.pyx +7 -0
- sage/libs/all__sagemath_linbox.py +1 -0
- sage/libs/iml.pxd +10 -0
- sage/libs/linbox/__init__.py +1 -0
- sage/libs/linbox/conversion.pxd +185 -0
- sage/libs/linbox/fflas.pxd +189 -0
- sage/libs/linbox/givaro.pxd +109 -0
- sage/libs/linbox/linbox.pxd +219 -0
- sage/libs/linbox/linbox_flint_interface.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/libs/linbox/linbox_flint_interface.pxd +18 -0
- sage/libs/linbox/linbox_flint_interface.pyx +192 -0
- sage/libs/m4ri.pxd +198 -0
- sage/libs/m4rie.pxd +204 -0
- sage/matrix/all__sagemath_linbox.py +1 -0
- sage/matrix/matrix_cyclo_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_cyclo_linbox.pyx +361 -0
- sage/matrix/matrix_gf2e_dense.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_gf2e_dense.pxd +15 -0
- sage/matrix/matrix_gf2e_dense.pyx +1573 -0
- sage/matrix/matrix_integer_iml.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_integer_iml.pyx +316 -0
- sage/matrix/matrix_integer_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_integer_linbox.pxd +5 -0
- sage/matrix/matrix_integer_linbox.pyx +358 -0
- sage/matrix/matrix_integer_sparse_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_integer_sparse_linbox.pyx +465 -0
- sage/matrix/matrix_mod2_dense.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_mod2_dense.pxd +14 -0
- sage/matrix/matrix_mod2_dense.pyx +2789 -0
- sage/matrix/matrix_modn_dense_double.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_modn_dense_double.pyx +179 -0
- sage/matrix/matrix_modn_dense_float.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_modn_dense_float.pyx +154 -0
- sage/matrix/matrix_modn_sparse.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_modn_sparse.pyx +871 -0
- sage/matrix/matrix_rational_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_rational_linbox.pyx +36 -0
- sage/matrix/misc.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/matrix/misc.pyx +418 -0
- sage/modules/all__sagemath_linbox.py +1 -0
- sage/modules/numpy_util.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/modules/numpy_util.pxd +10 -0
- sage/modules/numpy_util.pyx +136 -0
- sage/modules/vector_mod2_dense.cpython-313-x86_64-linux-gnu.so +0 -0
- sage/modules/vector_mod2_dense.pxd +11 -0
- sage/modules/vector_mod2_dense.pyx +547 -0
- sage/rings/all__sagemath_linbox.py +1 -0
- sage/rings/finite_rings/all__sagemath_linbox.py +1 -0
- sage/rings/polynomial/all__sagemath_linbox.py +1 -0
|
Binary file
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-linbox
|
|
2
|
+
|
|
3
|
+
from sage.arith.rational_reconstruction cimport mpq_rational_reconstruction
|
|
4
|
+
from sage.libs.flint.fmpq cimport fmpq_is_zero, fmpq_set_mpq, fmpq_canonicalise
|
|
5
|
+
from sage.libs.flint.fmpq_mat cimport fmpq_mat_entry_num, fmpq_mat_entry_den, fmpq_mat_entry
|
|
6
|
+
from sage.libs.flint.fmpz cimport fmpz_init, fmpz_clear, fmpz_set_mpz, fmpz_one, fmpz_get_mpz, fmpz_add, fmpz_mul, fmpz_sub, fmpz_mul_si, fmpz_mul_si, fmpz_mul_si, fmpz_divexact, fmpz_lcm
|
|
7
|
+
from sage.libs.flint.fmpz_mat cimport *
|
|
8
|
+
from sage.libs.gmp.mpz cimport mpz_init, mpz_clear, mpz_cmp_si
|
|
9
|
+
from sage.libs.gmp.mpq cimport mpq_init, mpq_clear, mpq_set_si, mpq_mul, mpq_add, mpq_set
|
|
10
|
+
from sage.libs.gmp.types cimport mpz_t, mpq_t
|
|
11
|
+
from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense
|
|
12
|
+
from sage.matrix.matrix_rational_dense cimport Matrix_rational_dense
|
|
13
|
+
from sage.matrix.matrix_integer_linbox cimport _lift_crt
|
|
14
|
+
from sage.rings.integer cimport Integer
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _lift_crt_rr(Matrix_rational_dense self, res, mm):
|
|
18
|
+
cdef Integer m
|
|
19
|
+
cdef Matrix_integer_dense ZA
|
|
20
|
+
cdef Matrix_rational_dense QA
|
|
21
|
+
cdef Py_ssize_t i, j
|
|
22
|
+
cdef mpz_t tmp
|
|
23
|
+
cdef mpq_t tmp2
|
|
24
|
+
mpz_init(tmp)
|
|
25
|
+
mpq_init(tmp2)
|
|
26
|
+
ZA = _lift_crt(res, mm)
|
|
27
|
+
QA = Matrix_rational_dense.__new__(Matrix_rational_dense, self.parent(), None, None, None)
|
|
28
|
+
m = mm.prod()
|
|
29
|
+
for i in range(ZA._nrows):
|
|
30
|
+
for j in range(ZA._ncols):
|
|
31
|
+
fmpz_get_mpz(tmp, fmpz_mat_entry(ZA._matrix,i,j))
|
|
32
|
+
mpq_rational_reconstruction(tmp2, tmp, m.value)
|
|
33
|
+
fmpq_set_mpq(fmpq_mat_entry(QA._matrix, i, j), tmp2)
|
|
34
|
+
mpz_clear(tmp)
|
|
35
|
+
mpq_clear(tmp2)
|
|
36
|
+
return QA
|
|
Binary file
|
sage/matrix/misc.pyx
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-linbox
|
|
2
|
+
# sage.doctest: needs sage.libs.flint
|
|
3
|
+
"""
|
|
4
|
+
Misc matrix algorithms
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from cysignals.signals cimport sig_check
|
|
8
|
+
|
|
9
|
+
from sage.arith.misc import CRT_basis, previous_prime
|
|
10
|
+
from sage.arith.rational_reconstruction cimport mpq_rational_reconstruction
|
|
11
|
+
from sage.data_structures.binary_search cimport *
|
|
12
|
+
from sage.ext.mod_int cimport *
|
|
13
|
+
from sage.libs.gmp.mpq cimport *
|
|
14
|
+
from sage.libs.gmp.mpz cimport *
|
|
15
|
+
from sage.misc.lazy_import import LazyImport
|
|
16
|
+
from sage.misc.verbose import verbose
|
|
17
|
+
from sage.modules.vector_integer_sparse cimport *
|
|
18
|
+
from sage.modules.vector_modn_sparse cimport *
|
|
19
|
+
from sage.modules.vector_rational_sparse cimport *
|
|
20
|
+
from sage.rings.integer cimport Integer
|
|
21
|
+
from sage.rings.rational_field import QQ
|
|
22
|
+
|
|
23
|
+
from sage.matrix.matrix0 cimport Matrix
|
|
24
|
+
from sage.matrix.matrix_integer_sparse cimport Matrix_integer_sparse
|
|
25
|
+
from sage.matrix.matrix_rational_sparse cimport Matrix_rational_sparse
|
|
26
|
+
|
|
27
|
+
matrix_integer_dense_rational_reconstruction = \
|
|
28
|
+
LazyImport('sage.matrix.misc_flint', 'matrix_integer_dense_rational_reconstruction',
|
|
29
|
+
deprecation=35758)
|
|
30
|
+
hadamard_row_bound_mpfr = \
|
|
31
|
+
LazyImport('sage.matrix.misc_mpfr', 'hadamard_row_bound_mpfr',
|
|
32
|
+
deprecation=35758)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def matrix_integer_sparse_rational_reconstruction(Matrix_integer_sparse A, Integer N):
|
|
36
|
+
r"""
|
|
37
|
+
Given a sparse matrix over the integers and an integer modulus, do
|
|
38
|
+
rational reconstruction on all entries of the matrix, viewed as
|
|
39
|
+
numbers mod `N`.
|
|
40
|
+
|
|
41
|
+
EXAMPLES::
|
|
42
|
+
|
|
43
|
+
sage: A = matrix(ZZ, 3, 4, [(1/3)%500, 2, 3, (-4)%500, 7, 2, 2, 3, 4, 3, 4, (5/7)%500], sparse=True)
|
|
44
|
+
sage: from sage.matrix.misc import matrix_integer_sparse_rational_reconstruction
|
|
45
|
+
sage: matrix_integer_sparse_rational_reconstruction(A, 500)
|
|
46
|
+
[1/3 2 3 -4]
|
|
47
|
+
[ 7 2 2 3]
|
|
48
|
+
[ 4 3 4 5/7]
|
|
49
|
+
|
|
50
|
+
TESTS:
|
|
51
|
+
|
|
52
|
+
Check that :issue:`9345` is fixed::
|
|
53
|
+
|
|
54
|
+
sage: A = random_matrix(ZZ, 3, sparse=True)
|
|
55
|
+
sage: sage.matrix.misc.matrix_integer_sparse_rational_reconstruction(A, 0)
|
|
56
|
+
Traceback (most recent call last):
|
|
57
|
+
...
|
|
58
|
+
ZeroDivisionError: The modulus cannot be zero
|
|
59
|
+
"""
|
|
60
|
+
if not N:
|
|
61
|
+
raise ZeroDivisionError("The modulus cannot be zero")
|
|
62
|
+
cdef Matrix_rational_sparse R
|
|
63
|
+
R = Matrix_rational_sparse.__new__(Matrix_rational_sparse,
|
|
64
|
+
A.parent().change_ring(QQ), 0,0,0)
|
|
65
|
+
|
|
66
|
+
cdef mpq_t t
|
|
67
|
+
cdef mpz_t a, bnd, other_bnd, denom
|
|
68
|
+
cdef Integer _bnd
|
|
69
|
+
cdef Py_ssize_t i, j
|
|
70
|
+
cdef int do_it
|
|
71
|
+
cdef mpz_vector* A_row
|
|
72
|
+
cdef mpq_vector* R_row
|
|
73
|
+
|
|
74
|
+
mpq_init(t)
|
|
75
|
+
mpz_init_set_si(denom, 1)
|
|
76
|
+
mpz_init(a)
|
|
77
|
+
mpz_init(other_bnd)
|
|
78
|
+
|
|
79
|
+
_bnd = (N//2).isqrt()
|
|
80
|
+
mpz_init_set(bnd, _bnd.value)
|
|
81
|
+
mpz_sub(other_bnd, N.value, bnd)
|
|
82
|
+
|
|
83
|
+
for i in range(A._nrows):
|
|
84
|
+
sig_check()
|
|
85
|
+
A_row = &A._matrix[i]
|
|
86
|
+
R_row = &R._matrix[i]
|
|
87
|
+
reallocate_mpq_vector(R_row, A_row.num_nonzero)
|
|
88
|
+
R_row.num_nonzero = A_row.num_nonzero
|
|
89
|
+
R_row.degree = A_row.degree
|
|
90
|
+
for j in range(A_row.num_nonzero):
|
|
91
|
+
sig_check()
|
|
92
|
+
mpz_set(a, A_row.entries[j])
|
|
93
|
+
if mpz_cmp_ui(denom, 1) != 0:
|
|
94
|
+
mpz_mul(a, a, denom)
|
|
95
|
+
mpz_fdiv_r(a, a, N.value)
|
|
96
|
+
do_it = 0
|
|
97
|
+
if mpz_cmp(a, bnd) <= 0:
|
|
98
|
+
do_it = 1
|
|
99
|
+
elif mpz_cmp(a, other_bnd) >= 0:
|
|
100
|
+
mpz_sub(a, a, N.value)
|
|
101
|
+
do_it = 1
|
|
102
|
+
if do_it:
|
|
103
|
+
mpz_set(mpq_numref(t), a)
|
|
104
|
+
if mpz_cmp_ui(denom, 1) != 0:
|
|
105
|
+
mpz_set(mpq_denref(t), denom)
|
|
106
|
+
mpq_canonicalize(t)
|
|
107
|
+
else:
|
|
108
|
+
mpz_set_si(mpq_denref(t), 1)
|
|
109
|
+
mpq_set(R_row.entries[j], t)
|
|
110
|
+
R_row.positions[j] = A_row.positions[j]
|
|
111
|
+
else:
|
|
112
|
+
# Otherwise have to do it the hard way
|
|
113
|
+
mpq_rational_reconstruction(t, A_row.entries[j], N.value)
|
|
114
|
+
mpq_set(R_row.entries[j], t)
|
|
115
|
+
R_row.positions[j] = A_row.positions[j]
|
|
116
|
+
mpz_lcm(denom, denom, mpq_denref(t))
|
|
117
|
+
|
|
118
|
+
mpq_clear(t)
|
|
119
|
+
mpz_clear(denom)
|
|
120
|
+
mpz_clear(a)
|
|
121
|
+
mpz_clear(other_bnd)
|
|
122
|
+
mpz_clear(bnd)
|
|
123
|
+
|
|
124
|
+
return R
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def matrix_rational_echelon_form_multimodular(Matrix self, height_guess=None, proof=None):
|
|
128
|
+
"""
|
|
129
|
+
Return reduced row-echelon form using a multi-modular
|
|
130
|
+
algorithm. Does not change ``self``.
|
|
131
|
+
|
|
132
|
+
REFERENCE: Chapter 7 of Stein's "Explicitly Computing Modular Forms".
|
|
133
|
+
|
|
134
|
+
INPUT:
|
|
135
|
+
|
|
136
|
+
- ``height_guess`` -- integer or ``None``
|
|
137
|
+
- ``proof`` -- boolean or ``None`` (default: ``None``, see
|
|
138
|
+
``proof.linear_algebra`` or ``sage.structure.proof``). Note that the
|
|
139
|
+
global Sage default is proof=True
|
|
140
|
+
|
|
141
|
+
OUTPUT: a pair consisting of a matrix in echelon form and a tuple of pivot
|
|
142
|
+
positions.
|
|
143
|
+
|
|
144
|
+
ALGORITHM:
|
|
145
|
+
|
|
146
|
+
The following is a modular algorithm for computing the echelon
|
|
147
|
+
form. Define the height of a matrix to be the max of the
|
|
148
|
+
absolute values of the entries.
|
|
149
|
+
|
|
150
|
+
Given Matrix A with n columns (self).
|
|
151
|
+
|
|
152
|
+
0. Rescale input matrix A to have integer entries. This does
|
|
153
|
+
not change echelon form and makes reduction modulo lots of
|
|
154
|
+
primes significantly easier if there were denominators.
|
|
155
|
+
Henceforth we assume A has integer entries.
|
|
156
|
+
|
|
157
|
+
1. Let c be a guess for the height of the echelon form. E.g.,
|
|
158
|
+
c=1000, e.g., if matrix is very sparse and application is to
|
|
159
|
+
computing modular symbols.
|
|
160
|
+
|
|
161
|
+
2. Let M = n * c * H(A) + 1,
|
|
162
|
+
where n is the number of columns of A.
|
|
163
|
+
|
|
164
|
+
3. List primes p_1, p_2, ..., such that the product of
|
|
165
|
+
the p_i is at least M.
|
|
166
|
+
|
|
167
|
+
4. Try to compute the rational reconstruction CRT echelon form
|
|
168
|
+
of A mod the product of the p_i. If rational
|
|
169
|
+
reconstruction fails, compute 1 more echelon forms mod the
|
|
170
|
+
next prime, and attempt again. Make sure to keep the
|
|
171
|
+
result of CRT on the primes from before, so we don't have
|
|
172
|
+
to do that computation again. Let E be this matrix.
|
|
173
|
+
|
|
174
|
+
5. Compute the denominator d of E.
|
|
175
|
+
Attempt to prove that result is correct by checking that
|
|
176
|
+
|
|
177
|
+
H(d*E)*ncols(A)*H(A) < (prod of reduction primes)
|
|
178
|
+
|
|
179
|
+
where H denotes the height. If this fails, do step 4 with
|
|
180
|
+
a few more primes.
|
|
181
|
+
|
|
182
|
+
EXAMPLES::
|
|
183
|
+
|
|
184
|
+
sage: A = matrix(QQ, 3, 7, [1..21])
|
|
185
|
+
sage: from sage.matrix.misc import matrix_rational_echelon_form_multimodular
|
|
186
|
+
sage: E, pivots = matrix_rational_echelon_form_multimodular(A)
|
|
187
|
+
sage: E
|
|
188
|
+
[ 1 0 -1 -2 -3 -4 -5]
|
|
189
|
+
[ 0 1 2 3 4 5 6]
|
|
190
|
+
[ 0 0 0 0 0 0 0]
|
|
191
|
+
sage: pivots
|
|
192
|
+
(0, 1)
|
|
193
|
+
|
|
194
|
+
sage: A = matrix(QQ, 3, 4, [0,0] + [1..9] + [-1/2^20])
|
|
195
|
+
sage: E, pivots = matrix_rational_echelon_form_multimodular(A)
|
|
196
|
+
sage: E
|
|
197
|
+
[ 1 0 0 -10485761/1048576]
|
|
198
|
+
[ 0 1 0 27262979/4194304]
|
|
199
|
+
[ 0 0 1 2]
|
|
200
|
+
sage: pivots
|
|
201
|
+
(0, 1, 2)
|
|
202
|
+
|
|
203
|
+
sage: A.echelon_form()
|
|
204
|
+
[ 1 0 0 -10485761/1048576]
|
|
205
|
+
[ 0 1 0 27262979/4194304]
|
|
206
|
+
[ 0 0 1 2]
|
|
207
|
+
sage: A.pivots()
|
|
208
|
+
(0, 1, 2)
|
|
209
|
+
|
|
210
|
+
A small benchmark, showing that flint fraction-free multimodular algorithm
|
|
211
|
+
is always faster than the fraction-free multimodular algorithm implemented in Python::
|
|
212
|
+
|
|
213
|
+
sage: import copy
|
|
214
|
+
sage: def benchmark(num_row, num_col, entry_size, timeout=2, integer_coefficient=True):
|
|
215
|
+
....: A = matrix(QQ, [[
|
|
216
|
+
....: randint(1, 2^entry_size) if integer_coefficient else ZZ(randint(1, 2^entry_size))/randint(1, 2^entry_size)
|
|
217
|
+
....: for col in range(num_col)] for row in range(num_row)])
|
|
218
|
+
....: data=[]
|
|
219
|
+
....: for algorithm in ("flint:fflu", "flint:multimodular", "padic", "multimodular"):
|
|
220
|
+
....: # classical is too slow
|
|
221
|
+
....: B = copy.copy(A)
|
|
222
|
+
....: t = walltime()
|
|
223
|
+
....: alarm(timeout)
|
|
224
|
+
....: try:
|
|
225
|
+
....: B.echelonize(algorithm=algorithm)
|
|
226
|
+
....: except AlarmInterrupt:
|
|
227
|
+
....: pass
|
|
228
|
+
....: finally:
|
|
229
|
+
....: cancel_alarm()
|
|
230
|
+
....: data.append((round(walltime(t), 4), algorithm))
|
|
231
|
+
....: return sorted(data)
|
|
232
|
+
sage: benchmark(20, 20, 10000) # long time
|
|
233
|
+
[...'flint:multimodular'...'multimodular'...'flint:fflu'...]
|
|
234
|
+
sage: benchmark(39, 40, 200) # long time
|
|
235
|
+
[...'flint:multimodular'...'flint:fflu'...'multimodular'...]
|
|
236
|
+
|
|
237
|
+
In older versions of flint
|
|
238
|
+
before this `issue <https://github.com/flintlib/flint/issues/2129>`_
|
|
239
|
+
is fixed, ``algorithm='flint'`` (automatic choice) may be slower than
|
|
240
|
+
``algorithm='flint:multimodular'``.
|
|
241
|
+
|
|
242
|
+
In this case, there are more columns than rows, which means the resulting
|
|
243
|
+
matrix has height much higher than the input matrix. We check that the function
|
|
244
|
+
does not take too long::
|
|
245
|
+
|
|
246
|
+
sage: A = matrix(QQ, [[randint(1, 2^500) for col in range(40)] for row in range(20)])
|
|
247
|
+
sage: t = walltime()
|
|
248
|
+
sage: A.echelonize(algorithm="multimodular") # long time
|
|
249
|
+
sage: t = walltime(t) # long time
|
|
250
|
+
sage: (t < 10, t) # long time
|
|
251
|
+
(True, ...)
|
|
252
|
+
"""
|
|
253
|
+
if proof is None:
|
|
254
|
+
from sage.structure.proof.proof import get_flag
|
|
255
|
+
proof = get_flag(proof, "linear_algebra")
|
|
256
|
+
|
|
257
|
+
verbose("Multimodular echelon algorithm on %s x %s matrix" % (self._nrows, self._ncols), caller_name="multimod echelon")
|
|
258
|
+
cdef Matrix E
|
|
259
|
+
if self._nrows == 0 or self._ncols == 0:
|
|
260
|
+
return self, ()
|
|
261
|
+
|
|
262
|
+
B, _ = self._clear_denom()
|
|
263
|
+
|
|
264
|
+
height = self.height()
|
|
265
|
+
if height_guess is None:
|
|
266
|
+
height_guess = 10000000*(height+100)
|
|
267
|
+
tm = verbose("height_guess = %s" % height_guess, level=2, caller_name="multimod echelon")
|
|
268
|
+
|
|
269
|
+
cdef Integer M
|
|
270
|
+
from sage.arith.misc import integer_floor as floor
|
|
271
|
+
if proof:
|
|
272
|
+
M = floor(max(1, self._ncols * height_guess * height + 1))
|
|
273
|
+
else:
|
|
274
|
+
M = floor(max(1, height_guess + 1))
|
|
275
|
+
|
|
276
|
+
if self.is_sparse():
|
|
277
|
+
from sage.matrix.matrix_modn_sparse import MAX_MODULUS
|
|
278
|
+
p = MAX_MODULUS + 1
|
|
279
|
+
else:
|
|
280
|
+
from sage.matrix.matrix_modn_dense_double import MAX_MODULUS
|
|
281
|
+
p = MAX_MODULUS + 1
|
|
282
|
+
t = None
|
|
283
|
+
X = []
|
|
284
|
+
best_pivots = []
|
|
285
|
+
prod = 1
|
|
286
|
+
problem = 0
|
|
287
|
+
lifts = {}
|
|
288
|
+
while True:
|
|
289
|
+
p = previous_prime(p)
|
|
290
|
+
while prod < M:
|
|
291
|
+
problem = problem + 1
|
|
292
|
+
if problem > 50:
|
|
293
|
+
verbose("echelon multi-modular possibly not converging?", caller_name="multimod echelon")
|
|
294
|
+
t = verbose("echelon modulo p=%s (%.2f%% done)" % (
|
|
295
|
+
p, 100*float(len(str(prod))) / len(str(M))), level=2, caller_name="multimod echelon")
|
|
296
|
+
|
|
297
|
+
# We use denoms=False, since we made self integral by calling clear_denom above.
|
|
298
|
+
A = B._mod_int(p)
|
|
299
|
+
t = verbose("time to reduce matrix mod p:",t, level=2, caller_name="multimod echelon")
|
|
300
|
+
A.echelonize()
|
|
301
|
+
t = verbose("time to put reduced matrix in echelon form:",t, level=2, caller_name="multimod echelon")
|
|
302
|
+
|
|
303
|
+
# a worthwhile check / shortcut.
|
|
304
|
+
if self._nrows >= self._ncols and self._nrows == len(A.pivots()):
|
|
305
|
+
verbose("done: the echelon form mod p is the identity matrix and possibly some 0 rows", caller_name="multimod echelon")
|
|
306
|
+
E = self.parent()(0)
|
|
307
|
+
one = self.base_ring().one()
|
|
308
|
+
for i in range(self._nrows):
|
|
309
|
+
E.set_unsafe(i, i, one)
|
|
310
|
+
return E, tuple(range(self._nrows))
|
|
311
|
+
|
|
312
|
+
c = cmp_pivots(best_pivots, A.pivots())
|
|
313
|
+
if c <= 0:
|
|
314
|
+
best_pivots = A.pivots()
|
|
315
|
+
X.append(A)
|
|
316
|
+
prod = prod * p
|
|
317
|
+
else:
|
|
318
|
+
# do not save A since it is bad.
|
|
319
|
+
verbose("Excluding this prime (bad pivots).", caller_name="multimod echelon")
|
|
320
|
+
t = verbose("time for pivot compare", t, level=2, caller_name="multimod echelon")
|
|
321
|
+
p = previous_prime(p)
|
|
322
|
+
# Find set of best matrices.
|
|
323
|
+
Y = []
|
|
324
|
+
# recompute product, since may drop bad matrices
|
|
325
|
+
prod = 1
|
|
326
|
+
t = verbose("now comparing pivots and dropping any bad ones", level=2, t=t, caller_name="multimod echelon")
|
|
327
|
+
for i in range(len(X)):
|
|
328
|
+
if cmp_pivots(best_pivots, X[i].pivots()) <= 0:
|
|
329
|
+
p = X[i].base_ring().order()
|
|
330
|
+
if p not in lifts:
|
|
331
|
+
t0 = verbose("Lifting a good matrix", level=2, caller_name="multimod echelon")
|
|
332
|
+
lift = X[i].lift()
|
|
333
|
+
lifts[p] = (lift, p)
|
|
334
|
+
verbose("Finished lift", level=2, caller_name="multimod echelon", t=t0)
|
|
335
|
+
Y.append(lifts[p])
|
|
336
|
+
prod = prod * X[i].base_ring().order()
|
|
337
|
+
verbose("finished comparing pivots", level=2, t=t, caller_name="multimod echelon")
|
|
338
|
+
try:
|
|
339
|
+
if not Y:
|
|
340
|
+
raise ValueError("not enough primes")
|
|
341
|
+
t = verbose("start crt linear combination", level=2, caller_name="multimod echelon")
|
|
342
|
+
a = CRT_basis([w[1] for w in Y])
|
|
343
|
+
t = verbose('got crt basis', level=2, t=t, caller_name="multimod echelon")
|
|
344
|
+
|
|
345
|
+
# take the linear combination of the lifts of the elements
|
|
346
|
+
# of Y times coefficients in a
|
|
347
|
+
L = a[0]*(Y[0][0])
|
|
348
|
+
assert Y[0][0].is_sparse() == L.is_sparse()
|
|
349
|
+
for j in range(1,len(Y)):
|
|
350
|
+
L += a[j]*(Y[j][0])
|
|
351
|
+
verbose("time to take linear combination of matrices over ZZ is",t, level=2, caller_name="multimod echelon")
|
|
352
|
+
t = verbose("now doing rational reconstruction", level=2, caller_name="multimod echelon")
|
|
353
|
+
E = L.rational_reconstruction(prod)
|
|
354
|
+
L = 0 # free memory
|
|
355
|
+
verbose('rational reconstruction completed', t, level=2, caller_name="multimod echelon")
|
|
356
|
+
except ValueError as msg:
|
|
357
|
+
verbose(msg, level=2)
|
|
358
|
+
verbose("Not enough primes to do CRT lift; redoing with several more primes.", level=2, caller_name="multimod echelon")
|
|
359
|
+
M <<= M.bit_length() // 5 + 1
|
|
360
|
+
continue
|
|
361
|
+
|
|
362
|
+
if not proof:
|
|
363
|
+
verbose("Not checking validity of result (since proof=False).", level=2, caller_name="multimod echelon")
|
|
364
|
+
break
|
|
365
|
+
d = E.denominator()
|
|
366
|
+
hdE = int((d*E).height())
|
|
367
|
+
if hdE * self.ncols() * height < prod:
|
|
368
|
+
verbose("Validity of result checked.", level=2, caller_name="multimod echelon")
|
|
369
|
+
break
|
|
370
|
+
verbose("Validity failed; trying again with more primes.", level=2, caller_name="multimod echelon")
|
|
371
|
+
M <<= M.bit_length() // 5 + 1
|
|
372
|
+
#end while
|
|
373
|
+
verbose("total time",tm, level=2, caller_name="multimod echelon")
|
|
374
|
+
return E, tuple(best_pivots)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def cmp_pivots(x, y):
|
|
378
|
+
r"""
|
|
379
|
+
Compare two sequences of pivot columns.
|
|
380
|
+
|
|
381
|
+
If `x` is shorter than `y`, return `-1`, i.e., `x < y`, "not as good".
|
|
382
|
+
If `x` is longer than `y`, then `x > y`, so "better" and return `+1`.
|
|
383
|
+
If the length is the same, then `x` is better, i.e., `x > y`
|
|
384
|
+
if the entries of `x` are correspondingly `\leq` those of `y` with
|
|
385
|
+
one being strictly less.
|
|
386
|
+
|
|
387
|
+
INPUT:
|
|
388
|
+
|
|
389
|
+
- ``x``, ``y`` -- lists or tuples of integers
|
|
390
|
+
|
|
391
|
+
EXAMPLES:
|
|
392
|
+
|
|
393
|
+
We illustrate each of the above comparisons. ::
|
|
394
|
+
|
|
395
|
+
sage: from sage.matrix.misc import cmp_pivots
|
|
396
|
+
sage: cmp_pivots([1,2,3], [4,5,6,7])
|
|
397
|
+
-1
|
|
398
|
+
sage: cmp_pivots([1,2,3,5], [4,5,6])
|
|
399
|
+
1
|
|
400
|
+
sage: cmp_pivots([1,2,4], [1,2,3])
|
|
401
|
+
-1
|
|
402
|
+
sage: cmp_pivots([1,2,3], [1,2,3])
|
|
403
|
+
0
|
|
404
|
+
sage: cmp_pivots([1,2,3], [1,2,4])
|
|
405
|
+
1
|
|
406
|
+
"""
|
|
407
|
+
x = tuple(x)
|
|
408
|
+
y = tuple(y)
|
|
409
|
+
if len(x) < len(y):
|
|
410
|
+
return -1
|
|
411
|
+
if len(x) > len(y):
|
|
412
|
+
return 1
|
|
413
|
+
if x < y:
|
|
414
|
+
return 1
|
|
415
|
+
elif x == y:
|
|
416
|
+
return 0
|
|
417
|
+
else:
|
|
418
|
+
return -1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-linbox
|
|
Binary file
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-linbox
|
|
2
|
+
from libc.stdint cimport uintptr_t
|
|
3
|
+
from sage.libs.m4ri cimport *
|
|
4
|
+
from sage.matrix.matrix_mod2_dense cimport Matrix_mod2_dense
|
|
5
|
+
|
|
6
|
+
cpdef int set_matrix_mod2_from_numpy(Matrix_mod2_dense a, b) except -1
|
|
7
|
+
|
|
8
|
+
cpdef int set_mzd_from_numpy(uintptr_t entries_addr, Py_ssize_t degree, x) except -1
|
|
9
|
+
# Note: we don't actually need ``cimport`` to work, which means this header file is not used in practice
|
|
10
|
+
# neither do we need ``cpdef`` (``def`` is sufficient)
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-linbox
|
|
2
|
+
# sage.doctest: optional - numpy
|
|
3
|
+
# cython: fast_getattr=False
|
|
4
|
+
# https://github.com/cython/cython/issues/6442
|
|
5
|
+
r"""
|
|
6
|
+
Utility functions for numpy.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
cimport numpy as np
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
ctypedef fused numpy_integral:
|
|
14
|
+
np.int8_t
|
|
15
|
+
np.int32_t
|
|
16
|
+
np.int64_t
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
cdef set_mzd_from_numpy_unsafe(mzd_t* entries, np.ndarray[numpy_integral, ndim=1] x):
|
|
20
|
+
"""
|
|
21
|
+
Internal function.
|
|
22
|
+
Caller are responsible for checking the two arrays have the same length.
|
|
23
|
+
"""
|
|
24
|
+
for i in range(len(x)):
|
|
25
|
+
mzd_write_bit(entries, 0, i, x[i] & 1)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
cpdef int set_mzd_from_numpy(uintptr_t entries_addr, Py_ssize_t degree, x) except -1:
|
|
29
|
+
"""
|
|
30
|
+
Set the entries in ``<mzd_t*>entries_addr`` from numpy array ``x``.
|
|
31
|
+
|
|
32
|
+
INPUT:
|
|
33
|
+
|
|
34
|
+
- ``entries_addr`` -- must be a ``mzd_t*`` casted to ``uintptr_t``; the casting
|
|
35
|
+
is necessary to pass it through Python boundary because of lazy import.
|
|
36
|
+
Do not pass arbitrary integer value here, will crash the program.
|
|
37
|
+
|
|
38
|
+
- ``degree`` -- the length of the array
|
|
39
|
+
|
|
40
|
+
- ``x`` -- a numpy array of integers or booleans, or any other object (in which
|
|
41
|
+
case this function will return ``False``)
|
|
42
|
+
|
|
43
|
+
OUTPUT: ``True`` if successful, ``False`` otherwise. May throw ``ValueError``.
|
|
44
|
+
"""
|
|
45
|
+
cdef Py_ssize_t i
|
|
46
|
+
cdef np.ndarray[np.npy_bool, ndim=1] x_bool
|
|
47
|
+
cdef mzd_t* entries = <mzd_t*>entries_addr
|
|
48
|
+
if isinstance(x, np.ndarray):
|
|
49
|
+
if x.ndim != 1:
|
|
50
|
+
raise ValueError("numpy array must have dimension 1")
|
|
51
|
+
if x.shape[0] != degree:
|
|
52
|
+
raise ValueError("numpy array must have the right length")
|
|
53
|
+
if x.dtype == np.int8:
|
|
54
|
+
set_mzd_from_numpy_unsafe(entries, <np.ndarray[np.int8_t, ndim=1]>x)
|
|
55
|
+
return True
|
|
56
|
+
if x.dtype == np.int32:
|
|
57
|
+
set_mzd_from_numpy_unsafe(entries, <np.ndarray[np.int32_t, ndim=1]>x)
|
|
58
|
+
return True
|
|
59
|
+
if x.dtype == np.int64:
|
|
60
|
+
set_mzd_from_numpy_unsafe(entries, <np.ndarray[np.int64_t, ndim=1]>x)
|
|
61
|
+
return True
|
|
62
|
+
if x.dtype == np.bool_:
|
|
63
|
+
x_bool = x
|
|
64
|
+
for i in range(degree):
|
|
65
|
+
mzd_write_bit(entries, 0, i, x_bool[i])
|
|
66
|
+
return True
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
cpdef int _set_matrix_mod2_from_numpy_helper(Matrix_mod2_dense a, np.ndarray[numpy_integral, ndim=2] b) except -1:
|
|
71
|
+
"""
|
|
72
|
+
Internal function, helper for :func:`set_matrix_mod2_from_numpy`.
|
|
73
|
+
|
|
74
|
+
TESTS::
|
|
75
|
+
|
|
76
|
+
sage: from sage.modules.numpy_util import _set_matrix_mod2_from_numpy_helper
|
|
77
|
+
sage: import numpy as np
|
|
78
|
+
sage: a = matrix(GF(2), 2, 3)
|
|
79
|
+
sage: b = np.array([[1, 0, 1], [0, 1, 0]], dtype=np.int8)
|
|
80
|
+
sage: _set_matrix_mod2_from_numpy_helper(a, b)
|
|
81
|
+
1
|
|
82
|
+
sage: a
|
|
83
|
+
[1 0 1]
|
|
84
|
+
[0 1 0]
|
|
85
|
+
sage: _set_matrix_mod2_from_numpy_helper(a, np.array([[1, 0], [0, 1]], dtype=np.int8))
|
|
86
|
+
Traceback (most recent call last):
|
|
87
|
+
...
|
|
88
|
+
ValueError: shape mismatch
|
|
89
|
+
"""
|
|
90
|
+
if not (a.nrows() == b.shape[0] and a.ncols() == b.shape[1]):
|
|
91
|
+
raise ValueError("shape mismatch")
|
|
92
|
+
for i in range(b.shape[0]):
|
|
93
|
+
for j in range(b.shape[1]):
|
|
94
|
+
a.set_unsafe_int(i, j, b[i, j] & 1)
|
|
95
|
+
return True
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
cpdef int set_matrix_mod2_from_numpy(Matrix_mod2_dense a, b) except -1:
|
|
99
|
+
"""
|
|
100
|
+
Try to set the entries of a matrix from a numpy array.
|
|
101
|
+
|
|
102
|
+
INPUT:
|
|
103
|
+
|
|
104
|
+
- ``a`` -- the destination matrix
|
|
105
|
+
- ``b`` -- a numpy array, must have dimension 2 and the same shape as ``a``
|
|
106
|
+
|
|
107
|
+
OUTPUT: ``True`` (when used as bool) if successful, ``False`` otherwise. May throw ``ValueError``.
|
|
108
|
+
|
|
109
|
+
The exact type of the return value is not guaranteed, in the actual current implementation
|
|
110
|
+
it is ``1`` for success and ``0`` for failure.
|
|
111
|
+
|
|
112
|
+
TESTS::
|
|
113
|
+
|
|
114
|
+
sage: from sage.modules.numpy_util import set_matrix_mod2_from_numpy
|
|
115
|
+
sage: import numpy as np
|
|
116
|
+
sage: a = matrix(GF(2), 2, 3)
|
|
117
|
+
sage: b = np.array([[1, 0, 1], [0, 1, 0]], dtype=np.int8)
|
|
118
|
+
sage: set_matrix_mod2_from_numpy(a, b)
|
|
119
|
+
1
|
|
120
|
+
sage: a
|
|
121
|
+
[1 0 1]
|
|
122
|
+
[0 1 0]
|
|
123
|
+
sage: set_matrix_mod2_from_numpy(a, np.array([[1, 0], [0, 1]], dtype=np.int8))
|
|
124
|
+
Traceback (most recent call last):
|
|
125
|
+
...
|
|
126
|
+
ValueError: shape mismatch
|
|
127
|
+
sage: # unsupported type (may be supported in the future)
|
|
128
|
+
sage: set_matrix_mod2_from_numpy(a, np.array([[1, 1, 0], [0, 1, 0]], dtype=np.float64))
|
|
129
|
+
0
|
|
130
|
+
sage: set_matrix_mod2_from_numpy(a, np.array([1, 0, 0], dtype=np.int8)) # wrong number of dimensions
|
|
131
|
+
0
|
|
132
|
+
"""
|
|
133
|
+
try:
|
|
134
|
+
return (<object>_set_matrix_mod2_from_numpy_helper)(a, b) # https://github.com/cython/cython/issues/6588
|
|
135
|
+
except TypeError:
|
|
136
|
+
return False
|
|
Binary file
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-linbox
|
|
2
|
+
from sage.modules.free_module_element cimport FreeModuleElement
|
|
3
|
+
from sage.libs.m4ri cimport mzd_t
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
cdef class Vector_mod2_dense(FreeModuleElement):
|
|
7
|
+
cdef mzd_t* _entries
|
|
8
|
+
cdef object _base_ring
|
|
9
|
+
|
|
10
|
+
cdef _new_c(self)
|
|
11
|
+
cdef _init(self, Py_ssize_t degree, parent)
|