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.

Files changed (73) hide show
  1. passagemath_linbox-10.6.32.dist-info/METADATA +100 -0
  2. passagemath_linbox-10.6.32.dist-info/RECORD +73 -0
  3. passagemath_linbox-10.6.32.dist-info/WHEEL +6 -0
  4. passagemath_linbox-10.6.32.dist-info/top_level.txt +2 -0
  5. passagemath_linbox.libs/libfflas-d452d784.so.1.0.0 +0 -0
  6. passagemath_linbox.libs/libffpack-32579c9b.so.1.0.0 +0 -0
  7. passagemath_linbox.libs/libflint-66e12231.so.21.0.0 +0 -0
  8. passagemath_linbox.libs/libgd-76eb082b.so.3.0.11 +0 -0
  9. passagemath_linbox.libs/libgfortran-83c28eba.so.5.0.0 +0 -0
  10. passagemath_linbox.libs/libgivaro-fc554fc9.so.9.2.1 +0 -0
  11. passagemath_linbox.libs/libgmp-6e109695.so.10.5.0 +0 -0
  12. passagemath_linbox.libs/libgmpxx-ecb9d6e3.so.4.7.0 +0 -0
  13. passagemath_linbox.libs/libiml-aeb1d147.so.0.1.1 +0 -0
  14. passagemath_linbox.libs/liblinbox-f1d24fc1.so.0.0.0 +0 -0
  15. passagemath_linbox.libs/libm4ri-9da2b874.so.1.0.0 +0 -0
  16. passagemath_linbox.libs/libm4rie-cf8cc058.so.1.0.0 +0 -0
  17. passagemath_linbox.libs/libmpfr-82690d50.so.6.2.1 +0 -0
  18. passagemath_linbox.libs/libopenblasp-r0-6dcb67f9.3.29.so +0 -0
  19. passagemath_linbox.libs/libpng16-b4a91cd1.so.16.43.0 +0 -0
  20. passagemath_linbox.libs/libquadmath-2284e583.so.0.0.0 +0 -0
  21. sage/all__sagemath_linbox.py +2 -0
  22. sage/geometry/all__sagemath_linbox.py +1 -0
  23. sage/geometry/integral_points.pxi +1426 -0
  24. sage/geometry/integral_points_integer_dense.cpython-313-x86_64-linux-gnu.so +0 -0
  25. sage/geometry/integral_points_integer_dense.pyx +7 -0
  26. sage/libs/all__sagemath_linbox.py +1 -0
  27. sage/libs/iml.pxd +10 -0
  28. sage/libs/linbox/__init__.py +1 -0
  29. sage/libs/linbox/conversion.pxd +185 -0
  30. sage/libs/linbox/fflas.pxd +189 -0
  31. sage/libs/linbox/givaro.pxd +109 -0
  32. sage/libs/linbox/linbox.pxd +219 -0
  33. sage/libs/linbox/linbox_flint_interface.cpython-313-x86_64-linux-gnu.so +0 -0
  34. sage/libs/linbox/linbox_flint_interface.pxd +18 -0
  35. sage/libs/linbox/linbox_flint_interface.pyx +192 -0
  36. sage/libs/m4ri.pxd +198 -0
  37. sage/libs/m4rie.pxd +204 -0
  38. sage/matrix/all__sagemath_linbox.py +1 -0
  39. sage/matrix/matrix_cyclo_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
  40. sage/matrix/matrix_cyclo_linbox.pyx +361 -0
  41. sage/matrix/matrix_gf2e_dense.cpython-313-x86_64-linux-gnu.so +0 -0
  42. sage/matrix/matrix_gf2e_dense.pxd +15 -0
  43. sage/matrix/matrix_gf2e_dense.pyx +1573 -0
  44. sage/matrix/matrix_integer_iml.cpython-313-x86_64-linux-gnu.so +0 -0
  45. sage/matrix/matrix_integer_iml.pyx +316 -0
  46. sage/matrix/matrix_integer_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
  47. sage/matrix/matrix_integer_linbox.pxd +5 -0
  48. sage/matrix/matrix_integer_linbox.pyx +358 -0
  49. sage/matrix/matrix_integer_sparse_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
  50. sage/matrix/matrix_integer_sparse_linbox.pyx +465 -0
  51. sage/matrix/matrix_mod2_dense.cpython-313-x86_64-linux-gnu.so +0 -0
  52. sage/matrix/matrix_mod2_dense.pxd +14 -0
  53. sage/matrix/matrix_mod2_dense.pyx +2789 -0
  54. sage/matrix/matrix_modn_dense_double.cpython-313-x86_64-linux-gnu.so +0 -0
  55. sage/matrix/matrix_modn_dense_double.pyx +179 -0
  56. sage/matrix/matrix_modn_dense_float.cpython-313-x86_64-linux-gnu.so +0 -0
  57. sage/matrix/matrix_modn_dense_float.pyx +154 -0
  58. sage/matrix/matrix_modn_sparse.cpython-313-x86_64-linux-gnu.so +0 -0
  59. sage/matrix/matrix_modn_sparse.pyx +871 -0
  60. sage/matrix/matrix_rational_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
  61. sage/matrix/matrix_rational_linbox.pyx +36 -0
  62. sage/matrix/misc.cpython-313-x86_64-linux-gnu.so +0 -0
  63. sage/matrix/misc.pyx +418 -0
  64. sage/modules/all__sagemath_linbox.py +1 -0
  65. sage/modules/numpy_util.cpython-313-x86_64-linux-gnu.so +0 -0
  66. sage/modules/numpy_util.pxd +10 -0
  67. sage/modules/numpy_util.pyx +136 -0
  68. sage/modules/vector_mod2_dense.cpython-313-x86_64-linux-gnu.so +0 -0
  69. sage/modules/vector_mod2_dense.pxd +11 -0
  70. sage/modules/vector_mod2_dense.pyx +547 -0
  71. sage/rings/all__sagemath_linbox.py +1 -0
  72. sage/rings/finite_rings/all__sagemath_linbox.py +1 -0
  73. sage/rings/polynomial/all__sagemath_linbox.py +1 -0
@@ -0,0 +1,871 @@
1
+ # sage_setup: distribution = sagemath-linbox
2
+ r"""
3
+ Sparse matrices over `\ZZ/n\ZZ` for `n` small
4
+
5
+ This is a compiled implementation of sparse matrices over
6
+ `\ZZ/n\ZZ` for `n` small.
7
+
8
+ .. TODO::
9
+
10
+ move vectors into a Cython vector class - add _add_ and _mul_ methods.
11
+
12
+ EXAMPLES::
13
+
14
+ sage: a = matrix(Integers(37),3,3,range(9),sparse=True); a
15
+ [0 1 2]
16
+ [3 4 5]
17
+ [6 7 8]
18
+ sage: type(a)
19
+ <class 'sage.matrix.matrix_modn_sparse.Matrix_modn_sparse'>
20
+ sage: parent(a)
21
+ Full MatrixSpace of 3 by 3 sparse matrices over Ring of integers modulo 37
22
+ sage: a^2
23
+ [15 18 21]
24
+ [ 5 17 29]
25
+ [32 16 0]
26
+ sage: a+a
27
+ [ 0 2 4]
28
+ [ 6 8 10]
29
+ [12 14 16]
30
+ sage: b = a.new_matrix(2,3,range(6)); b
31
+ [0 1 2]
32
+ [3 4 5]
33
+ sage: a*b
34
+ Traceback (most recent call last):
35
+ ...
36
+ TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 3 by 3 sparse matrices over Ring of integers modulo 37' and 'Full MatrixSpace of 2 by 3 sparse matrices over Ring of integers modulo 37'
37
+ sage: b*a
38
+ [15 18 21]
39
+ [ 5 17 29]
40
+
41
+ ::
42
+
43
+ sage: TestSuite(a).run()
44
+ sage: TestSuite(b).run()
45
+
46
+ ::
47
+
48
+ sage: a.echelonize(); a
49
+ [ 1 0 36]
50
+ [ 0 1 2]
51
+ [ 0 0 0]
52
+ sage: b.echelonize(); b
53
+ [ 1 0 36]
54
+ [ 0 1 2]
55
+ sage: a.pivots()
56
+ (0, 1)
57
+ sage: b.pivots()
58
+ (0, 1)
59
+ sage: a.rank()
60
+ 2
61
+ sage: b.rank()
62
+ 2
63
+ sage: a[2,2] = 5
64
+ sage: a.rank()
65
+ 3
66
+
67
+ TESTS::
68
+
69
+ sage: matrix(Integers(37),0,0,sparse=True).inverse()
70
+ []
71
+ """
72
+
73
+ # ****************************************************************************
74
+ # Copyright (C) 2006 William Stein <wstein@gmail.com>
75
+ #
76
+ # This program is free software: you can redistribute it and/or modify
77
+ # it under the terms of the GNU General Public License as published by
78
+ # the Free Software Foundation, either version 2 of the License, or
79
+ # (at your option) any later version.
80
+ # https://www.gnu.org/licenses/
81
+ # ****************************************************************************
82
+
83
+ from libc.stdint cimport uint64_t
84
+ from libc.limits cimport UINT_MAX
85
+
86
+ from cysignals.memory cimport check_calloc, sig_free
87
+ from cysignals.signals cimport sig_on, sig_off
88
+
89
+ cimport sage.libs.linbox.givaro as givaro
90
+ cimport sage.libs.linbox.linbox as linbox
91
+
92
+ from sage.arith.misc import is_prime
93
+ from sage.data_structures.binary_search cimport *
94
+ from sage.ext.stdsage cimport PY_NEW
95
+ from sage.libs.flint.fmpz cimport fmpz_get_mpz, fmpz_set_mpz
96
+ from sage.libs.flint.fmpz_mat cimport fmpz_mat_entry
97
+ from sage.libs.gmp.mpz cimport mpz_set
98
+ from sage.libs.linbox.conversion cimport (get_method,
99
+ METHOD_DEFAULT,
100
+ METHOD_DENSE_ELIMINATION,
101
+ METHOD_SPARSE_ELIMINATION,
102
+ METHOD_BLACKBOX,
103
+ METHOD_WIEDEMANN,
104
+ new_linbox_matrix_modn_sparse,
105
+ new_linbox_matrix_integer_sparse,
106
+ new_linbox_vector_integer_dense,
107
+ new_sage_vector_integer_dense)
108
+ from sage.matrix.args cimport SparseEntry, MatrixArgs_init
109
+ from sage.matrix.matrix2 import Matrix as Matrix2
110
+ from sage.matrix.matrix_dense cimport Matrix_dense
111
+ from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense
112
+ from sage.matrix.matrix_sparse cimport Matrix_sparse
113
+ from sage.misc.verbose import verbose, get_verbose
114
+ from sage.modules.vector_integer_dense cimport Vector_integer_dense
115
+ from sage.modules.vector_integer_sparse cimport *
116
+ from sage.modules.vector_modn_sparse cimport *
117
+ from sage.rings.fast_arith cimport arith_int
118
+ from sage.rings.finite_rings.integer_mod cimport IntegerMod_int, IntegerMod_abstract
119
+ from sage.rings.integer cimport Integer
120
+ from sage.rings.integer_ring import ZZ
121
+ from sage.rings.rational_field import QQ
122
+ from sage.structure.element cimport Matrix
123
+
124
+ ################
125
+ # TODO: change this to use extern cdef's methods.
126
+ cdef arith_int ai
127
+ ai = arith_int()
128
+ ################
129
+
130
+ # The 46341 below is because the mod-n sparse code still uses
131
+ # int's, even on 64-bit computers. Improving this is
132
+ # Github Issue #12679.
133
+ MAX_MODULUS = 46341
134
+
135
+ cdef class Matrix_modn_sparse(Matrix_sparse):
136
+ def __cinit__(self):
137
+ nr = self._nrows
138
+ nc = self._ncols
139
+ cdef int p = self._base_ring.order()
140
+ self.p = p
141
+
142
+ self.rows = <c_vector_modint*>check_calloc(nr, sizeof(c_vector_modint))
143
+
144
+ cdef Py_ssize_t i
145
+ for i in range(nr):
146
+ init_c_vector_modint(&self.rows[i], p, nc, 0)
147
+
148
+ def __dealloc__(self):
149
+ cdef Py_ssize_t i
150
+ if self.rows:
151
+ for i in range(self._nrows):
152
+ clear_c_vector_modint(&self.rows[i])
153
+ sig_free(self.rows)
154
+
155
+ def __init__(self, parent, entries=None, copy=None, bint coerce=True):
156
+ r"""
157
+ Create a sparse matrix over the integers modulo ``n``.
158
+
159
+ INPUT:
160
+
161
+ - ``parent`` -- a matrix space over the integers modulo ``n``
162
+
163
+ - ``entries`` -- see :func:`matrix`
164
+
165
+ - ``copy`` -- ignored (for backwards compatibility)
166
+
167
+ - ``coerce`` -- if ``False``, assume without checking that the
168
+ entries lie in the base ring
169
+ """
170
+ ma = MatrixArgs_init(parent, entries)
171
+ for t in ma.iter(coerce, True):
172
+ se = <SparseEntry>t
173
+ z = se.entry
174
+ if z:
175
+ set_entry(&self.rows[se.i], se.j, z)
176
+
177
+ cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, value):
178
+ set_entry(&self.rows[i], j, (<IntegerMod_int> value).ivalue)
179
+
180
+ cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
181
+ cdef IntegerMod_int n
182
+ n = IntegerMod_int.__new__(IntegerMod_int)
183
+ IntegerMod_abstract.__init__(n, self._base_ring)
184
+ n.ivalue = get_entry(&self.rows[i], j)
185
+ return n
186
+
187
+ cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1:
188
+ """
189
+ Return 1 if the entry ``(i, j)`` is zero, otherwise 0.
190
+
191
+ EXAMPLES::
192
+
193
+ sage: M = matrix(GF(13), [[0,1,0],[0,0,0]], sparse=True)
194
+ sage: M.zero_pattern_matrix() # indirect doctest
195
+ [1 0 1]
196
+ [1 1 1]
197
+ """
198
+ return is_entry_zero_unsafe(&self.rows[i], j)
199
+
200
+ def _dict(self):
201
+ """
202
+ Unsafe version of the dict method, mainly for internal use. This
203
+ may return the dict of elements, but as an *unsafe* reference to
204
+ the underlying dict of the object. It might be dangerous if you
205
+ change entries of the returned dict.
206
+
207
+ EXAMPLES::
208
+
209
+ sage: MS = MatrixSpace(GF(13), 50, 50, sparse=True)
210
+ sage: m = MS._random_nonzero_element(density=0.002)
211
+ sage: d = m._dict()
212
+ sage: for i in range(50):
213
+ ....: for j in range(50):
214
+ ....: if m[i, j] != 0:
215
+ ....: assert m[i, j] == d[i, j]
216
+ ....: else:
217
+ ....: assert (i, j) not in d
218
+
219
+ TESTS::
220
+
221
+ sage: [i, j] = list(d.keys())[0]
222
+ sage: parent(m._dict()[i, j])
223
+ Finite Field of size 13
224
+ """
225
+ d = self.fetch('dict')
226
+ if d is not None:
227
+ return d
228
+
229
+ cdef Py_ssize_t i, j
230
+ d = {}
231
+ cdef IntegerMod_int n
232
+ for i from 0 <= i < self._nrows:
233
+ for j from 0 <= j < self.rows[i].num_nonzero:
234
+ n = IntegerMod_int.__new__(IntegerMod_int)
235
+ IntegerMod_abstract.__init__(n, self._base_ring)
236
+ n.ivalue = self.rows[i].entries[j]
237
+ d[(int(i),int(self.rows[i].positions[j]))] = n
238
+ self.cache('dict', d)
239
+ return d
240
+
241
+ def _pickle(self):
242
+ """
243
+ TESTS::
244
+
245
+ sage: M = Matrix( GF(2), [[1,1,1,1,0,0,0,0,0,0]], sparse=True )
246
+ sage: loads(dumps(M))
247
+ [1 1 1 1 0 0 0 0 0 0]
248
+ sage: loads(dumps(M)) == M
249
+ True
250
+ """
251
+ return self._dict(), 1
252
+
253
+ def _unpickle(self, data, version):
254
+ if version == 1:
255
+ self.__init__(self.parent(), data, coerce=False)
256
+ else:
257
+ raise ValueError("unknown matrix format")
258
+
259
+ cdef Matrix _matrix_times_matrix_(self, Matrix _right):
260
+ """
261
+ This code is implicitly called for multiplying ``self`` by another
262
+ sparse matrix.
263
+
264
+ EXAMPLES::
265
+
266
+ sage: a = matrix(GF(43), 3, 3, range(9), sparse=True)
267
+ sage: b = matrix(GF(43), 3, 3, range(10,19), sparse=True)
268
+ sage: a*b
269
+ [ 2 5 8]
270
+ [33 2 14]
271
+ [21 42 20]
272
+ sage: a*a
273
+ [15 18 21]
274
+ [42 11 23]
275
+ [26 4 25]
276
+ sage: c = matrix(GF(43), 3, 8, range(24), sparse=True)
277
+ sage: a*c
278
+ [40 0 3 6 9 12 15 18]
279
+ [26 38 7 19 31 0 12 24]
280
+ [12 33 11 32 10 31 9 30]
281
+
282
+ Even though sparse and dense matrices are represented
283
+ differently, they still compare as equal if they have the
284
+ same entries::
285
+
286
+ sage: a*b == a._matrix_times_matrix_dense(b)
287
+ True
288
+ sage: d = matrix(GF(43), 3, 8, range(24))
289
+ sage: a*c == a*d
290
+ True
291
+
292
+ TESTS:
293
+
294
+ The following shows that :issue:`23669` has been addressed::
295
+
296
+ sage: p = next_prime(2**15)
297
+ sage: M = Matrix(GF(p), 1,3, lambda i,j: -1, sparse=True); M
298
+ [32770 32770 32770]
299
+ sage: M*M.transpose() # previously returned [32738]
300
+ [3]
301
+ """
302
+ cdef Matrix_modn_sparse right, ans
303
+ right = _right
304
+
305
+ cdef c_vector_modint* v
306
+
307
+ # Build a table that gives the nonzero positions in each column of right
308
+ cdef list nonzero_positions_in_columns = [set() for _ in range(right._ncols)]
309
+ cdef Py_ssize_t i, j, k
310
+ for i in range(right._nrows):
311
+ v = &(right.rows[i])
312
+ for j in range(v.num_nonzero):
313
+ (<set> nonzero_positions_in_columns[v.positions[j]]).add(i)
314
+
315
+ ans = self.new_matrix(self._nrows, right._ncols)
316
+
317
+ # Now do the multiplication, getting each row completely before filling it in.
318
+ cdef int x, y, s
319
+ cdef set c
320
+
321
+ for i in range(self._nrows):
322
+ v = &(self.rows[i])
323
+ for j in range(right._ncols):
324
+ s = 0
325
+ c = <set> nonzero_positions_in_columns[j]
326
+ for k in range(v.num_nonzero):
327
+ if v.positions[k] in c:
328
+ y = get_entry(&right.rows[v.positions[k]], j)
329
+ x = v.entries[k] * y
330
+ s = (s + x) % self.p
331
+ set_entry(&ans.rows[i], j, s)
332
+ return ans
333
+
334
+ def _matrix_times_matrix_dense(self, Matrix _right):
335
+ """
336
+ Multiply ``self`` by the sparse matrix ``_right``, and return the
337
+ result as a dense matrix.
338
+
339
+ EXAMPLES::
340
+
341
+ sage: # needs sage.rings.finite_rings
342
+ sage: a = matrix(GF(10007), 2, [1,2,3,4], sparse=True)
343
+ sage: b = matrix(GF(10007), 2, 3, [1..6], sparse=True)
344
+ sage: a * b
345
+ [ 9 12 15]
346
+ [19 26 33]
347
+ sage: c = a._matrix_times_matrix_dense(b); c
348
+ [ 9 12 15]
349
+ [19 26 33]
350
+ sage: type(c)
351
+ <class 'sage.matrix.matrix_modn_dense_double.Matrix_modn_dense_double'>
352
+
353
+ sage: a = matrix(GF(2), 20, 20, sparse=True)
354
+ sage: a*a == a._matrix_times_matrix_dense(a)
355
+ True
356
+ sage: type(a._matrix_times_matrix_dense(a))
357
+ <class 'sage.matrix.matrix_mod2_dense.Matrix_mod2_dense'>
358
+ """
359
+ cdef Matrix_modn_sparse right
360
+ cdef Matrix_dense ans
361
+ right = _right
362
+
363
+ cdef c_vector_modint* v
364
+
365
+ # Build a table that gives the nonzero positions in each column of right
366
+ nonzero_positions_in_columns = [set() for _ in range(right._ncols)]
367
+ cdef Py_ssize_t i, j, k
368
+ for i from 0 <= i < right._nrows:
369
+ v = &(right.rows[i])
370
+ for j from 0 <= j < right.rows[i].num_nonzero:
371
+ nonzero_positions_in_columns[v.positions[j]].add(i)
372
+
373
+ ans = self.new_matrix(self._nrows, right._ncols, sparse=False)
374
+
375
+ # Now do the multiplication, getting each row completely before filling it in.
376
+ cdef int x, y, s
377
+
378
+ for i from 0 <= i < self._nrows:
379
+ v = &self.rows[i]
380
+ for j from 0 <= j < right._ncols:
381
+ s = 0
382
+ c = nonzero_positions_in_columns[j]
383
+ for k from 0 <= k < v.num_nonzero:
384
+ if v.positions[k] in c:
385
+ y = get_entry(&right.rows[v.positions[k]], j)
386
+ x = v.entries[k] * y
387
+ s = (s + x) % self.p
388
+ ans.set_unsafe_int(i, j, s)
389
+ #ans._matrix[i][j] = s
390
+ return ans
391
+
392
+ def swap_rows(self, r1, r2):
393
+ self.check_bounds_and_mutability(r1,0)
394
+ self.check_bounds_and_mutability(r2,0)
395
+ self.swap_rows_c(r1, r2)
396
+
397
+ cdef swap_rows_c(self, Py_ssize_t n1, Py_ssize_t n2):
398
+ """
399
+ Swap the rows in positions n1 and n2. No bounds checking.
400
+ """
401
+ cdef c_vector_modint tmp
402
+ tmp = self.rows[n1]
403
+ self.rows[n1] = self.rows[n2]
404
+ self.rows[n2] = tmp
405
+
406
+ cpdef _echelon_in_place(self, str algorithm):
407
+ """
408
+ Replace ``self`` by its reduction to reduced row echelon form.
409
+
410
+ ALGORITHM: We use Gauss elimination, in a slightly intelligent way,
411
+ in that we clear each column using a row with the minimum number of
412
+ nonzero entries.
413
+
414
+ TODO: Implement switching to a dense method when the matrix gets
415
+ dense.
416
+ """
417
+ from sage.misc.verbose import verbose, get_verbose
418
+ x = self.fetch('in_echelon_form')
419
+ if x is not None and x:
420
+ return # already known to be in echelon form
421
+ self.check_mutability()
422
+
423
+ cdef Py_ssize_t i, r, c, min, min_row, start_row
424
+ cdef int a_inverse, b, do_verb
425
+ cdef c_vector_modint tmp
426
+ start_row = 0
427
+ pivots = []
428
+ fifth = self._ncols / 10 + 1
429
+ tm = verbose(caller_name = 'sparse_matrix_pyx matrix_modint echelon')
430
+ do_verb = (get_verbose() >= 2)
431
+
432
+ for c from 0 <= c < self._ncols:
433
+ if do_verb and (c % fifth == 0 and c>0):
434
+ tm = verbose('on column %s of %s' % (c, self._ncols),
435
+ level = 2,
436
+ caller_name = 'matrix_modn_sparse echelon')
437
+ #end if
438
+ min = self._ncols + 1
439
+ min_row = -1
440
+ for r from start_row <= r < self._nrows:
441
+ if self.rows[r].num_nonzero > 0 and self.rows[r].num_nonzero < min:
442
+ # Since there is at least one nonzero entry, the first entry
443
+ # of the positions list is defined. It is the first position
444
+ # of a nonzero entry, and it equals c precisely if row r
445
+ # is a row we could use to clear column c.
446
+ if self.rows[r].positions[0] == c:
447
+ min_row = r
448
+ min = self.rows[r].num_nonzero
449
+ #endif
450
+ #endif
451
+ #endfor
452
+ if min_row != -1:
453
+ r = min_row
454
+ # print("min number of entries in a pivoting row = ", min)
455
+ pivots.append(c)
456
+ # Since we can use row r to clear column c, the
457
+ # entry in position c in row r must be the first nonzero entry.
458
+ a = self.rows[r].entries[0]
459
+ if a != 1:
460
+ a_inverse = ai.c_inverse_mod_int(a, self.p)
461
+ scale_c_vector_modint(&self.rows[r], a_inverse)
462
+ self.swap_rows_c(r, start_row)
463
+ sig_on()
464
+ for i from 0 <= i < self._nrows:
465
+ if i != start_row:
466
+ b = get_entry(&self.rows[i], c)
467
+ if b != 0:
468
+ add_c_vector_modint_init(&tmp, &self.rows[i],
469
+ &self.rows[start_row], self.p - b)
470
+ clear_c_vector_modint(&self.rows[i])
471
+ self.rows[i] = tmp
472
+ sig_off()
473
+ start_row = start_row + 1
474
+
475
+ self.cache('pivots', tuple(pivots))
476
+ self.cache('in_echelon_form', True)
477
+
478
+ def _nonzero_positions_by_row(self, copy=True):
479
+ """
480
+ Return the list of pairs (i,j) such that self[i,j] != 0.
481
+
482
+ It is safe to change the resulting list (unless you give the option copy=False).
483
+
484
+ EXAMPLES::
485
+
486
+ sage: M = Matrix(GF(7), [[0,0,0,1,0,0,0,0],[0,1,0,0,0,0,1,0]], sparse=True); M
487
+ [0 0 0 1 0 0 0 0]
488
+ [0 1 0 0 0 0 1 0]
489
+ sage: M.nonzero_positions()
490
+ [(0, 3), (1, 1), (1, 6)]
491
+ """
492
+ x = self.fetch('nonzero_positions')
493
+ if x is not None:
494
+ if copy:
495
+ return list(x)
496
+ return x
497
+ nzp = []
498
+ cdef Py_ssize_t i, j
499
+ for i from 0 <= i < self._nrows:
500
+ for j from 0 <= j < self.rows[i].num_nonzero:
501
+ nzp.append((i,self.rows[i].positions[j]))
502
+ self.cache('nonzero_positions', nzp)
503
+ if copy:
504
+ return list(nzp)
505
+ return nzp
506
+
507
+ def density(self):
508
+ """
509
+ Return the density of ``self``, i.e., the ratio of the number of
510
+ nonzero entries of ``self`` to the total size of ``self``.
511
+
512
+ EXAMPLES::
513
+
514
+ sage: A = matrix(QQ,3,3,[0,1,2,3,0,0,6,7,8],sparse=True)
515
+ sage: A.density()
516
+ 2/3
517
+
518
+ Notice that the density parameter does not ensure the density
519
+ of a matrix; it is only an upper bound.
520
+
521
+ ::
522
+
523
+ sage: A = random_matrix(GF(127), 200, 200, density=0.3, sparse=True)
524
+ sage: density_sum = float(A.density())
525
+ sage: total = 1
526
+ sage: expected_density = 1.0 - (199/200)^60
527
+ sage: expected_density
528
+ 0.2597...
529
+ sage: while abs(density_sum/total - expected_density) > 0.001:
530
+ ....: A = random_matrix(GF(127), 200, 200, density=0.3, sparse=True)
531
+ ....: density_sum += float(A.density())
532
+ ....: total += 1
533
+ """
534
+ cdef Py_ssize_t i, nonzero_entries
535
+
536
+ nonzero_entries = 0
537
+ for i from 0 <= i < self._nrows:
538
+ nonzero_entries += self.rows[i].num_nonzero
539
+
540
+ return ZZ(nonzero_entries) / ZZ(self._nrows*self._ncols)
541
+
542
+ def transpose(self):
543
+ """
544
+ Return the transpose of ``self``.
545
+
546
+ EXAMPLES::
547
+
548
+ sage: A = matrix(GF(127),3,3,[0,1,0,2,0,0,3,0,0],sparse=True)
549
+ sage: A
550
+ [0 1 0]
551
+ [2 0 0]
552
+ [3 0 0]
553
+ sage: A.transpose()
554
+ [0 2 3]
555
+ [1 0 0]
556
+ [0 0 0]
557
+
558
+ ``.T`` is a convenient shortcut for the transpose::
559
+
560
+ sage: A.T
561
+ [0 2 3]
562
+ [1 0 0]
563
+ [0 0 0]
564
+ """
565
+ cdef Py_ssize_t i, j
566
+ cdef c_vector_modint row
567
+ cdef Matrix_modn_sparse B
568
+
569
+ B = self.new_matrix(nrows = self.ncols(), ncols = self.nrows())
570
+ for i from 0 <= i < self._nrows:
571
+ row = self.rows[i]
572
+ for j from 0 <= j < row.num_nonzero:
573
+ set_entry(&B.rows[row.positions[j]], i, row.entries[j])
574
+ if self._subdivisions is not None:
575
+ row_divs, col_divs = self.subdivisions()
576
+ B.subdivide(col_divs, row_divs)
577
+ return B
578
+
579
+ def matrix_from_rows(self, rows):
580
+ """
581
+ Return the matrix constructed from ``self`` using rows with indices in
582
+ the rows list.
583
+
584
+ INPUT:
585
+
586
+ - ``rows`` -- list or tuple of row indices
587
+
588
+ EXAMPLES::
589
+
590
+ sage: M = MatrixSpace(GF(127),3,3,sparse=True)
591
+ sage: A = M(range(9)); A
592
+ [0 1 2]
593
+ [3 4 5]
594
+ [6 7 8]
595
+ sage: A.matrix_from_rows([2,1])
596
+ [6 7 8]
597
+ [3 4 5]
598
+ """
599
+ cdef Py_ssize_t i,k
600
+ cdef Matrix_modn_sparse A
601
+ cdef c_vector_modint row
602
+
603
+ if not isinstance(rows, (list, tuple)):
604
+ rows = list(rows)
605
+
606
+ A = self.new_matrix(nrows = len(rows))
607
+
608
+ k = 0
609
+ for ii in rows:
610
+ i = ii
611
+ if i < 0 or i >= self.nrows():
612
+ raise IndexError("row %s out of range" % i)
613
+
614
+ row = self.rows[i]
615
+ for j from 0 <= j < row.num_nonzero:
616
+ set_entry(&A.rows[k], row.positions[j], row.entries[j])
617
+ k += 1
618
+ return A
619
+
620
+ def matrix_from_columns(self, cols):
621
+ """
622
+ Return the matrix constructed from ``self`` using columns with indices
623
+ in the columns list.
624
+
625
+ EXAMPLES::
626
+
627
+ sage: M = MatrixSpace(GF(127),3,3,sparse=True)
628
+ sage: A = M(range(9)); A
629
+ [0 1 2]
630
+ [3 4 5]
631
+ [6 7 8]
632
+ sage: A.matrix_from_columns([2,1])
633
+ [2 1]
634
+ [5 4]
635
+ [8 7]
636
+ """
637
+ cdef Py_ssize_t i,j
638
+ cdef Matrix_modn_sparse A
639
+ cdef c_vector_modint row
640
+
641
+ if not isinstance(cols, (list, tuple)):
642
+ cols = list(cols)
643
+
644
+ A = self.new_matrix(ncols = len(cols))
645
+
646
+ cols = dict(zip([int(e) for e in cols],range(len(cols))))
647
+
648
+ for i from 0 <= i < self.nrows():
649
+ row = self.rows[i]
650
+ for j from 0 <= j < row.num_nonzero:
651
+ if int(row.positions[j]) in cols:
652
+ set_entry(&A.rows[i], cols[int(row.positions[j])], row.entries[j])
653
+ return A
654
+
655
+ def _rank_det_linbox(self):
656
+ """
657
+ Return the rank and determinant using linbox.
658
+
659
+ .. NOTE::
660
+
661
+ This method does not perform any caching contrarily to
662
+ :meth:`determinant` and :meth:`rank`.
663
+
664
+ EXAMPLES::
665
+
666
+ sage: m = matrix(Zmod(13), 1, sparse=True)
667
+ sage: m[0,0] = 0
668
+ sage: m._rank_det_linbox()
669
+ (0, 0)
670
+ sage: for i in range(1, 13):
671
+ ....: m[0,0] = i
672
+ ....: assert m._rank_det_linbox() == (1, i)
673
+
674
+ sage: m = matrix(GF(5), 2, sparse=True)
675
+ sage: m[0,0] = 1
676
+ sage: m[0,1] = 2
677
+ sage: m[1,0] = 1
678
+ sage: m[1,1] = 3
679
+ sage: m._rank_det_linbox()
680
+ (2, 1)
681
+ sage: m
682
+ [1 2]
683
+ [1 3]
684
+
685
+ TESTS::
686
+
687
+ sage: matrix(Zmod(3), 0, sparse=True)._rank_det_linbox()
688
+ (0, 1)
689
+ """
690
+ if self._nrows == 0 or self._ncols == 0:
691
+ # TODO: bug in linbox (gives segfault)
692
+ return 0, self.base_ring().one()
693
+
694
+ cdef size_t A_rank = 0
695
+ cdef uint64_t A_det = 0
696
+
697
+ if not is_prime(self.p):
698
+ raise TypeError("only GF(p) supported via LinBox")
699
+
700
+ cdef givaro.Modular_uint64 * F = new givaro.Modular_uint64(<uint64_t> self.p)
701
+ cdef linbox.SparseMatrix_Modular_uint64 * A
702
+ A = new_linbox_matrix_modn_sparse(F[0], self)
703
+
704
+ cdef linbox.GaussDomain_Modular_uint64 * dom = new linbox.GaussDomain_Modular_uint64(F[0])
705
+
706
+ # NOTE: see above for the reason of casting...
707
+ if A.rowdim() >= <size_t> UINT_MAX or A.coldim() >= <size_t> UINT_MAX:
708
+ raise ValueError("row/column size unsupported in LinBox")
709
+
710
+ dom.InPlaceLinearPivoting(A_rank, A_det, A[0], A.rowdim(), A.coldim())
711
+
712
+ del A
713
+ del F
714
+ del dom
715
+
716
+ return <long> A_rank, self.base_ring()(A_det)
717
+
718
+ def rank(self, algorithm=None):
719
+ """
720
+ Return the rank of this matrix.
721
+
722
+ INPUT:
723
+
724
+ - ``algorithm`` -- either ``'linbox'`` (only available for
725
+ matrices over prime fields) or ``'generic'``
726
+
727
+ EXAMPLES::
728
+
729
+ sage: A = matrix(GF(127), 2, 2, sparse=True)
730
+ sage: A[0,0] = 34
731
+ sage: A[0,1] = 102
732
+ sage: A[1,0] = 55
733
+ sage: A[1,1] = 74
734
+ sage: A.rank()
735
+ 2
736
+
737
+ sage: A._clear_cache()
738
+ sage: A.rank(algorithm='generic')
739
+ 2
740
+ sage: A._clear_cache()
741
+ sage: A.rank(algorithm='hey')
742
+ Traceback (most recent call last):
743
+ ...
744
+ ValueError: no algorithm 'hey'
745
+
746
+ TESTS::
747
+
748
+ sage: matrix(GF(3), 0, sparse=True).rank(algorithm='generic')
749
+ 0
750
+ sage: matrix(GF(3), 0, sparse=True).rank(algorithm='linbox')
751
+ 0
752
+
753
+ sage: for _ in range(50):
754
+ ....: nrows = randint(0, 100)
755
+ ....: ncols = randint(0, 100)
756
+ ....: p = random_prime(10000)
757
+ ....: M = MatrixSpace(GF(p), nrows, ncols, sparse=True)
758
+ ....: m = M.random_element()
759
+ ....: rank_linbox = m.rank(algorithm='linbox')
760
+ ....: rank_generic = m.rank(algorithm='generic')
761
+ ....: if rank_linbox != rank_generic:
762
+ ....: print(m)
763
+ ....: raise RuntimeError
764
+
765
+ REFERENCES:
766
+
767
+ - Jean-Guillaume Dumas and Gilles Villars. 'Computing the Rank
768
+ of Large Sparse Matrices over Finite
769
+ Fields'. Proc. CASC'2002, The Fifth International Workshop
770
+ on Computer Algebra in Scientific Computing, Big Yalta,
771
+ Crimea, Ukraine, 22-27 sept. 2002, Springer-Verlag,
772
+ http://perso.ens-lyon.fr/gilles.villard/BIBLIOGRAPHIE/POSTSCRIPT/rankjgd.ps
773
+
774
+ .. NOTE::
775
+
776
+ For very sparse matrices Gaussian elimination is faster
777
+ because it barely has anything to do. If the fill in needs to
778
+ be considered, 'Symbolic Reordering' is usually much faster.
779
+ """
780
+ if self._nrows == 0 or self._ncols == 0:
781
+ return 0
782
+
783
+ if not is_prime(self.p):
784
+ raise ArithmeticError("rank not well defined for matrices over general ring")
785
+
786
+ x = self.fetch('rank')
787
+ if x is not None:
788
+ return x
789
+
790
+ if algorithm is None or algorithm == "linbox":
791
+ rank, det = self._rank_det_linbox()
792
+ self.cache("rank", rank)
793
+ self.cache("det", det)
794
+ return rank
795
+
796
+ elif algorithm == "generic":
797
+ return Matrix2.rank(self)
798
+
799
+ else:
800
+ raise ValueError("no algorithm '%s'" % algorithm)
801
+
802
+ def determinant(self, algorithm=None):
803
+ r"""
804
+ Return the determinant of this matrix.
805
+
806
+ INPUT:
807
+
808
+ - ``algorithm`` -- either ``'linbox'`` (default) or ``'generic'``
809
+
810
+ EXAMPLES::
811
+
812
+ sage: A = matrix(GF(3), 4, range(16), sparse=True)
813
+ sage: B = identity_matrix(GF(3), 4, sparse=True)
814
+ sage: (A + B).det()
815
+ 2
816
+ sage: (A + B).det(algorithm='linbox')
817
+ 2
818
+ sage: (A + B).det(algorithm='generic')
819
+ 2
820
+ sage: (A + B).det(algorithm='hey')
821
+ Traceback (most recent call last):
822
+ ...
823
+ ValueError: no algorithm 'hey'
824
+
825
+ sage: matrix(GF(11), 1, 2, sparse=True).det()
826
+ Traceback (most recent call last):
827
+ ...
828
+ ValueError: self must be a square matrix
829
+
830
+ TESTS::
831
+
832
+ sage: matrix(GF(3), 0, sparse=True).det(algorithm='generic')
833
+ 1
834
+ sage: matrix(GF(3), 0, sparse=True).det(algorithm='linbox')
835
+ 1
836
+
837
+ sage: for _ in range(100):
838
+ ....: dim = randint(0, 50)
839
+ ....: p = random_prime(10000)
840
+ ....: M = MatrixSpace(GF(p), dim, sparse=True)
841
+ ....: m = M.random_element()
842
+ ....: det_linbox = m.det(algorithm='linbox')
843
+ ....: det_generic = m.det(algorithm='generic')
844
+ ....: assert parent(det_linbox) == m.base_ring()
845
+ ....: assert parent(det_generic) == m.base_ring()
846
+ ....: if det_linbox != det_generic:
847
+ ....: print(m)
848
+ ....: raise RuntimeError
849
+ """
850
+ if self._nrows != self._ncols:
851
+ raise ValueError("self must be a square matrix")
852
+
853
+ if self._nrows == 0:
854
+ return self.base_ring().one()
855
+
856
+ d = self.fetch('det')
857
+ if d is not None:
858
+ return d
859
+
860
+ if algorithm is None or algorithm == "linbox":
861
+ r, d = self._rank_det_linbox()
862
+ self.cache('rank', r)
863
+ self.cache('det', d)
864
+ return d
865
+
866
+ if algorithm == 'generic':
867
+ d = Matrix_sparse.determinant(self)
868
+ self.cache('det', d)
869
+ return d
870
+
871
+ raise ValueError("no algorithm '%s'" % algorithm)