passagemath-ntl 10.6.38__cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.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-ntl might be problematic. Click here for more details.

Files changed (162) hide show
  1. passagemath_ntl/__init__.py +3 -0
  2. passagemath_ntl-10.6.38.dist-info/METADATA +122 -0
  3. passagemath_ntl-10.6.38.dist-info/RECORD +162 -0
  4. passagemath_ntl-10.6.38.dist-info/WHEEL +6 -0
  5. passagemath_ntl-10.6.38.dist-info/top_level.txt +3 -0
  6. passagemath_ntl.libs/libgf2x-fbd36f80.so.3.0.0 +0 -0
  7. passagemath_ntl.libs/libgmp-93ebf16a.so.10.5.0 +0 -0
  8. passagemath_ntl.libs/libmpfi-ad12a86d.so.0.0.0 +0 -0
  9. passagemath_ntl.libs/libmpfr-9d41ebf1.so.6.2.1 +0 -0
  10. passagemath_ntl.libs/libntl-1bc30f7e.so.45.0.0 +0 -0
  11. sage/all__sagemath_ntl.py +7 -0
  12. sage/libs/all__sagemath_ntl.py +3 -0
  13. sage/libs/mpfi/__init__.pxd +287 -0
  14. sage/libs/mpfi/types.pxd +10 -0
  15. sage/libs/ntl/GF2.pxd +18 -0
  16. sage/libs/ntl/GF2E.pxd +28 -0
  17. sage/libs/ntl/GF2EX.pxd +12 -0
  18. sage/libs/ntl/GF2X.pxd +81 -0
  19. sage/libs/ntl/ZZ.pxd +93 -0
  20. sage/libs/ntl/ZZX.pxd +85 -0
  21. sage/libs/ntl/ZZ_p.pxd +28 -0
  22. sage/libs/ntl/ZZ_pE.pxd +37 -0
  23. sage/libs/ntl/ZZ_pEX.pxd +106 -0
  24. sage/libs/ntl/ZZ_pX.pxd +122 -0
  25. sage/libs/ntl/__init__.py +4 -0
  26. sage/libs/ntl/all.py +72 -0
  27. sage/libs/ntl/conversion.pxd +106 -0
  28. sage/libs/ntl/convert.cpython-314-aarch64-linux-gnu.so +0 -0
  29. sage/libs/ntl/convert.pxd +7 -0
  30. sage/libs/ntl/convert.pyx +38 -0
  31. sage/libs/ntl/decl.pxi +18 -0
  32. sage/libs/ntl/error.cpython-314-aarch64-linux-gnu.so +0 -0
  33. sage/libs/ntl/error.pyx +63 -0
  34. sage/libs/ntl/lzz_p.pxd +20 -0
  35. sage/libs/ntl/lzz_pX.pxd +59 -0
  36. sage/libs/ntl/mat_GF2.pxd +30 -0
  37. sage/libs/ntl/mat_GF2E.pxd +30 -0
  38. sage/libs/ntl/mat_ZZ.pxd +59 -0
  39. sage/libs/ntl/misc.pxi +33 -0
  40. sage/libs/ntl/ntl_GF2.cpython-314-aarch64-linux-gnu.so +0 -0
  41. sage/libs/ntl/ntl_GF2.pxd +5 -0
  42. sage/libs/ntl/ntl_GF2.pyx +281 -0
  43. sage/libs/ntl/ntl_GF2E.cpython-314-aarch64-linux-gnu.so +0 -0
  44. sage/libs/ntl/ntl_GF2E.pxd +8 -0
  45. sage/libs/ntl/ntl_GF2E.pyx +488 -0
  46. sage/libs/ntl/ntl_GF2EContext.cpython-314-aarch64-linux-gnu.so +0 -0
  47. sage/libs/ntl/ntl_GF2EContext.pxd +9 -0
  48. sage/libs/ntl/ntl_GF2EContext.pyx +134 -0
  49. sage/libs/ntl/ntl_GF2EX.cpython-314-aarch64-linux-gnu.so +0 -0
  50. sage/libs/ntl/ntl_GF2EX.pxd +10 -0
  51. sage/libs/ntl/ntl_GF2EX.pyx +251 -0
  52. sage/libs/ntl/ntl_GF2X.cpython-314-aarch64-linux-gnu.so +0 -0
  53. sage/libs/ntl/ntl_GF2X.pxd +5 -0
  54. sage/libs/ntl/ntl_GF2X.pyx +771 -0
  55. sage/libs/ntl/ntl_GF2X_linkage.pxi +404 -0
  56. sage/libs/ntl/ntl_ZZ.cpython-314-aarch64-linux-gnu.so +0 -0
  57. sage/libs/ntl/ntl_ZZ.pxd +7 -0
  58. sage/libs/ntl/ntl_ZZ.pyx +541 -0
  59. sage/libs/ntl/ntl_ZZX.cpython-314-aarch64-linux-gnu.so +0 -0
  60. sage/libs/ntl/ntl_ZZX.pxd +7 -0
  61. sage/libs/ntl/ntl_ZZX.pyx +1206 -0
  62. sage/libs/ntl/ntl_ZZ_p.cpython-314-aarch64-linux-gnu.so +0 -0
  63. sage/libs/ntl/ntl_ZZ_p.pxd +10 -0
  64. sage/libs/ntl/ntl_ZZ_p.pyx +509 -0
  65. sage/libs/ntl/ntl_ZZ_pContext.cpython-314-aarch64-linux-gnu.so +0 -0
  66. sage/libs/ntl/ntl_ZZ_pContext.pxd +22 -0
  67. sage/libs/ntl/ntl_ZZ_pContext.pyx +201 -0
  68. sage/libs/ntl/ntl_ZZ_pE.cpython-314-aarch64-linux-gnu.so +0 -0
  69. sage/libs/ntl/ntl_ZZ_pE.pxd +11 -0
  70. sage/libs/ntl/ntl_ZZ_pE.pyx +349 -0
  71. sage/libs/ntl/ntl_ZZ_pEContext.cpython-314-aarch64-linux-gnu.so +0 -0
  72. sage/libs/ntl/ntl_ZZ_pEContext.pxd +23 -0
  73. sage/libs/ntl/ntl_ZZ_pEContext.pyx +226 -0
  74. sage/libs/ntl/ntl_ZZ_pEX.cpython-314-aarch64-linux-gnu.so +0 -0
  75. sage/libs/ntl/ntl_ZZ_pEX.pxd +10 -0
  76. sage/libs/ntl/ntl_ZZ_pEX.pyx +1255 -0
  77. sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi +420 -0
  78. sage/libs/ntl/ntl_ZZ_pX.cpython-314-aarch64-linux-gnu.so +0 -0
  79. sage/libs/ntl/ntl_ZZ_pX.pxd +17 -0
  80. sage/libs/ntl/ntl_ZZ_pX.pyx +1532 -0
  81. sage/libs/ntl/ntl_lzz_p.cpython-314-aarch64-linux-gnu.so +0 -0
  82. sage/libs/ntl/ntl_lzz_p.pxd +8 -0
  83. sage/libs/ntl/ntl_lzz_p.pyx +440 -0
  84. sage/libs/ntl/ntl_lzz_pContext.cpython-314-aarch64-linux-gnu.so +0 -0
  85. sage/libs/ntl/ntl_lzz_pContext.pxd +7 -0
  86. sage/libs/ntl/ntl_lzz_pContext.pyx +137 -0
  87. sage/libs/ntl/ntl_lzz_pX.cpython-314-aarch64-linux-gnu.so +0 -0
  88. sage/libs/ntl/ntl_lzz_pX.pxd +10 -0
  89. sage/libs/ntl/ntl_lzz_pX.pyx +902 -0
  90. sage/libs/ntl/ntl_mat_GF2.cpython-314-aarch64-linux-gnu.so +0 -0
  91. sage/libs/ntl/ntl_mat_GF2.pxd +8 -0
  92. sage/libs/ntl/ntl_mat_GF2.pyx +612 -0
  93. sage/libs/ntl/ntl_mat_GF2E.cpython-314-aarch64-linux-gnu.so +0 -0
  94. sage/libs/ntl/ntl_mat_GF2E.pxd +10 -0
  95. sage/libs/ntl/ntl_mat_GF2E.pyx +752 -0
  96. sage/libs/ntl/ntl_mat_ZZ.cpython-314-aarch64-linux-gnu.so +0 -0
  97. sage/libs/ntl/ntl_mat_ZZ.pxd +6 -0
  98. sage/libs/ntl/ntl_mat_ZZ.pyx +1523 -0
  99. sage/libs/ntl/ntl_tools.pxd +3 -0
  100. sage/libs/ntl/ntlwrap.h +53 -0
  101. sage/libs/ntl/ntlwrap_impl.h +743 -0
  102. sage/libs/ntl/types.pxd +157 -0
  103. sage/libs/ntl/vec_GF2.pxd +26 -0
  104. sage/libs/ntl/vec_GF2E.pxd +2 -0
  105. sage/matrix/all__sagemath_ntl.py +1 -0
  106. sage/matrix/matrix_modn_dense_double.pxd +10 -0
  107. sage/matrix/matrix_modn_dense_float.pxd +9 -0
  108. sage/matrix/matrix_modn_dense_template.pxi +3257 -0
  109. sage/matrix/matrix_modn_dense_template_header.pxi +15 -0
  110. sage/matrix/matrix_modn_sparse.pxd +8 -0
  111. sage/misc/all__sagemath_ntl.py +1 -0
  112. sage/rings/all__sagemath_ntl.py +7 -0
  113. sage/rings/bernmm.cpython-314-aarch64-linux-gnu.so +0 -0
  114. sage/rings/bernmm.pyx +161 -0
  115. sage/rings/bernoulli_mod_p.cpython-314-aarch64-linux-gnu.so +0 -0
  116. sage/rings/bernoulli_mod_p.pyx +313 -0
  117. sage/rings/finite_rings/all__sagemath_ntl.py +1 -0
  118. sage/rings/finite_rings/finite_field_ntl_gf2e.py +305 -0
  119. sage/rings/finite_rings/residue_field_ntl_gf2e.cpython-314-aarch64-linux-gnu.so +0 -0
  120. sage/rings/finite_rings/residue_field_ntl_gf2e.pyx +140 -0
  121. sage/rings/padics/all__sagemath_ntl.py +5 -0
  122. sage/rings/padics/padic_ZZ_pX_CA_element.cpython-314-aarch64-linux-gnu.so +0 -0
  123. sage/rings/padics/padic_ZZ_pX_CA_element.pxd +25 -0
  124. sage/rings/padics/padic_ZZ_pX_CA_element.pyx +2368 -0
  125. sage/rings/padics/padic_ZZ_pX_CR_element.cpython-314-aarch64-linux-gnu.so +0 -0
  126. sage/rings/padics/padic_ZZ_pX_CR_element.pxd +33 -0
  127. sage/rings/padics/padic_ZZ_pX_CR_element.pyx +3277 -0
  128. sage/rings/padics/padic_ZZ_pX_FM_element.cpython-314-aarch64-linux-gnu.so +0 -0
  129. sage/rings/padics/padic_ZZ_pX_FM_element.pxd +12 -0
  130. sage/rings/padics/padic_ZZ_pX_FM_element.pyx +1739 -0
  131. sage/rings/padics/padic_ZZ_pX_element.cpython-314-aarch64-linux-gnu.so +0 -0
  132. sage/rings/padics/padic_ZZ_pX_element.pxd +6 -0
  133. sage/rings/padics/padic_ZZ_pX_element.pyx +919 -0
  134. sage/rings/padics/padic_ext_element.cpython-314-aarch64-linux-gnu.so +0 -0
  135. sage/rings/padics/padic_ext_element.pxd +38 -0
  136. sage/rings/padics/padic_ext_element.pyx +512 -0
  137. sage/rings/padics/pow_computer_ext.cpython-314-aarch64-linux-gnu.so +0 -0
  138. sage/rings/padics/pow_computer_ext.pxd +107 -0
  139. sage/rings/padics/pow_computer_ext.pyx +2401 -0
  140. sage/rings/polynomial/all__sagemath_ntl.py +1 -0
  141. sage/rings/polynomial/evaluation_ntl.cpython-314-aarch64-linux-gnu.so +0 -0
  142. sage/rings/polynomial/evaluation_ntl.pxd +7 -0
  143. sage/rings/polynomial/evaluation_ntl.pyx +70 -0
  144. sage/rings/polynomial/polynomial_gf2x.cpython-314-aarch64-linux-gnu.so +0 -0
  145. sage/rings/polynomial/polynomial_gf2x.pxd +10 -0
  146. sage/rings/polynomial/polynomial_gf2x.pyx +364 -0
  147. sage/rings/polynomial/polynomial_integer_dense_ntl.cpython-314-aarch64-linux-gnu.so +0 -0
  148. sage/rings/polynomial/polynomial_integer_dense_ntl.pxd +8 -0
  149. sage/rings/polynomial/polynomial_integer_dense_ntl.pyx +1128 -0
  150. sage/rings/polynomial/polynomial_modn_dense_ntl.cpython-314-aarch64-linux-gnu.so +0 -0
  151. sage/rings/polynomial/polynomial_modn_dense_ntl.pxd +36 -0
  152. sage/rings/polynomial/polynomial_modn_dense_ntl.pyx +2049 -0
  153. sage/rings/polynomial/polynomial_template.pxi +842 -0
  154. sage/rings/polynomial/polynomial_template_header.pxi +11 -0
  155. sage/rings/polynomial/polynomial_zz_pex.cpython-314-aarch64-linux-gnu.so +0 -0
  156. sage/rings/polynomial/polynomial_zz_pex.pxd +12 -0
  157. sage/rings/polynomial/polynomial_zz_pex.pyx +778 -0
  158. sage/rings/real_mpfi.pxd +50 -0
  159. sage/schemes/all__sagemath_ntl.py +1 -0
  160. sage/schemes/hyperelliptic_curves/all__sagemath_ntl.py +1 -0
  161. sage/schemes/hyperelliptic_curves/hypellfrob.cpython-314-aarch64-linux-gnu.so +0 -0
  162. sage/schemes/hyperelliptic_curves/hypellfrob.pyx +252 -0
@@ -0,0 +1,3257 @@
1
+ # sage_setup: distribution = sagemath-ntl
2
+ r"""
3
+ Dense matrices over `\ZZ/n\ZZ` for `n` small using the LinBox library (FFLAS/FFPACK)
4
+
5
+ FFLAS/FFPACK are libraries to provide BLAS/LAPACK-style routines for
6
+ working with finite fields. Additionally, these routines reduce to
7
+ BLAS/LAPACK routines using floating point arithmetic.
8
+
9
+ EXAMPLES::
10
+
11
+ sage: A = matrix(GF(127), 7, 7, range(49))
12
+ sage: A*A
13
+ [ 2 23 44 65 86 107 1]
14
+ [ 15 85 28 98 41 111 54]
15
+ [ 28 20 12 4 123 115 107]
16
+ [ 41 82 123 37 78 119 33]
17
+ [ 54 17 107 70 33 123 86]
18
+ [ 67 79 91 103 115 0 12]
19
+ [ 80 14 75 9 70 4 65]
20
+ sage: A.rank()
21
+ 2
22
+
23
+ sage: A = matrix(GF(127), 4, 4, [106, 98, 24, 84, 108, 7, 94, 71, 96, 100, 15, 42, 80, 56, 72, 35])
24
+ sage: A.rank()
25
+ 4
26
+ sage: v = vector(GF(127), 4, (100, 93, 47, 110))
27
+ sage: x = A.solve_right(v)
28
+ sage: A*x == v
29
+ True
30
+
31
+ AUTHORS:
32
+
33
+ - William Stein (2004-2006): some functions in this file were copied
34
+ from ``matrix_modn_dense.pyx`` which was mainly written by William
35
+ Stein
36
+ - Clement Pernet (2010): LinBox related functions in this file were
37
+ taken from linbox-sage.C by Clement Pernet
38
+ - Burcin Erocal (2010-2011): most of the functions present in this file
39
+ - Martin Albrecht (2011): some polishing, bug fixes, documentation
40
+ - Rob Beezer (2011): documentation
41
+
42
+ TESTS:
43
+
44
+ We test corner cases for multiplication::
45
+
46
+ sage: v0 = vector(GF(3),[])
47
+ sage: v1 = vector(GF(3),[1])
48
+ sage: m00 = matrix(GF(3),0,0,[])
49
+ sage: m01 = matrix(GF(3),0,1,[])
50
+ sage: m10 = matrix(GF(3),1,0,[])
51
+ sage: m11 = matrix(GF(3),1,1,[1])
52
+ sage: good = [ (v0,m00), (v0,m01), (v1,m10), (v1,m11), (m00,v0), (m10,v0), (m01,v1), (m11,v1), (m00,m00), (m01,m10), (m10,m01), (m11,m11) ]
53
+ sage: for v, m in good:
54
+ ....: print('{} x {} = {}'.format(v, m, v * m))
55
+ () x [] = ()
56
+ () x [] = (0)
57
+ (1) x [] = ()
58
+ (1) x [1] = (1)
59
+ [] x () = ()
60
+ [] x () = (0)
61
+ [] x (1) = ()
62
+ [1] x (1) = (1)
63
+ [] x [] = []
64
+ [] x [] = []
65
+ [] x [] = [0]
66
+ [1] x [1] = [1]
67
+
68
+ sage: bad = [ (v1,m00), (v1,m01), (v0,m10), (v0,m11), (m00,v1), (m10,v1), (m01,v0), (m11,v0), (m01,m01), (m10,m10), (m11,m01), (m10,m11) ]
69
+ sage: for v, m in bad:
70
+ ....: try:
71
+ ....: v*m
72
+ ....: print('Uncaught dimension mismatch!')
73
+ ....: except (IndexError, TypeError, ArithmeticError):
74
+ ....: pass
75
+ """
76
+
77
+ # ****************************************************************************
78
+ # Copyright (C) 2004,2005,2006 William Stein <wstein@gmail.com>
79
+ # Copyright (C) 2011 Burcin Erocal <burcin@erocal.org>
80
+ # Copyright (C) 2011 Martin Albrecht <martinralbrecht@googlemail.com>
81
+ # Copyright (C) 2011 Rob Beezer
82
+ #
83
+ # This program is free software: you can redistribute it and/or modify
84
+ # it under the terms of the GNU General Public License as published by
85
+ # the Free Software Foundation, either version 2 of the License, or
86
+ # (at your option) any later version.
87
+ # https://www.gnu.org/licenses/
88
+ # ****************************************************************************
89
+
90
+ from libc.stdint cimport uint64_t
91
+ from cpython.bytes cimport *
92
+
93
+ from cysignals.memory cimport check_malloc, check_allocarray, check_calloc, sig_malloc, sig_free
94
+ from cysignals.signals cimport sig_check, sig_on, sig_off
95
+
96
+ from sage.libs.gmp.mpz cimport *
97
+ from sage.libs.linbox.fflas cimport FFLAS_TRANSPOSE, FflasNoTrans, FflasTrans, \
98
+ FflasRight, vector, list as std_list
99
+ from libcpp cimport bool
100
+ from sage.parallel.parallelism import Parallelism
101
+
102
+ cimport sage.rings.fast_arith
103
+ cdef sage.rings.fast_arith.arith_int ArithIntObj
104
+ ArithIntObj = sage.rings.fast_arith.arith_int()
105
+
106
+ # for copying/pickling
107
+ from libc.string cimport memcpy
108
+ from libc.stdio cimport snprintf
109
+
110
+ from sage.modules.vector_modn_dense cimport Vector_modn_dense
111
+
112
+ from sage.arith.misc import is_prime
113
+ from sage.structure.element cimport (Element, Vector, Matrix,
114
+ ModuleElement, RingElement)
115
+ from sage.matrix.matrix_dense cimport Matrix_dense
116
+ from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense
117
+ from sage.rings.finite_rings.integer_mod cimport IntegerMod_int, IntegerMod_abstract
118
+ from sage.misc.timing import cputime
119
+ from sage.misc.verbose import verbose, get_verbose
120
+ from sage.rings.integer cimport Integer
121
+ from sage.rings.integer_ring import ZZ
122
+ from sage.structure.proof.proof import get_flag as get_proof_flag
123
+ from sage.structure.richcmp cimport rich_to_bool
124
+ from sage.misc.randstate cimport randstate, current_randstate
125
+ import sage.matrix.matrix_space as matrix_space
126
+ from sage.matrix.args cimport SparseEntry, MatrixArgs_init
127
+
128
+
129
+ from sage.cpython.string cimport char_to_str
130
+
131
+ cdef long num = 1
132
+ cdef bint little_endian = (<char*>(&num))[0]
133
+
134
+ cdef inline celement_invert(celement a, celement n):
135
+ """
136
+ Invert the finite field element `a` modulo `n`.
137
+ """
138
+ # This is copied from linbox source linbox/field/modular-float.h
139
+ # The extended Euclidean algorithm
140
+ cdef int x_int, y_int, q, tx, ty, temp
141
+ x_int = <int>n
142
+ y_int = <int>a
143
+ tx = 0
144
+ ty = 1
145
+
146
+ while y_int != 0:
147
+ # always: gcd (n,residue) = gcd (x_int,y_int)
148
+ # sx*n + tx*residue = x_int
149
+ # sy*n + ty*residue = y_int
150
+ q = x_int / y_int # integer quotient
151
+ temp = y_int
152
+ y_int = x_int - q * y_int
153
+ x_int = temp
154
+ temp = ty
155
+ ty = tx - q * ty
156
+ tx = temp
157
+
158
+ if tx < 0:
159
+ tx += <int>n
160
+
161
+ # now x_int = gcd (n,residue)
162
+ return <celement>tx
163
+
164
+ cdef inline bint linbox_is_zero(celement modulus, celement* entries, Py_ssize_t nrows, Py_ssize_t ncols) except -1:
165
+ """
166
+ Return 1 if all entries of this matrix are zero.
167
+ """
168
+ cdef Py_ssize_t i, j
169
+ for i in range(nrows):
170
+ for j in range(ncols):
171
+ if (entries+i*ncols+j)[0] != 0:
172
+ return 0
173
+ return 1
174
+
175
+ cdef inline linbox_echelonize(celement modulus, celement* entries, Py_ssize_t nrows, Py_ssize_t ncols):
176
+ """
177
+ Return the reduced row echelon form of this matrix.
178
+ """
179
+ if linbox_is_zero(modulus, entries, nrows, ncols):
180
+ return 0, []
181
+
182
+ cdef Py_ssize_t i, j
183
+ cdef ModField *F = new ModField(<long>modulus)
184
+ cdef size_t* P = <size_t*>check_allocarray(nrows, sizeof(size_t))
185
+ cdef size_t* Q = <size_t*>check_allocarray(ncols, sizeof(size_t))
186
+
187
+ cdef Py_ssize_t r
188
+ cdef size_t nbthreads
189
+ nbthreads = Parallelism().get('linbox')
190
+ cdef bool transform = False
191
+ if nrows * ncols > 1000:
192
+ sig_on()
193
+ if nbthreads > 1 :
194
+ r = pReducedRowEchelonForm(F[0], nrows, ncols, <ModField.Element*>entries, ncols, P, Q, transform, nbthreads)
195
+ else :
196
+ r = ReducedRowEchelonForm(F[0], nrows, ncols, <ModField.Element*>entries, ncols, P, Q)
197
+ if nrows * ncols > 1000:
198
+ sig_off()
199
+
200
+ for i in range(nrows):
201
+ for j in range(r):
202
+ (entries+i*ncols+j)[0] = 0
203
+ if i<r:
204
+ (entries + i*(ncols+1))[0] = 1
205
+
206
+ applyP(F[0], FflasRight, FflasNoTrans, nrows, 0, r, <ModField.Element*>entries, ncols, Q)
207
+
208
+ cdef list pivots = [int(Q[i]) for i in range(r)]
209
+
210
+ sig_free(P)
211
+ sig_free(Q)
212
+ del F
213
+ return r, pivots
214
+
215
+ cdef inline linbox_echelonize_efd(celement modulus, celement* entries, Py_ssize_t nrows, Py_ssize_t ncols):
216
+ # See trac #13878: This is to avoid sending invalid data to linbox,
217
+ # which would yield a segfault in Sage's debug version. TODO: Fix
218
+ # that bug upstream.
219
+ if nrows == 0 or ncols == 0:
220
+ return 0, []
221
+
222
+ cdef ModField *F = new ModField(<long>modulus)
223
+ cdef DenseMatrix *A = new DenseMatrix(F[0], nrows, ncols)
224
+
225
+ cdef Py_ssize_t i, j
226
+ for i in range(nrows):
227
+ for j in range(ncols):
228
+ A.setEntry(i, j, entries[i*ncols+j])
229
+
230
+ cdef Py_ssize_t r = reducedRowEchelonize(A[0])
231
+ for i in range(nrows):
232
+ for j in range(ncols):
233
+ entries[i*ncols+j] = <celement>A.getEntry(i, j)
234
+
235
+ cdef Py_ssize_t ii = 0
236
+ cdef list pivots = []
237
+ for i in range(r):
238
+ for j in range(ii, ncols):
239
+ if entries[i*ncols+j] == 1:
240
+ pivots.append(j)
241
+ ii = j+1
242
+ break
243
+
244
+ del F
245
+ return r, pivots
246
+
247
+ cdef inline celement *linbox_copy(celement modulus, celement *entries, Py_ssize_t nrows, Py_ssize_t ncols) except? NULL:
248
+ """
249
+ Create a copy of the entries array.
250
+ """
251
+ cdef celement *entries_copy = <celement*>check_allocarray(nrows * ncols, sizeof(celement))
252
+ memcpy(entries_copy, entries, sizeof(celement)*nrows*ncols)
253
+ return entries_copy
254
+
255
+ cdef inline int linbox_rank(celement modulus, celement* entries, Py_ssize_t nrows, Py_ssize_t ncols) except -1:
256
+ """
257
+ Return the rank of this matrix.
258
+ """
259
+ cdef ModField *F = new ModField(<long>modulus)
260
+
261
+ cdef celement *cpy = linbox_copy(modulus, entries, nrows, ncols)
262
+
263
+ cdef Py_ssize_t r
264
+ cdef size_t nbthreads
265
+ nbthreads = Parallelism().get('linbox')
266
+ if nrows * ncols > 1000:
267
+ sig_on()
268
+ if nbthreads > 1:
269
+ r = pRank(F[0], nrows, ncols, <ModField.Element*>cpy, ncols, nbthreads)
270
+ else:
271
+ r = Rank(F[0], nrows, ncols, <ModField.Element*>cpy, ncols)
272
+ if nrows * ncols > 1000:
273
+ sig_off()
274
+ sig_free(cpy)
275
+ del F
276
+ return r
277
+
278
+ cdef inline celement linbox_det(celement modulus, celement* entries, Py_ssize_t n) noexcept:
279
+ """
280
+ Return the determinant of this matrix.
281
+ """
282
+ cdef ModField *F = new ModField(<long>modulus)
283
+ cdef celement *cpy = linbox_copy(modulus, entries, n, n)
284
+
285
+ cdef celement d = 0
286
+ cdef size_t nbthreads
287
+ nbthreads = Parallelism().get('linbox')
288
+
289
+ if n*n > 1000:
290
+ sig_on()
291
+ if nbthreads > 1 :
292
+ pDet(F[0], d, n, <ModField.Element*>cpy, n, nbthreads)
293
+ else :
294
+ Det(F[0], d, n, <ModField.Element*>cpy, n)
295
+ if n*n > 1000:
296
+ sig_off()
297
+ sig_free(cpy)
298
+ del F
299
+ return d
300
+
301
+ cdef inline celement linbox_matrix_matrix_multiply(celement modulus, celement* ans, celement* A, celement* B, Py_ssize_t m, Py_ssize_t n, Py_ssize_t k) noexcept:
302
+ """
303
+ C = A*B
304
+ """
305
+ cdef ModField *F = new ModField(<long>modulus)
306
+ cdef ModField.Element one = 0, zero = 0
307
+ F[0].init(one, <int>1)
308
+ F[0].init(zero, <int>0)
309
+
310
+ cdef size_t nbthreads
311
+ nbthreads = Parallelism().get('linbox')
312
+
313
+ if m*n*k > 100000:
314
+ sig_on()
315
+ if nbthreads > 1 :
316
+ pfgemm(F[0], FflasNoTrans, FflasNoTrans, m, n, k, one,
317
+ <ModField.Element*>A, k, <ModField.Element*>B, n, zero,
318
+ <ModField.Element*>ans, n, nbthreads)
319
+ else:
320
+ fgemm(F[0], FflasNoTrans, FflasNoTrans, m, n, k, one,
321
+ <ModField.Element*>A, k, <ModField.Element*>B, n, zero,
322
+ <ModField.Element*>ans, n)
323
+
324
+ if m*n*k > 100000:
325
+ sig_off()
326
+
327
+ del F
328
+
329
+ cdef inline int linbox_matrix_vector_multiply(celement modulus, celement* C, celement* A, celement* b, Py_ssize_t m, Py_ssize_t n, FFLAS_TRANSPOSE trans) noexcept:
330
+ """
331
+ C = A*v
332
+ """
333
+ cdef ModField *F = new ModField(<long>modulus)
334
+ cdef ModField.Element one = 0, zero = 0
335
+ F.init(one, <int>1)
336
+ F.init(zero, <int>0)
337
+
338
+ if m*n > 100000:
339
+ sig_on()
340
+
341
+ fgemv(F[0], trans, m, n, one, <ModField.Element*>A, n, <ModField.Element*>b, 1,
342
+ zero, <ModField.Element*>C, 1)
343
+
344
+ if m*n > 100000:
345
+ sig_off()
346
+
347
+ del F
348
+
349
+ cdef inline linbox_minpoly(celement modulus, Py_ssize_t nrows, celement* entries):
350
+ """
351
+ Compute the minimal polynomial.
352
+ """
353
+ cdef Py_ssize_t i
354
+ cdef ModField *F = new ModField(<long>modulus)
355
+ cdef vector[ModField.Element] *minP = new vector[ModField.Element]()
356
+
357
+ if nrows*nrows > 1000:
358
+ sig_on()
359
+ MinPoly(F[0], minP[0], nrows, <ModField.Element*>entries, nrows)
360
+ if nrows*nrows > 1000:
361
+ sig_off()
362
+
363
+ l = [<celement>minP.at(i) for i in range(minP.size())]
364
+
365
+ del F
366
+ return l
367
+
368
+ cdef inline linbox_charpoly(celement modulus, Py_ssize_t nrows, celement* entries):
369
+ """
370
+ Compute the characteristic polynomial.
371
+ """
372
+ cdef Py_ssize_t i
373
+ cdef ModField *F = new ModField(<long>modulus)
374
+ cdef ModDensePolyRing * R = new ModDensePolyRing(F[0])
375
+ cdef ModDensePoly P
376
+
377
+ cdef celement *cpy = linbox_copy(modulus, entries, nrows, nrows)
378
+
379
+ if nrows * nrows > 1000:
380
+ sig_on()
381
+ CharPoly(R[0], P, nrows, <ModField.Element*>cpy, nrows)
382
+ if nrows * nrows > 1000:
383
+ sig_off()
384
+
385
+ sig_free(cpy)
386
+
387
+ l = []
388
+ for i in range(P.size()):
389
+ l.append(<celement>P[i])
390
+
391
+ del F
392
+ del R
393
+ return l
394
+
395
+
396
+ cpdef __matrix_from_rows_of_matrices(X):
397
+ """
398
+ Return a matrix whose row ``i`` is constructed from the entries of
399
+ matrix ``X[i]``.
400
+
401
+ INPUT:
402
+
403
+ - ``X`` -- a nonempty list of matrices of the same size mod a
404
+ single modulus `n`
405
+
406
+ EXAMPLES::
407
+
408
+ sage: X = [random_matrix(GF(17), 4, 4) for _ in range(10)]
409
+ sage: Y = X[0]._matrix_from_rows_of_matrices(X) # indirect doctest
410
+ sage: all(list(Y[i]) == X[i].list() for i in range(10))
411
+ True
412
+
413
+ OUTPUT: a single matrix mod ``p`` whose ``i``-th row is ``X[i].list()``.
414
+
415
+ .. NOTE::
416
+
417
+ Do not call this function directly but use the static method
418
+ ``Matrix_modn_dense_float/double._matrix_from_rows_of_matrices``
419
+ """
420
+ # The code below is just a fast version of the following:
421
+ # from constructor import matrix
422
+ # K = X[0].base_ring()
423
+ # v = sum([y.list() for y in X],[])
424
+ # return matrix(K, len(X), X[0].nrows()*X[0].ncols(), v)
425
+
426
+ cdef Matrix_modn_dense_template T
427
+ cdef Py_ssize_t i, n, m
428
+ n = len(X)
429
+
430
+ T = X[0]
431
+ m = T._nrows * T._ncols
432
+ cdef Matrix_modn_dense_template A = T.new_matrix(nrows=n, ncols=m)
433
+
434
+ for i from 0 <= i < n:
435
+ T = X[i]
436
+ memcpy(A._entries + i*m, T._entries, sizeof(celement)*m)
437
+ return A
438
+
439
+
440
+ cdef class Matrix_modn_dense_template(Matrix_dense):
441
+ def __cinit__(self, *args, bint zeroed_alloc=True, **kwds):
442
+ cdef long p = self._base_ring.characteristic()
443
+ self.p = p
444
+ if p >= MAX_MODULUS:
445
+ raise OverflowError("p (=%s) must be < %s." % (p, MAX_MODULUS))
446
+
447
+ if zeroed_alloc:
448
+ self._entries = <celement *> check_calloc(self._nrows * self._ncols, sizeof(celement))
449
+ else:
450
+ self._entries = <celement *> check_allocarray(self._nrows * self._ncols, sizeof(celement))
451
+
452
+ # TODO: it is a bit of a waste to allocate _matrix when ncols=0. Though some
453
+ # of the code expects self._matrix[i] to be valid, even though it points to
454
+ # an empty vector.
455
+ self._matrix = <celement **> check_allocarray(self._nrows, sizeof(celement*))
456
+ if self._nrows == 0:
457
+ return
458
+
459
+ cdef Py_ssize_t i
460
+ self._matrix[0] = self._entries
461
+ for i in range(self._nrows - 1):
462
+ self._matrix[i + 1] = self._matrix[i] + self._ncols
463
+
464
+ def __dealloc__(self):
465
+ """
466
+ TESTS::
467
+
468
+ sage: import gc
469
+ sage: for i in range(10): # needs sage.libs.linbox sage.rings.finite_rings
470
+ ....: A = random_matrix(GF(7),1000,1000)
471
+ ....: B = random_matrix(Integers(10),1000,1000)
472
+ ....: C = random_matrix(GF(16007),1000,1000)
473
+ ....: D = random_matrix(Integers(1000),1000,1000)
474
+ ....: del A
475
+ ....: del B
476
+ ....: del C
477
+ ....: del D
478
+ ....: _ = gc.collect()
479
+ """
480
+ sig_free(self._entries)
481
+ sig_free(self._matrix)
482
+
483
+ def __init__(self, parent, entries=None, copy=None, bint coerce=True):
484
+ r"""
485
+ Create a new matrix.
486
+
487
+ INPUT:
488
+
489
+ - ``parent`` -- a matrix space
490
+
491
+ - ``entries`` -- see :func:`matrix`
492
+
493
+ - ``copy`` -- ignored (for backwards compatibility)
494
+
495
+ - ``coerce`` -- perform modular reduction first?
496
+
497
+ EXAMPLES::
498
+
499
+ sage: A = random_matrix(GF(3),1000,1000)
500
+ sage: type(A)
501
+ <class 'sage.matrix.matrix_modn_dense_float.Matrix_modn_dense_float'>
502
+ sage: A = random_matrix(Integers(10),1000,1000)
503
+ sage: type(A)
504
+ <class 'sage.matrix.matrix_modn_dense_float.Matrix_modn_dense_float'>
505
+ sage: A = random_matrix(Integers(2^16),1000,1000)
506
+ sage: type(A)
507
+ <class 'sage.matrix.matrix_modn_dense_double.Matrix_modn_dense_double'>
508
+
509
+ TESTS::
510
+
511
+ sage: Matrix(GF(7), 2, 2, [-1, int(-2), GF(7)(-3), 1/4])
512
+ [6 5]
513
+ [4 2]
514
+
515
+ sage: Matrix(GF(6434383), 2, 2, [-1, int(-2), GF(7)(-3), 1/4]) # needs sage.rings.finite_rings
516
+ [6434382 6434381]
517
+ [ 4 1608596]
518
+
519
+ sage: Matrix(Integers(4618990), 2, 2, [-1, int(-2), GF(7)(-3), 1/7]) # needs sage.rings.finite_rings
520
+ [4618989 4618988]
521
+ [ 4 2639423]
522
+
523
+ sage: Matrix(IntegerModRing(200), [[int(2**128+1), int(2**256+1), int(2**1024+1)]]) # needs sage.rings.finite_rings
524
+ [ 57 137 17]
525
+ """
526
+ ma = MatrixArgs_init(parent, entries)
527
+ cdef long i, j
528
+ it = ma.iter(convert=False, sparse=True)
529
+ R = ma.base
530
+ p = R.characteristic()
531
+
532
+ for t in it:
533
+ se = <SparseEntry>t
534
+ x = se.entry
535
+ v = self._matrix[se.i]
536
+ if type(x) is IntegerMod_int and (<IntegerMod_int>x)._parent is R:
537
+ v[se.j] = <celement>(<IntegerMod_int>x).ivalue
538
+ elif type(x) is Integer:
539
+ if coerce:
540
+ v[se.j] = mpz_fdiv_ui((<Integer>x).value, p)
541
+ else:
542
+ v[se.j] = mpz_get_ui((<Integer>x).value)
543
+ elif coerce:
544
+ v[se.j] = R(x)
545
+ else:
546
+ v[se.j] = <celement>x
547
+
548
+ cdef long _hash_(self) except -1:
549
+ """
550
+ EXAMPLES::
551
+
552
+ sage: B = random_matrix(GF(127),3,3)
553
+ sage: B.set_immutable()
554
+ sage: _ = {B:0} # indirect doctest
555
+
556
+ sage: M = random_matrix(GF(7), 10, 10)
557
+ sage: M.set_immutable()
558
+ sage: _ = hash(M)
559
+ sage: MZ = M.change_ring(ZZ)
560
+ sage: MZ.set_immutable()
561
+ sage: hash(MZ) == hash(M)
562
+ True
563
+ sage: MS = M.sparse_matrix()
564
+ sage: MS.set_immutable()
565
+ sage: hash(MS) == hash(M)
566
+ True
567
+
568
+ TESTS::
569
+
570
+ sage: A = matrix(GF(2),2,0)
571
+ sage: hash(A)
572
+ Traceback (most recent call last):
573
+ ...
574
+ TypeError: mutable matrices are unhashable
575
+ sage: A.set_immutable()
576
+ sage: hash(A)
577
+ 0
578
+ """
579
+ cdef long C[5]
580
+ self.get_hash_constants(C)
581
+
582
+ cdef long h = 0, k, l
583
+ cdef Py_ssize_t i, j
584
+ cdef celement* row
585
+ sig_on()
586
+ for i in range(self._nrows):
587
+ k = C[0] if i == 0 else C[1] + C[2] * i
588
+ row = self._matrix[i]
589
+ for j in range(self._ncols):
590
+ l = C[3] * (i - j) * (i ^ j)
591
+ h += (k ^ l) * <long>(row[j])
592
+ h *= C[4]
593
+ sig_off()
594
+
595
+ if h == -1:
596
+ return -2
597
+ return h
598
+
599
+ def _pickle(self):
600
+ """
601
+ Utility function for pickling.
602
+
603
+ If the prime is small enough to fit in a byte, then it is
604
+ stored as a contiguous string of bytes (to save
605
+ space). Otherwise, memcpy is used to copy the raw data in the
606
+ platforms native format. Endianness is dealt with when
607
+ unpickling.
608
+
609
+ EXAMPLES::
610
+
611
+ sage: m = matrix(Integers(128), 3, 3, [ord(c) for c in "Hi there!"]); m
612
+ [ 72 105 32]
613
+ [116 104 101]
614
+ [114 101 33]
615
+ sage: m._pickle()
616
+ ((1, ..., ...'Hi there!'), 10)
617
+
618
+ .. todo::
619
+
620
+ The upcoming buffer protocol would be useful to not have
621
+ to do any copying.
622
+ """
623
+ cdef Py_ssize_t i, j
624
+ cdef unsigned char* us
625
+ cdef mod_int *um
626
+ cdef unsigned char* row_us
627
+ cdef mod_int *row_um
628
+ cdef long word_size
629
+ cdef celement *row_self
630
+
631
+ if self.p <= 0xFF:
632
+ word_size = sizeof(unsigned char)
633
+ else:
634
+ word_size = sizeof(mod_int)
635
+
636
+ cdef void *buf = check_allocarray(self._nrows * self._ncols, word_size)
637
+
638
+ sig_on()
639
+ try:
640
+ if word_size == sizeof(unsigned char):
641
+ us = <unsigned char*>buf
642
+ for i in range(self._nrows):
643
+ row_self = self._matrix[i]
644
+ row_us = us + i*self._ncols
645
+ for j in range(self._ncols):
646
+ row_us[j] = <mod_int>row_self[j]
647
+ else:
648
+ um = <mod_int*>buf
649
+ for i in range(self._nrows):
650
+ row_self = self._matrix[i]
651
+ row_um = um + i*self._ncols
652
+ for j in range(self._ncols):
653
+ row_um[j] = <mod_int>row_self[j]
654
+
655
+ s = PyBytes_FromStringAndSize(<char*>buf, word_size * self._nrows * self._ncols)
656
+ finally:
657
+ sig_free(buf)
658
+ sig_off()
659
+ return (word_size, little_endian, s), 10
660
+
661
+ def _unpickle(self, data, int version):
662
+ """
663
+ TESTS:
664
+
665
+ Test for char-sized modulus::
666
+
667
+ sage: A = random_matrix(GF(7), 5, 9)
668
+ sage: data, version = A._pickle()
669
+ sage: B = A.parent()(0)
670
+ sage: B._unpickle(data, version)
671
+ sage: B == A
672
+ True
673
+
674
+ And for larger modulus::
675
+
676
+ sage: # needs sage.rings.finite_rings
677
+ sage: A = random_matrix(GF(1009), 51, 5)
678
+ sage: data, version = A._pickle()
679
+ sage: B = A.parent()(0)
680
+ sage: B._unpickle(data, version)
681
+ sage: B == A
682
+ True
683
+
684
+ Now test all the bit-packing options::
685
+
686
+ sage: A = matrix(Integers(1000), 2, 2)
687
+ sage: A._unpickle((1, True, b'\x01\x02\xFF\x00'), 10)
688
+ sage: A
689
+ [ 1 2]
690
+ [255 0]
691
+
692
+ sage: A = matrix(Integers(1000), 1, 2)
693
+ sage: A._unpickle((4, True, b'\x02\x01\x00\x00\x01\x00\x00\x00'), 10)
694
+ sage: A
695
+ [258 1]
696
+ sage: A._unpickle((4, False, b'\x00\x00\x02\x01\x00\x00\x01\x03'), 10)
697
+ sage: A
698
+ [513 259]
699
+ sage: A._unpickle((8, True, b'\x03\x01\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00'), 10)
700
+ sage: A
701
+ [259 5]
702
+ sage: A._unpickle((8, False, b'\x00\x00\x00\x00\x00\x00\x02\x08\x00\x00\x00\x00\x00\x00\x01\x04'), 10)
703
+ sage: A
704
+ [520 260]
705
+
706
+ Now make sure it works in context::
707
+
708
+ sage: A = random_matrix(Integers(33), 31, 31)
709
+ sage: loads(dumps(A)) == A
710
+ True
711
+ sage: A = random_matrix(Integers(3333), 31, 31)
712
+ sage: loads(dumps(A)) == A
713
+ True
714
+ """
715
+ if version < 10:
716
+ return Matrix_dense._unpickle(self, data, version)
717
+
718
+ cdef Py_ssize_t i, j
719
+ cdef unsigned char* us
720
+ cdef long word_size
721
+ cdef celement *row_self
722
+ cdef bint little_endian_data
723
+ cdef char* buf
724
+ cdef Py_ssize_t buflen
725
+ cdef Py_ssize_t expectedlen
726
+ cdef mod_int v
727
+
728
+ if version == 10:
729
+ word_size, little_endian_data, s = data
730
+ expectedlen = word_size * self._nrows * self._ncols
731
+
732
+ PyBytes_AsStringAndSize(s, &buf, &buflen)
733
+ if buflen != expectedlen:
734
+ raise ValueError("incorrect size in matrix pickle (expected %d, got %d)" % (expectedlen, buflen))
735
+
736
+ sig_on()
737
+ try:
738
+ if word_size == 1:
739
+ us = <unsigned char*>buf
740
+ for i from 0 <= i < self._nrows:
741
+ row_self = self._matrix[i]
742
+ for j from 0 <= j < self._ncols:
743
+ row_self[j] = <celement>(us[0])
744
+ us += word_size
745
+
746
+ elif word_size >= 4 and little_endian_data:
747
+ us = <unsigned char*>buf
748
+ for i from 0 <= i < self._nrows:
749
+ row_self = self._matrix[i]
750
+ for j from 0 <= j < self._ncols:
751
+ v = <mod_int>(us[0])
752
+ v += <mod_int>(us[1]) << 8
753
+ v += <mod_int>(us[2]) << 16
754
+ v += <mod_int>(us[3]) << 24
755
+ row_self[j] = <celement>v
756
+ us += word_size
757
+
758
+ elif word_size >= 4 and not little_endian_data:
759
+ us = <unsigned char*>buf
760
+ for i from 0 <= i < self._nrows:
761
+ row_self = self._matrix[i]
762
+ for j from 0 <= j < self._ncols:
763
+ v = <mod_int>(us[word_size-1])
764
+ v += <mod_int>(us[word_size-2]) << 8
765
+ v += <mod_int>(us[word_size-3]) << 16
766
+ v += <mod_int>(us[word_size-4]) << 24
767
+ row_self[j] = <celement>v
768
+ us += word_size
769
+
770
+ else:
771
+ raise ValueError("unknown matrix pickle format")
772
+ finally:
773
+ sig_off()
774
+ else:
775
+ raise ValueError("unknown matrix pickle version")
776
+
777
+ def __neg__(self):
778
+ """
779
+ EXAMPLES::
780
+
781
+ sage: A = matrix(GF(19), 3, 3, range(9)); A
782
+ [0 1 2]
783
+ [3 4 5]
784
+ [6 7 8]
785
+
786
+ sage: -A
787
+ [ 0 18 17]
788
+ [16 15 14]
789
+ [13 12 11]
790
+ """
791
+ cdef Py_ssize_t i, j
792
+ cdef Matrix_modn_dense_template M
793
+ cdef celement p = self.p
794
+
795
+ M = self.__class__.__new__(self.__class__, self._parent,
796
+ None, None, None, zeroed_alloc=False)
797
+
798
+ sig_on()
799
+ for i in range(self._nrows*self._ncols):
800
+ if self._entries[i]:
801
+ M._entries[i] = p - self._entries[i]
802
+ else:
803
+ M._entries[i] = 0
804
+ sig_off()
805
+ return M
806
+
807
+ cpdef _lmul_(self, Element left):
808
+ """
809
+ EXAMPLES::
810
+
811
+ sage: A = matrix(GF(101), 3, 3, range(9)); A
812
+ [0 1 2]
813
+ [3 4 5]
814
+ [6 7 8]
815
+ sage: A * 5
816
+ [ 0 5 10]
817
+ [15 20 25]
818
+ [30 35 40]
819
+ sage: A * 50
820
+ [ 0 50 100]
821
+ [ 49 99 48]
822
+ [ 98 47 97]
823
+
824
+ ::
825
+
826
+ sage: A = random_matrix(Integers(60), 400, 500)
827
+ sage: 3*A + 9*A == 12*A
828
+ True
829
+ """
830
+ cdef Py_ssize_t i, j
831
+ cdef Matrix_modn_dense_template M
832
+ cdef celement p = self.p
833
+ cdef celement a = left
834
+
835
+ M = self.__class__.__new__(self.__class__, self._parent,
836
+ None, None, None, zeroed_alloc=False)
837
+
838
+ sig_on()
839
+ for i in range(self._nrows*self._ncols):
840
+ M._entries[i] = (a*self._entries[i]) % p
841
+ sig_off()
842
+ return M
843
+
844
+ def __copy__(self):
845
+ """
846
+ EXAMPLES::
847
+
848
+ sage: A = random_matrix(GF(127), 100, 100)
849
+ sage: copy(A) == A
850
+ True
851
+ sage: copy(A) is A
852
+ False
853
+ """
854
+ cdef Matrix_modn_dense_template A
855
+ A = self.__class__.__new__(self.__class__, self._parent,
856
+ None, None, None, zeroed_alloc=False)
857
+ memcpy(A._entries, self._entries, sizeof(celement)*self._nrows*self._ncols)
858
+ if self._subdivisions is not None:
859
+ A.subdivide(*self.subdivisions())
860
+ return A
861
+
862
+ cpdef _add_(self, right):
863
+ r"""
864
+ Add two dense matrices over `\Z/n\Z`.
865
+
866
+ INPUT:
867
+
868
+ - ``right`` -- a matrix
869
+
870
+ EXAMPLES::
871
+
872
+ sage: A = MatrixSpace(GF(19),3)(range(9))
873
+ sage: A+A
874
+ [ 0 2 4]
875
+ [ 6 8 10]
876
+ [12 14 16]
877
+
878
+ sage: B = MatrixSpace(GF(19),3)(range(9))
879
+ sage: B.swap_rows(1,2)
880
+ sage: A+B
881
+ [ 0 2 4]
882
+ [ 9 11 13]
883
+ [ 9 11 13]
884
+
885
+ sage: B+A
886
+ [ 0 2 4]
887
+ [ 9 11 13]
888
+ [ 9 11 13]
889
+ """
890
+ cdef Py_ssize_t i
891
+ cdef celement k, p
892
+ cdef Matrix_modn_dense_template M
893
+
894
+ M = self.__class__.__new__(self.__class__, self._parent,
895
+ None, None, None, zeroed_alloc=False)
896
+ p = self.p
897
+ cdef celement* other_ent = (<Matrix_modn_dense_template>right)._entries
898
+
899
+ sig_on()
900
+ for i in range(self._nrows*self._ncols):
901
+ k = self._entries[i] + other_ent[i]
902
+ M._entries[i] = k - (k >= p) * p
903
+ sig_off()
904
+ return M
905
+
906
+ cpdef _sub_(self, right):
907
+ r"""
908
+ Subtract two dense matrices over `\Z/n\Z`.
909
+
910
+ EXAMPLES::
911
+
912
+ sage: A = matrix(GF(11), 3, 3, range(9)); A
913
+ [0 1 2]
914
+ [3 4 5]
915
+ [6 7 8]
916
+
917
+ sage: A - 4
918
+ [7 1 2]
919
+ [3 0 5]
920
+ [6 7 4]
921
+
922
+ sage: A - matrix(GF(11), 3, 3, range(1, 19, 2))
923
+ [10 9 8]
924
+ [ 7 6 5]
925
+ [ 4 3 2]
926
+ """
927
+ cdef Py_ssize_t i
928
+ cdef celement k, p
929
+ cdef Matrix_modn_dense_template M
930
+
931
+ M = self.__class__.__new__(self.__class__, self._parent, None, None, None, zeroed_alloc=False)
932
+ p = self.p
933
+ cdef celement* other_ent = (<Matrix_modn_dense_template>right)._entries
934
+
935
+ sig_on()
936
+ for i in range(self._nrows*self._ncols):
937
+ k = p + self._entries[i] - other_ent[i]
938
+ M._entries[i] = k - (k >= p) * p
939
+ sig_off()
940
+ return M
941
+
942
+ cpdef _richcmp_(self, right, int op):
943
+ r"""
944
+ Compare two dense matrices over `\Z/n\Z`.
945
+
946
+ EXAMPLES::
947
+
948
+ sage: A = matrix(GF(17), 4, range(3, 83, 5)); A
949
+ [ 3 8 13 1]
950
+ [ 6 11 16 4]
951
+ [ 9 14 2 7]
952
+ [12 0 5 10]
953
+ sage: A == A
954
+ True
955
+ sage: B = A - 3; B
956
+ [ 0 8 13 1]
957
+ [ 6 8 16 4]
958
+ [ 9 14 16 7]
959
+ [12 0 5 7]
960
+ sage: B < A
961
+ True
962
+ sage: B > A
963
+ False
964
+ sage: B == A
965
+ False
966
+ sage: B + 3 == A
967
+ True
968
+
969
+ ::
970
+
971
+ sage: A = matrix(ZZ, 10, 10, range(1000, 1100))
972
+ sage: A.change_ring(GF(17)) == A.change_ring(GF(17))
973
+ True
974
+ sage: A.change_ring(GF(17)) == A.change_ring(GF(19)) # needs sage.rings.finite_rings
975
+ False
976
+ sage: A.change_ring(GF(17)) == A.change_ring(Integers(2000)) # needs sage.rings.finite_rings
977
+ False
978
+ sage: A.change_ring(GF(17)) == A.change_ring(Integers(2000)) # needs sage.rings.finite_rings
979
+ False
980
+ """
981
+ cdef Py_ssize_t i
982
+ cdef celement* other_ent = (<Matrix_modn_dense_template>right)._entries
983
+ sig_on()
984
+ for i in range(self._nrows * self._ncols):
985
+ if self._entries[i] < other_ent[i]:
986
+ sig_off()
987
+ return rich_to_bool(op, -1)
988
+ elif self._entries[i] > other_ent[i]:
989
+ sig_off()
990
+ return rich_to_bool(op, 1)
991
+ sig_off()
992
+ return rich_to_bool(op, 0)
993
+
994
+ cdef _matrix_times_matrix_(self, Matrix right):
995
+ """
996
+ Return ``self*right``.
997
+
998
+ INPUT:
999
+
1000
+ - ``right``- a matrix
1001
+
1002
+ EXAMPLES::
1003
+
1004
+ sage: A = random_matrix(GF(7),2,2)
1005
+ sage: B = random_matrix(GF(7),2,2)
1006
+ sage: C = A*B
1007
+ sage: all(C[i, j] == sum(A[i, k]*B[k, j] for k in range(2)) for i in range(2) for j in range(2))
1008
+ True
1009
+
1010
+ sage: MS = parent(A)
1011
+ sage: MS(3) * A == 3*A
1012
+ True
1013
+
1014
+ ::
1015
+
1016
+ sage: A = random_matrix(GF(17), 201, 117)
1017
+ sage: B = random_matrix(GF(17), 117, 195)
1018
+ sage: C = random_matrix(GF(17), 201, 117)
1019
+ sage: D = random_matrix(GF(17), 117, 195)
1020
+
1021
+ sage: E = (A+C)*(B+D)
1022
+
1023
+ sage: F = A*B + A*D + C*B + C*D
1024
+
1025
+ sage: E == F
1026
+ True
1027
+
1028
+ sage: A = random_matrix(GF(17), 200, 200)
1029
+ sage: MS = parent(A)
1030
+ sage: (MS(0) * A) == 0
1031
+ True
1032
+
1033
+ sage: (MS(1) * A) == A
1034
+ True
1035
+
1036
+ ::
1037
+
1038
+ sage: A = random_matrix(Integers(8),2,2)
1039
+ sage: B = random_matrix(Integers(8),2,2)
1040
+ sage: C = A*B
1041
+ sage: all(C[i, j] == sum(A[i, k]*B[k, j] for k in range(2)) for i in range(2) for j in range(2))
1042
+ True
1043
+
1044
+ sage: MS = parent(A)
1045
+ sage: MS(3) * A == 3*A
1046
+ True
1047
+
1048
+ ::
1049
+
1050
+ sage: A = random_matrix(Integers(16), 201, 117)
1051
+ sage: B = random_matrix(Integers(16), 117, 195)
1052
+ sage: C = random_matrix(Integers(16), 201, 117)
1053
+ sage: D = random_matrix(Integers(16), 117, 195)
1054
+
1055
+ sage: E = (A+C)*(B+D)
1056
+
1057
+ sage: F = A*B + A*D + C*B + C*D
1058
+
1059
+ sage: E == F
1060
+ True
1061
+
1062
+ sage: A = random_matrix(Integers(16), 200, 200)
1063
+ sage: MS = parent(A)
1064
+ sage: (MS(0) * A) == 0
1065
+ True
1066
+
1067
+ sage: (MS(1) * A) == A
1068
+ True
1069
+
1070
+ ::
1071
+
1072
+ sage: A = random_matrix(GF(16007),2,2) # needs sage.rings.finite_rings
1073
+ sage: B = random_matrix(GF(16007),2,2) # needs sage.rings.finite_rings
1074
+ sage: C = A*B
1075
+ sage: all(C[i, j] == sum(A[i, k]*B[k, j] for k in range(2)) for i in range(2) for j in range(2))
1076
+ True
1077
+
1078
+ sage: MS = parent(A)
1079
+ sage: MS(3) * A == 3*A
1080
+ True
1081
+
1082
+ ::
1083
+
1084
+ sage: # needs sage.rings.finite_rings
1085
+ sage: A = random_matrix(GF(15991), 201, 117)
1086
+ sage: B = random_matrix(GF(15991), 117, 195)
1087
+ sage: C = random_matrix(GF(15991), 201, 117)
1088
+ sage: D = random_matrix(GF(15991), 117, 195)
1089
+
1090
+ sage: E = (A+C)*(B+D)
1091
+
1092
+ sage: F = A*B + A*D + C*B + C*D
1093
+
1094
+ sage: E == F
1095
+ True
1096
+
1097
+ ::
1098
+
1099
+ sage: A = random_matrix(GF(16007), 200, 200) # needs sage.rings.finite_rings
1100
+ sage: MS = parent(A)
1101
+ sage: (MS(0) * A) == 0
1102
+ True
1103
+
1104
+ sage: (MS(1) * A) == A
1105
+ True
1106
+
1107
+ ::
1108
+
1109
+ sage: A = random_matrix(Integers(1008),2,2)
1110
+ sage: B = random_matrix(Integers(1008),2,2)
1111
+ sage: C = A*B
1112
+ sage: all(C[i, j] == sum(A[i, k]*B[k, j] for k in range(2)) for i in range(2) for j in range(2))
1113
+ True
1114
+
1115
+ sage: MS = parent(A)
1116
+ sage: MS(3) * A == 3*A
1117
+ True
1118
+
1119
+ ::
1120
+
1121
+ sage: A = random_matrix(Integers(1600), 201, 117)
1122
+ sage: B = random_matrix(Integers(1600), 117, 195)
1123
+ sage: C = random_matrix(Integers(1600), 201, 117)
1124
+ sage: D = random_matrix(Integers(1600), 117, 195)
1125
+
1126
+ sage: E = (A+C)*(B+D)
1127
+
1128
+ sage: F = A*B + A*D + C*B + C*D
1129
+
1130
+ sage: E == F
1131
+ True
1132
+ """
1133
+ if get_verbose() >= 2:
1134
+ verbose('mod-p multiply of %s x %s matrix by %s x %s matrix modulo %s' % (
1135
+ self._nrows, self._ncols, right._nrows, right._ncols, self.p))
1136
+
1137
+ if self._ncols != right._nrows:
1138
+ raise ArithmeticError("right's number of rows must match self's number of columns")
1139
+
1140
+ cdef int e
1141
+ cdef Matrix_modn_dense_template ans, B
1142
+
1143
+ ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols())
1144
+
1145
+ B = right
1146
+
1147
+ linbox_matrix_matrix_multiply(self.p, ans._entries, self._entries,
1148
+ B._entries, self._nrows, B._ncols, B._nrows)
1149
+
1150
+ return ans
1151
+
1152
+ cdef _vector_times_matrix_(self, Vector v):
1153
+ """
1154
+ Return ``v*self``.
1155
+
1156
+ INPUT:
1157
+
1158
+ - ``v`` -- a vector
1159
+
1160
+ EXAMPLES::
1161
+
1162
+ sage: A = random_matrix(GF(17), 10, 20)
1163
+ sage: v = random_vector(GF(17), 10)
1164
+ sage: matrix(v*A) == matrix(v)*A
1165
+ True
1166
+
1167
+ sage: A = random_matrix(Integers(126), 10, 20)
1168
+ sage: v = random_vector(Integers(126), 10)
1169
+ sage: matrix(v*A) == matrix(v)*A
1170
+ True
1171
+
1172
+ sage: A = random_matrix(GF(4796509), 10, 20) # needs sage.rings.finite_rings
1173
+ sage: v = random_vector(GF(4796509), 10) # needs sage.rings.finite_rings
1174
+ sage: matrix(v*A) == matrix(v)*A
1175
+ True
1176
+
1177
+ sage: A = random_matrix(Integers(16337), 10, 20)
1178
+ sage: v = random_vector(Integers(16337), 10) # needs sage.rings.finite_rings
1179
+ sage: matrix(v*A) == matrix(v)*A
1180
+ True
1181
+ """
1182
+ if not isinstance(v, Vector_modn_dense):
1183
+ return (self.new_matrix(1, self._nrows, entries=v.list()) * self)[0]
1184
+
1185
+ M = self.row_ambient_module()
1186
+ cdef Vector_modn_dense c = M.zero_vector()
1187
+
1188
+ if self._ncols == 0 or self._nrows == 0:
1189
+ return c
1190
+
1191
+ cdef Py_ssize_t i
1192
+ cdef Vector_modn_dense b = v
1193
+
1194
+ cdef celement *_b = <celement*>check_allocarray(self._nrows, sizeof(celement))
1195
+ cdef celement *_c = <celement*>check_allocarray(self._ncols, sizeof(celement))
1196
+
1197
+ for i in range(self._nrows):
1198
+ _b[i] = <celement>b._entries[i]
1199
+
1200
+ linbox_matrix_vector_multiply(self.p, _c, self._entries, _b, self._nrows, self._ncols, FflasTrans)
1201
+
1202
+ for i in range(self._ncols):
1203
+ c._entries[i] = <mod_int>_c[i]
1204
+ sig_free(_b)
1205
+ sig_free(_c)
1206
+ return c
1207
+
1208
+ cdef _matrix_times_vector_(self, Vector v):
1209
+ """
1210
+ Return ``self*v``.
1211
+
1212
+ EXAMPLES::
1213
+
1214
+ sage: A = random_matrix(GF(17), 10, 20)
1215
+ sage: v = random_vector(GF(17), 20)
1216
+ sage: matrix(A*v).transpose() == A*matrix(v).transpose()
1217
+ True
1218
+
1219
+ sage: A = random_matrix(Integers(126), 10, 20)
1220
+ sage: v = random_vector(Integers(126), 20)
1221
+ sage: matrix(A*v).transpose() == A*matrix(v).transpose()
1222
+ True
1223
+
1224
+ sage: A = random_matrix(GF(4796509), 10, 20) # needs sage.rings.finite_rings
1225
+ sage: v = random_vector(GF(4796509), 20) # needs sage.rings.finite_rings
1226
+ sage: matrix(A*v).transpose() == A*matrix(v).transpose()
1227
+ True
1228
+
1229
+ sage: A = random_matrix(Integers(16337), 10, 20)
1230
+ sage: v = random_vector(Integers(16337), 20) # needs sage.rings.finite_rings
1231
+ sage: matrix(A*v).transpose() == A*matrix(v).transpose()
1232
+ True
1233
+ """
1234
+ if not isinstance(v, Vector_modn_dense):
1235
+ r = (self * self.new_matrix(nrows=len(v), ncols=1, entries=v.list()))
1236
+ from sage.modules.free_module_element import vector
1237
+ return vector(r.list())
1238
+
1239
+ M = self.column_ambient_module()
1240
+ cdef Vector_modn_dense c = M.zero_vector()
1241
+
1242
+ if self._ncols == 0 or self._nrows == 0:
1243
+ return c
1244
+
1245
+ cdef Py_ssize_t i
1246
+ cdef Vector_modn_dense b = v
1247
+
1248
+ cdef celement *_b = <celement*>check_allocarray(self._ncols, sizeof(celement))
1249
+ cdef celement *_c = <celement*>check_allocarray(self._nrows, sizeof(celement))
1250
+
1251
+ for i in range(self._ncols):
1252
+ _b[i] = <celement>b._entries[i]
1253
+
1254
+ linbox_matrix_vector_multiply(self.p, _c, self._entries, _b, self._nrows, self._ncols, FflasNoTrans)
1255
+
1256
+ for i in range(self._nrows):
1257
+ c._entries[i] = <mod_int>_c[i]
1258
+ sig_free(_b)
1259
+ sig_free(_c)
1260
+ return c
1261
+
1262
+ ########################################################################
1263
+ # LEVEL 3 functionality (Optional)
1264
+ # x * cdef _sub_
1265
+ # * __deepcopy__
1266
+ # * __invert__
1267
+ # * Matrix windows -- only if you need strassen for that base
1268
+ # * Other functions (list them here):
1269
+ # - all row/column operations, but optimized
1270
+ # x - echelon form in place
1271
+ # - Hessenberg forms of matrices
1272
+ ########################################################################
1273
+
1274
+ def charpoly(self, var='x', algorithm='linbox'):
1275
+ """
1276
+ Return the characteristic polynomial of ``self``.
1277
+
1278
+ INPUT:
1279
+
1280
+ - ``var`` -- a variable name
1281
+
1282
+ - ``algorithm`` -- 'generic', 'linbox' or 'all' (default: linbox)
1283
+
1284
+ EXAMPLES::
1285
+
1286
+ sage: A = random_matrix(GF(19), 10, 10)
1287
+ sage: B = copy(A)
1288
+ sage: char_p = A.characteristic_polynomial()
1289
+ sage: char_p(A) == 0
1290
+ True
1291
+ sage: B == A # A is not modified
1292
+ True
1293
+
1294
+ sage: min_p = A.minimal_polynomial(proof=True)
1295
+ sage: min_p.divides(char_p)
1296
+ True
1297
+
1298
+ ::
1299
+
1300
+ sage: A = random_matrix(GF(2916337), 7, 7) # needs sage.rings.finite_rings
1301
+ sage: B = copy(A)
1302
+ sage: char_p = A.characteristic_polynomial()
1303
+ sage: char_p(A) == 0
1304
+ True
1305
+ sage: B == A # A is not modified
1306
+ True
1307
+
1308
+ sage: min_p = A.minimal_polynomial(proof=True)
1309
+ sage: min_p.divides(char_p)
1310
+ True
1311
+
1312
+ sage: A = Mat(Integers(6),3,3)(range(9))
1313
+ sage: A.charpoly()
1314
+ x^3
1315
+
1316
+ TESTS::
1317
+
1318
+ sage: for i in range(10):
1319
+ ....: A = random_matrix(GF(17), 50, 50, density=0.1)
1320
+ ....: _ = A.characteristic_polynomial(algorithm='all')
1321
+
1322
+ sage: A = random_matrix(GF(19), 0, 0)
1323
+ sage: A.minimal_polynomial()
1324
+ 1
1325
+
1326
+ sage: A = random_matrix(GF(19), 0, 1)
1327
+ sage: A.minimal_polynomial()
1328
+ Traceback (most recent call last):
1329
+ ...
1330
+ ValueError: matrix must be square
1331
+
1332
+ sage: A = random_matrix(GF(19), 1, 0)
1333
+ sage: A.minimal_polynomial()
1334
+ Traceback (most recent call last):
1335
+ ...
1336
+ ValueError: matrix must be square
1337
+
1338
+ sage: A = matrix(GF(19), 10, 10)
1339
+ sage: A.minimal_polynomial() # needs sage.libs.pari
1340
+ x
1341
+
1342
+ sage: A = random_matrix(GF(4198973), 0, 0) # needs sage.rings.finite_rings
1343
+ sage: A.minimal_polynomial() # needs sage.rings.finite_rings
1344
+ 1
1345
+
1346
+ sage: A = random_matrix(GF(4198973), 0, 1) # needs sage.rings.finite_rings
1347
+ sage: A.minimal_polynomial() # needs sage.rings.finite_rings
1348
+ Traceback (most recent call last):
1349
+ ...
1350
+ ValueError: matrix must be square
1351
+
1352
+ sage: A = random_matrix(GF(4198973), 1, 0) # needs sage.rings.finite_rings
1353
+ sage: A.minimal_polynomial() # needs sage.rings.finite_rings
1354
+ Traceback (most recent call last):
1355
+ ...
1356
+ ValueError: matrix must be square
1357
+
1358
+ sage: A = matrix(GF(4198973), 10, 10) # needs sage.rings.finite_rings
1359
+ sage: A.minimal_polynomial() # needs sage.rings.finite_rings
1360
+ x
1361
+
1362
+ sage: A = Mat(GF(7),3,3)([0, 1, 2] * 3)
1363
+ sage: A.charpoly()
1364
+ x^3 + 4*x^2
1365
+
1366
+ ALGORITHM: Uses LinBox if ``self.base_ring()`` is a field,
1367
+ otherwise use Hessenberg form algorithm.
1368
+
1369
+ TESTS:
1370
+
1371
+ The cached polynomial should be independent of the ``var``
1372
+ argument (:issue:`12292`). We check (indirectly) that the
1373
+ second call uses the cached value by noting that its result is
1374
+ not cached. The polynomial here is not unique, so we only
1375
+ check the polynomial's variable.
1376
+
1377
+ sage: M = MatrixSpace(Integers(37), 2)
1378
+ sage: A = M(range(0, 2^2))
1379
+ sage: type(A)
1380
+ <class 'sage.matrix.matrix_modn_dense_float.Matrix_modn_dense_float'>
1381
+ sage: A.charpoly('x').variables()
1382
+ (x,)
1383
+ sage: A.charpoly('y').variables()
1384
+ (y,)
1385
+ sage: A._cache['charpoly_linbox'].variables()
1386
+ (x,)
1387
+ """
1388
+ cache_key = 'charpoly_%s' % algorithm
1389
+ g = self.fetch(cache_key)
1390
+ if g is not None:
1391
+ return g.change_variable_name(var)
1392
+
1393
+ if algorithm == 'linbox' and (self.p == 2 or not self.base_ring().is_field()):
1394
+ algorithm = 'generic' # LinBox only supports Z/pZ (p prime)
1395
+
1396
+ if algorithm == 'linbox':
1397
+ g = self._charpoly_linbox(var)
1398
+ elif algorithm == 'generic':
1399
+ g = Matrix_dense.charpoly(self, var)
1400
+ elif algorithm == 'all':
1401
+ g = self._charpoly_linbox(var)
1402
+ h = Matrix_dense.charpoly(self, var)
1403
+ if g != h:
1404
+ raise ArithmeticError("Characteristic polynomials do not match.")
1405
+ else:
1406
+ raise ValueError("no algorithm '%s'" % algorithm)
1407
+
1408
+ self.cache(cache_key, g)
1409
+ return g
1410
+
1411
+ def minpoly(self, var='x', algorithm='linbox', proof=None):
1412
+ """
1413
+ Return the minimal polynomial of ``self``.
1414
+
1415
+ INPUT:
1416
+
1417
+ - ``var`` -- a variable name
1418
+
1419
+ - ``algorithm`` -- ``generic`` or ``linbox`` (default:
1420
+ ``linbox``)
1421
+
1422
+ - ``proof`` -- (default: ``True``) whether to provably return
1423
+ the true minimal polynomial; if ``False``, we only guarantee
1424
+ to return a divisor of the minimal polynomial. There are
1425
+ also certainly cases where the computed results is
1426
+ frequently not exactly equal to the minimal polynomial (but
1427
+ is instead merely a divisor of it).
1428
+
1429
+ .. warning::
1430
+
1431
+ If ``proof=True``, minpoly is insanely slow compared to
1432
+ ``proof=False``. This matters since proof=True is the
1433
+ default, unless you first type
1434
+ ``proof.linear_algebra(False)``.
1435
+
1436
+ EXAMPLES::
1437
+
1438
+ sage: A = random_matrix(GF(17), 10, 10)
1439
+ sage: B = copy(A)
1440
+ sage: min_p = A.minimal_polynomial(proof=True)
1441
+ sage: min_p(A) == 0
1442
+ True
1443
+ sage: B == A
1444
+ True
1445
+
1446
+ sage: char_p = A.characteristic_polynomial()
1447
+ sage: min_p.divides(char_p)
1448
+ True
1449
+
1450
+ ::
1451
+
1452
+ sage: A = random_matrix(GF(1214471), 10, 10) # needs sage.rings.finite_rings
1453
+ sage: B = copy(A)
1454
+ sage: min_p = A.minimal_polynomial(proof=True)
1455
+ sage: min_p(A) == 0
1456
+ True
1457
+ sage: B == A
1458
+ True
1459
+
1460
+ sage: char_p = A.characteristic_polynomial()
1461
+ sage: min_p.divides(char_p)
1462
+ True
1463
+
1464
+ TESTS::
1465
+
1466
+ sage: A = random_matrix(GF(17), 0, 0)
1467
+ sage: A.minimal_polynomial()
1468
+ 1
1469
+
1470
+ sage: A = random_matrix(GF(17), 0, 1)
1471
+ sage: A.minimal_polynomial()
1472
+ Traceback (most recent call last):
1473
+ ...
1474
+ ValueError: matrix must be square
1475
+
1476
+ sage: A = random_matrix(GF(17), 1, 0)
1477
+ sage: A.minimal_polynomial()
1478
+ Traceback (most recent call last):
1479
+ ...
1480
+ ValueError: matrix must be square
1481
+
1482
+ sage: A = matrix(GF(17), 10, 10)
1483
+ sage: A.minimal_polynomial() # needs sage.libs.pari
1484
+ x
1485
+
1486
+ ::
1487
+
1488
+ sage: A = random_matrix(GF(2535919), 0, 0) # needs sage.rings.finite_rings
1489
+ sage: A.minimal_polynomial() # needs sage.rings.finite_rings
1490
+ 1
1491
+
1492
+ sage: A = random_matrix(GF(2535919), 0, 1) # needs sage.rings.finite_rings
1493
+ sage: A.minimal_polynomial() # needs sage.rings.finite_rings
1494
+ Traceback (most recent call last):
1495
+ ...
1496
+ ValueError: matrix must be square
1497
+
1498
+ sage: A = random_matrix(GF(2535919), 1, 0) # needs sage.rings.finite_rings
1499
+ sage: A.minimal_polynomial() # needs sage.rings.finite_rings
1500
+ Traceback (most recent call last):
1501
+ ...
1502
+ ValueError: matrix must be square
1503
+
1504
+ sage: A = matrix(GF(2535919), 10, 10) # needs sage.rings.finite_rings
1505
+ sage: A.minimal_polynomial() # needs sage.rings.finite_rings
1506
+ x
1507
+
1508
+ EXAMPLES::
1509
+
1510
+ sage: R.<x>=GF(3)[]
1511
+ sage: A = matrix(GF(3),2,[0,0,1,2])
1512
+ sage: A.minpoly()
1513
+ x^2 + x
1514
+
1515
+ sage: A.minpoly(proof=False) in [x, x+1, x^2+x]
1516
+ True
1517
+ """
1518
+ proof = get_proof_flag(proof, "linear_algebra")
1519
+
1520
+ if algorithm == 'linbox' and (self.p == 2 or not self.base_ring().is_field()):
1521
+ algorithm='generic' # LinBox only supports fields
1522
+
1523
+ if algorithm == 'linbox':
1524
+ if self._nrows != self._ncols:
1525
+ raise ValueError("matrix must be square")
1526
+
1527
+ if self._nrows <= 1:
1528
+ return Matrix_dense.minpoly(self, var)
1529
+
1530
+ R = self._base_ring[var]
1531
+ v = linbox_minpoly(self.p, self._nrows, self._entries)
1532
+ g = R(v)
1533
+
1534
+ if proof:
1535
+ while g(self): # insanely toy slow (!)
1536
+ g = g.lcm(R(linbox_minpoly(self.p, self._nrows, self._entries)))
1537
+
1538
+ elif algorithm == 'generic':
1539
+ raise NotImplementedError("Minimal polynomials are not implemented for Z/nZ.")
1540
+
1541
+ else:
1542
+ raise ValueError("no algorithm '%s'" % algorithm)
1543
+
1544
+ self.cache('minpoly_%s_%s' % (algorithm, var), g)
1545
+ return g
1546
+
1547
+ def _charpoly_linbox(self, var='x'):
1548
+ """
1549
+ Compute the characteristic polynomial using LinBox. No checks
1550
+ are performed.
1551
+
1552
+ This function is called internally by ``charpoly``.
1553
+
1554
+ INPUT:
1555
+
1556
+ - ``var`` -- a variable name
1557
+
1558
+ EXAMPLES::
1559
+
1560
+ sage: # needs sage.libs.linbox
1561
+ sage: A = random_matrix(GF(19), 10, 10)
1562
+ sage: B = copy(A)
1563
+ sage: char_p = A._charpoly_linbox()
1564
+ sage: char_p(A) == 0
1565
+ True
1566
+ sage: B == A # A is not modified
1567
+ True
1568
+ sage: min_p = A.minimal_polynomial(proof=True)
1569
+ sage: min_p.divides(char_p)
1570
+ True
1571
+ """
1572
+ verbose('_charpoly_linbox...')
1573
+
1574
+ if self._nrows != self._ncols:
1575
+ raise ValueError("matrix must be square")
1576
+ R = self._base_ring[var]
1577
+ # call linbox for charpoly
1578
+ v = linbox_charpoly(self.p, self._nrows, self._entries)
1579
+ r = R(v)
1580
+ return r
1581
+
1582
+ def echelonize(self, algorithm='linbox_noefd', **kwds):
1583
+ """
1584
+ Put ``self`` in reduced row echelon form.
1585
+
1586
+ INPUT:
1587
+
1588
+ - ``self`` -- a mutable matrix
1589
+
1590
+ - ``algorithm``
1591
+
1592
+ - ``linbox`` -- uses the LinBox library (wrapping fflas-ffpack)
1593
+
1594
+ - ``linbox_noefd`` -- uses the FFPACK directly, less memory and faster (default)
1595
+
1596
+ - ``gauss`` -- uses a custom slower `O(n^3)` Gauss
1597
+ elimination implemented in Sage
1598
+
1599
+ - ``all`` -- compute using both algorithms and verify that
1600
+ the results are the same
1601
+
1602
+ - ``**kwds`` -- these are all ignored
1603
+
1604
+ OUTPUT: ``self`` is put in reduced row echelon form
1605
+
1606
+ - the rank of ``self`` is computed and cached
1607
+
1608
+ - the pivot columns of ``self`` are computed and cached
1609
+
1610
+ - the fact that ``self`` is now in echelon form is recorded and
1611
+ cached so future calls to echelonize return immediately
1612
+
1613
+ EXAMPLES::
1614
+
1615
+ sage: A = random_matrix(GF(7), 10, 20)
1616
+ sage: E = A.echelon_form()
1617
+ sage: A.row_space() == E.row_space()
1618
+ True
1619
+ sage: all(r[r.nonzero_positions()[0]] == 1 for r in E.rows() if r)
1620
+ True
1621
+
1622
+ ::
1623
+
1624
+ sage: A = random_matrix(GF(13), 10, 10)
1625
+ sage: while A.rank() != 10:
1626
+ ....: A = random_matrix(GF(13), 10, 10)
1627
+ sage: MS = parent(A)
1628
+ sage: B = A.augment(MS(1))
1629
+ sage: B.echelonize()
1630
+ sage: A.rank()
1631
+ 10
1632
+ sage: C = B.submatrix(0,10,10,10)
1633
+ sage: ~A == C
1634
+ True
1635
+
1636
+ ::
1637
+
1638
+ sage: A = random_matrix(Integers(10), 10, 20)
1639
+ sage: A.echelon_form()
1640
+ Traceback (most recent call last):
1641
+ ...
1642
+ NotImplementedError: Echelon form not implemented over 'Ring of integers modulo 10'.
1643
+
1644
+ ::
1645
+
1646
+ sage: # needs sage.rings.finite_rings
1647
+ sage: A = random_matrix(GF(16007), 10, 20)
1648
+ sage: E = A.echelon_form()
1649
+ sage: A.row_space() == E.row_space()
1650
+ True
1651
+ sage: all(r[r.nonzero_positions()[0]] == 1 for r in E.rows() if r)
1652
+ True
1653
+
1654
+ ::
1655
+
1656
+ sage: A = random_matrix(Integers(10000), 10, 20)
1657
+ sage: A.echelon_form()
1658
+ Traceback (most recent call last):
1659
+ ...
1660
+ NotImplementedError: Echelon form not implemented over 'Ring of integers modulo 10000'.
1661
+
1662
+ Parallel computation::
1663
+
1664
+ sage: # needs sage.rings.finite_rings
1665
+ sage: A = random_matrix(GF(65521),100,200)
1666
+ sage: Parallelism().set('linbox', nproc=2)
1667
+ sage: E = A.echelon_form()
1668
+ sage: Parallelism().set('linbox', nproc=1) # switch off parallelization
1669
+ sage: F = A.echelon_form()
1670
+ sage: E==F
1671
+ True
1672
+
1673
+ TESTS::
1674
+
1675
+ sage: A = random_matrix(GF(7), 0, 10)
1676
+ sage: A.echelon_form()
1677
+ []
1678
+ sage: A = random_matrix(GF(7), 10, 0)
1679
+ sage: A.echelon_form()
1680
+ []
1681
+ sage: A = random_matrix(GF(7), 0, 0)
1682
+ sage: A.echelon_form()
1683
+ []
1684
+ sage: A = matrix(GF(7), 10, 10)
1685
+ sage: A.echelon_form()
1686
+ [0 0 0 0 0 0 0 0 0 0]
1687
+ [0 0 0 0 0 0 0 0 0 0]
1688
+ [0 0 0 0 0 0 0 0 0 0]
1689
+ [0 0 0 0 0 0 0 0 0 0]
1690
+ [0 0 0 0 0 0 0 0 0 0]
1691
+ [0 0 0 0 0 0 0 0 0 0]
1692
+ [0 0 0 0 0 0 0 0 0 0]
1693
+ [0 0 0 0 0 0 0 0 0 0]
1694
+ [0 0 0 0 0 0 0 0 0 0]
1695
+ [0 0 0 0 0 0 0 0 0 0]
1696
+
1697
+ sage: # needs sage.rings.finite_rings
1698
+ sage: A = random_matrix(GF(16007), 0, 10)
1699
+ sage: A.echelon_form()
1700
+ []
1701
+ sage: A = random_matrix(GF(16007), 10, 0)
1702
+ sage: A.echelon_form()
1703
+ []
1704
+ sage: A = random_matrix(GF(16007), 0, 0)
1705
+ sage: A.echelon_form()
1706
+ []
1707
+ sage: A = matrix(GF(16007), 10, 10)
1708
+ sage: A.echelon_form()
1709
+ [0 0 0 0 0 0 0 0 0 0]
1710
+ [0 0 0 0 0 0 0 0 0 0]
1711
+ [0 0 0 0 0 0 0 0 0 0]
1712
+ [0 0 0 0 0 0 0 0 0 0]
1713
+ [0 0 0 0 0 0 0 0 0 0]
1714
+ [0 0 0 0 0 0 0 0 0 0]
1715
+ [0 0 0 0 0 0 0 0 0 0]
1716
+ [0 0 0 0 0 0 0 0 0 0]
1717
+ [0 0 0 0 0 0 0 0 0 0]
1718
+ [0 0 0 0 0 0 0 0 0 0]
1719
+
1720
+ sage: A = matrix(GF(97),3,4,range(12))
1721
+ sage: A.echelonize(); A
1722
+ [ 1 0 96 95]
1723
+ [ 0 1 2 3]
1724
+ [ 0 0 0 0]
1725
+ sage: A.pivots()
1726
+ (0, 1)
1727
+
1728
+ sage: for p in (3,17,97,127,1048573):
1729
+ ....: for i in range(10):
1730
+ ....: A = random_matrix(GF(3), 100, 100)
1731
+ ....: A.echelonize(algorithm='all')
1732
+ """
1733
+ x = self.fetch('in_echelon_form')
1734
+ if x is not None:
1735
+ return # already known to be in echelon form
1736
+
1737
+ if not self.base_ring().is_field():
1738
+ raise NotImplementedError("Echelon form not implemented over '%s'." % self.base_ring())
1739
+
1740
+ if algorithm == 'linbox':
1741
+ self._echelonize_linbox(efd=True)
1742
+ elif algorithm == 'linbox_noefd':
1743
+ self._echelonize_linbox(efd=False)
1744
+ elif algorithm == 'gauss':
1745
+ self._echelon_in_place_classical()
1746
+
1747
+ elif algorithm == 'all':
1748
+ A = self.__copy__()
1749
+ B = self.__copy__()
1750
+ self._echelonize_linbox(efd=True)
1751
+ A._echelon_in_place_classical()
1752
+ B._echelonize_linbox(efd=False)
1753
+ if A != self or A != B:
1754
+ raise ArithmeticError("Bug in echelon form.")
1755
+ else:
1756
+ raise ValueError("Algorithm '%s' not known" % algorithm)
1757
+
1758
+ def _echelonize_linbox(self, efd=True):
1759
+ """
1760
+ Puts ``self`` in row echelon form using LinBox.
1761
+
1762
+ This function is called by echelonize if
1763
+ ``algorithm='linbox'``.
1764
+
1765
+ INPUT:
1766
+
1767
+ - ``efd`` -- if ``True`` LinBox's ``EchelonFormDomain``
1768
+ implementation is used, which is faster than the direct
1769
+ ``LinBox::FFPACK`` implementation, since the latter also
1770
+ computes the transformation matrix (which we
1771
+ ignore). However, ``efd=True`` uses more memory than FFLAS
1772
+ directly (default: ``True``)
1773
+
1774
+ EXAMPLES::
1775
+
1776
+ sage: # needs sage.libs.linbox
1777
+ sage: A = random_matrix(GF(7), 10, 20)
1778
+ sage: B = copy(A)
1779
+ sage: A._echelonize_linbox()
1780
+ sage: A.row_space() == B.row_space()
1781
+ True
1782
+ sage: all(r[r.nonzero_positions()[0]] == 1 for r in A.rows() if r)
1783
+ True
1784
+ """
1785
+ self.check_mutability()
1786
+ self.clear_cache()
1787
+
1788
+ t = verbose('Calling echelonize mod %d.' % self.p)
1789
+ if efd:
1790
+ r, pivots = linbox_echelonize_efd(self.p, self._entries,
1791
+ self._nrows, self._ncols)
1792
+ else:
1793
+ r, pivots = linbox_echelonize(self.p, self._entries,
1794
+ self._nrows, self._ncols)
1795
+ verbose('done with echelonize', t)
1796
+ self.cache('in_echelon_form', True)
1797
+ self.cache('rank', r)
1798
+ self.cache('pivots', tuple(pivots))
1799
+
1800
+ def _echelon_in_place_classical(self):
1801
+ """
1802
+ Puts ``self`` in row echelon form using LinBox.
1803
+
1804
+ This function is called by echelonize if
1805
+ ``algorithm='gauss'``.
1806
+
1807
+ EXAMPLES::
1808
+
1809
+ sage: A = random_matrix(GF(7), 10, 20)
1810
+ sage: B = copy(A)
1811
+ sage: A._echelon_in_place_classical()
1812
+ sage: A.row_space() == B.row_space()
1813
+ True
1814
+ sage: all(r[r.nonzero_positions()[0]] == 1 for r in A.rows() if r)
1815
+ True
1816
+ """
1817
+ self.check_mutability()
1818
+ self.clear_cache()
1819
+
1820
+ cdef Py_ssize_t start_row, c, r, nr, nc, i
1821
+ cdef celement p, a, s, t, b
1822
+ cdef celement **m
1823
+
1824
+ start_row = 0
1825
+ p = self.p
1826
+ m = self._matrix
1827
+ nr = self._nrows
1828
+ nc = self._ncols
1829
+ pivots = []
1830
+ fifth = self._ncols / 10 + 1
1831
+ do_verb = (get_verbose() >= 2)
1832
+ for c from 0 <= c < nc:
1833
+ if do_verb and (c % fifth == 0 and c > 0):
1834
+ tm = verbose('on column %s of %s' % (c, self._ncols),
1835
+ level = 2,
1836
+ caller_name = 'matrix_modn_dense echelon')
1837
+ # end if
1838
+ sig_check()
1839
+ for r from start_row <= r < nr:
1840
+ a = m[r][c]
1841
+ if a:
1842
+ pivots.append(c)
1843
+ a_inverse = celement_invert(a, p)
1844
+ self.rescale_row_c(r, a_inverse, c)
1845
+ self.swap_rows_c(r, start_row)
1846
+ for i from 0 <= i < nr:
1847
+ if i != start_row:
1848
+ b = m[i][c]
1849
+ if b != 0:
1850
+ self.add_multiple_of_row_c(i, start_row, p-b, c)
1851
+ start_row = start_row + 1
1852
+ break
1853
+ self.cache('pivots', tuple(pivots))
1854
+ self.cache('in_echelon_form', True)
1855
+
1856
+ def right_kernel_matrix(self, algorithm='linbox', basis='echelon'):
1857
+ r"""
1858
+ Return a matrix whose rows form a basis for the right kernel
1859
+ of ``self``.
1860
+
1861
+ If the base ring is the ring of integers modulo a composite,
1862
+ the keyword arguments are ignored and the computation is
1863
+ delegated to :meth:`Matrix_dense.right_kernel_matrix`.
1864
+
1865
+ INPUT:
1866
+
1867
+ - ``algorithm`` -- (default: ``'linbox'``) a parameter that is
1868
+ passed on to ``self.echelon_form``, if computation of an echelon
1869
+ form is required; see that routine for allowable values
1870
+
1871
+ - ``basis`` -- (default: ``'echelon'``) a keyword that describes the
1872
+ format of the basis returned, allowable values are:
1873
+
1874
+ - ``'echelon'``: the basis matrix is in echelon form
1875
+ - ``'pivot'``: the basis matrix is such that the submatrix obtained
1876
+ by taking the columns that in ``self`` contain no pivots, is the
1877
+ identity matrix
1878
+ - ``'computed'``: no work is done to transform the basis; in
1879
+ the current implementation the result is the negative of
1880
+ that returned by ``'pivot'``
1881
+
1882
+ OUTPUT:
1883
+
1884
+ A matrix ``X`` whose rows are a basis for the right kernel of
1885
+ ``self``. This means that ``self * X.transpose()`` is a zero matrix.
1886
+
1887
+ The result is not cached, but the routine benefits when ``self`` is
1888
+ known to be in echelon form already.
1889
+
1890
+ EXAMPLES::
1891
+
1892
+ sage: M = matrix(GF(5),6,6,range(36))
1893
+ sage: M.right_kernel_matrix(basis='computed')
1894
+ [4 2 4 0 0 0]
1895
+ [3 3 0 4 0 0]
1896
+ [2 4 0 0 4 0]
1897
+ [1 0 0 0 0 4]
1898
+ sage: M.right_kernel_matrix(basis='pivot')
1899
+ [1 3 1 0 0 0]
1900
+ [2 2 0 1 0 0]
1901
+ [3 1 0 0 1 0]
1902
+ [4 0 0 0 0 1]
1903
+ sage: M.right_kernel_matrix()
1904
+ [1 0 0 0 0 4]
1905
+ [0 1 0 0 1 3]
1906
+ [0 0 1 0 2 2]
1907
+ [0 0 0 1 3 1]
1908
+ sage: M * M.right_kernel_matrix().transpose()
1909
+ [0 0 0 0]
1910
+ [0 0 0 0]
1911
+ [0 0 0 0]
1912
+ [0 0 0 0]
1913
+ [0 0 0 0]
1914
+ [0 0 0 0]
1915
+ """
1916
+ if self.fetch('in_echelon_form') is None:
1917
+ try:
1918
+ self = self.echelon_form(algorithm=algorithm)
1919
+ except NotImplementedError: # composite modulus
1920
+ return Matrix_dense.right_kernel_matrix(self)
1921
+
1922
+ cdef Py_ssize_t r = self.rank()
1923
+ cdef Py_ssize_t nrows = self._nrows
1924
+ cdef Py_ssize_t ncols = self._ncols
1925
+ cdef Py_ssize_t i, j, k
1926
+
1927
+ cdef Py_ssize_t* nonpivots = <Py_ssize_t*>sig_malloc(sizeof(Py_ssize_t)*(ncols-r))
1928
+ cdef Py_ssize_t* pivots = <Py_ssize_t*>sig_malloc(sizeof(Py_ssize_t)*(r))
1929
+ cdef tuple pivot_tuple = self.pivots()
1930
+
1931
+ for i in range(r):
1932
+ pivots[i] = pivot_tuple[i]
1933
+ j = 0
1934
+ k = 0
1935
+ for i in range(ncols):
1936
+ if j < r and i == pivots[j]:
1937
+ j += 1
1938
+ else:
1939
+ nonpivots[k] = i
1940
+ k += 1
1941
+
1942
+ cdef Matrix_modn_dense_template M = self.new_matrix(nrows=ncols-r, ncols=ncols)
1943
+ cdef celement pm1 = self.p - 1
1944
+
1945
+ k = 0
1946
+ for i in range(ncols-r):
1947
+ for j in range(ncols-r):
1948
+ M._entries[nonpivots[i]+j*ncols] = 0
1949
+ M._entries[nonpivots[i]+k*ncols] = pm1
1950
+ k += 1
1951
+ for j in range(r):
1952
+ M._entries[i*ncols+pivots[j]] = self._entries[nonpivots[i]+j*ncols]
1953
+
1954
+ sig_free(pivots)
1955
+ sig_free(nonpivots)
1956
+ if basis == 'computed':
1957
+ return M
1958
+ elif basis == 'pivot':
1959
+ return -M
1960
+ elif basis != 'echelon':
1961
+ raise ValueError("matrix kernel basis format not recognized")
1962
+ M.echelonize(algorithm=algorithm)
1963
+ return M
1964
+
1965
+ def hessenbergize(self):
1966
+ """
1967
+ Transform ``self`` in place to its Hessenberg form.
1968
+
1969
+ EXAMPLES::
1970
+
1971
+ sage: A = random_matrix(GF(17), 10, 10, density=0.1)
1972
+ sage: B = copy(A)
1973
+ sage: A.hessenbergize()
1974
+ sage: all(A[i,j] == 0 for j in range(10) for i in range(j+2, 10))
1975
+ True
1976
+ sage: A.charpoly() == B.charpoly()
1977
+ True
1978
+ """
1979
+ self.check_mutability()
1980
+ x = self.fetch('in_hessenberg_form')
1981
+ if x is not None and x:
1982
+ return # already known to be in Hessenberg form
1983
+ if self._nrows != self._ncols:
1984
+ raise ArithmeticError("Matrix must be square to compute Hessenberg form.")
1985
+
1986
+ cdef Py_ssize_t n
1987
+ n = self._nrows
1988
+
1989
+ cdef celement **h
1990
+ h = self._matrix
1991
+
1992
+ cdef celement p, t, t_inv, u
1993
+ cdef Py_ssize_t i, j, m
1994
+ p = self.p
1995
+
1996
+ sig_on()
1997
+ for m from 1 <= m < n-1:
1998
+ # Search for a nonzero entry in column m-1
1999
+ i = -1
2000
+ for r from m+1 <= r < n:
2001
+ if h[r][m-1]:
2002
+ i = r
2003
+ break
2004
+
2005
+ if i != -1:
2006
+ # Found a nonzero entry in column m-1 that is strictly
2007
+ # below row m. Now set i to be the first nonzero position >=
2008
+ # m in column m-1.
2009
+ if h[m][m-1]:
2010
+ i = m
2011
+ t = h[i][m-1]
2012
+ t_inv = celement_invert(t, p)
2013
+ if i > m:
2014
+ self.swap_rows_c(i, m)
2015
+ self.swap_columns_c(i, m)
2016
+
2017
+ # Now the nonzero entry in position (m,m-1) is t.
2018
+ # Use t to clear the entries in column m-1 below m.
2019
+ for j from m+1 <= j < n:
2020
+ if h[j][m-1]:
2021
+ u = (h[j][m-1] * t_inv) % p
2022
+ self.add_multiple_of_row_c(j, m, p - u, 0) # h[j] -= u*h[m]
2023
+ # To maintain charpoly, do the corresponding
2024
+ # column operation, which doesn't mess up the
2025
+ # matrix, since it only changes column m, and
2026
+ # we're only worried about column m-1 right
2027
+ # now. Add u*column_j to column_m.
2028
+ self.add_multiple_of_column_c(m, j, u, 0)
2029
+ # end for
2030
+ # end if
2031
+ # end for
2032
+ sig_off()
2033
+ self.cache('in_hessenberg_form', True)
2034
+
2035
+ def _charpoly_hessenberg(self, var):
2036
+ """
2037
+ Transform ``self`` in place to its Hessenberg form then computes
2038
+ and returns the coefficients of the characteristic polynomial
2039
+ of this matrix.
2040
+
2041
+ INPUT:
2042
+
2043
+ - ``var`` -- name of the indeterminate of the charpoly
2044
+
2045
+ OUTPUT:
2046
+
2047
+ The characteristic polynomial is represented as a vector of
2048
+ ints, where the constant term of the characteristic
2049
+ polynomial is the `0`-th coefficient of the vector.
2050
+
2051
+ EXAMPLES::
2052
+
2053
+ sage: A = random_matrix(GF(17), 10, 10, density=0.1)
2054
+ sage: B = copy(A)
2055
+ sage: P.<x> = GF(17)[]
2056
+ sage: A._charpoly_hessenberg('x') == B.charpoly()
2057
+ True
2058
+ """
2059
+ if self._nrows != self._ncols:
2060
+ raise ArithmeticError("charpoly not defined for non-square matrix.")
2061
+
2062
+ cdef Py_ssize_t i, m, n,
2063
+ n = self._nrows
2064
+
2065
+ cdef celement p, t
2066
+ p = self.p
2067
+
2068
+ # Replace self by its Hessenberg form, and set H to this form
2069
+ # for notation below.
2070
+ cdef Matrix_modn_dense_template H
2071
+ H = self.__copy__()
2072
+ H.hessenbergize()
2073
+
2074
+ # We represent the intermediate polynomials that come up in
2075
+ # the calculations as rows of an (n+1)x(n+1) matrix, since
2076
+ # we've implemented basic arithmetic with such a matrix.
2077
+ # Please see the generic implementation of charpoly in
2078
+ # matrix.py to see more clearly how the following algorithm
2079
+ # actually works. (The implementation is clearer (but slower)
2080
+ # if one uses polynomials to represent polynomials instead of
2081
+ # using the rows of a matrix.) Also see Cohen's first GTM,
2082
+ # Algorithm 2.2.9.
2083
+
2084
+ cdef Matrix_modn_dense_template c
2085
+ c = self.new_matrix(nrows=n+1, ncols=n+1) # the 0 matrix
2086
+ c._matrix[0][0] = 1
2087
+ for m from 1 <= m <= n:
2088
+ # Set the m-th row of c to (x - H[m-1,m-1])*c[m-1] = x*c[m-1] - H[m-1,m-1]*c[m-1]
2089
+ # We do this by hand by setting the m-th row to c[m-1]
2090
+ # shifted to the right by one. We then add
2091
+ # -H[m-1,m-1]*c[m-1] to the resulting m-th row.
2092
+ for i from 1 <= i <= n:
2093
+ c._matrix[m][i] = c._matrix[m-1][i-1]
2094
+ # the p-.. below is to keep scalar normalized between 0 and p.
2095
+ c.add_multiple_of_row_c(m, m-1, p - H._matrix[m-1][m-1], 0)
2096
+ t = 1
2097
+ for i from 1 <= i < m:
2098
+ t = (t*H._matrix[m-i][m-i-1]) % p
2099
+ # Set the m-th row of c to c[m] - t*H[m-i-1,m-1]*c[m-i-1]
2100
+ c.add_multiple_of_row_c(m, m-i-1, p - (t*H._matrix[m-i-1][m-1]) % p, 0)
2101
+
2102
+ # The answer is now the n-th row of c.
2103
+ v = []
2104
+ for i from 0 <= i <= n:
2105
+ v.append(int(c._matrix[n][i]))
2106
+ R = self._base_ring[var] # polynomial ring over the base ring
2107
+ return R(v)
2108
+
2109
+ def rank(self):
2110
+ """
2111
+ Return the rank of this matrix.
2112
+
2113
+ EXAMPLES::
2114
+
2115
+ sage: A = random_matrix(GF(3), 100, 100)
2116
+ sage: B = copy(A)
2117
+ sage: _ = A.rank()
2118
+ sage: B == A
2119
+ True
2120
+
2121
+ sage: A = random_matrix(GF(3), 100, 100, density=0.01)
2122
+ sage: A.transpose().rank() == A.rank()
2123
+ True
2124
+
2125
+ sage: A = matrix(GF(3), 100, 100)
2126
+ sage: A.rank()
2127
+ 0
2128
+
2129
+ Rank is not implemented over the integers modulo a composite
2130
+ yet.::
2131
+
2132
+ sage: M = matrix(Integers(4), 2, [2,2,2,2])
2133
+ sage: M.rank()
2134
+ Traceback (most recent call last):
2135
+ ...
2136
+ NotImplementedError: Echelon form not implemented over 'Ring of integers modulo 4'.
2137
+
2138
+ ::
2139
+
2140
+ sage: # needs sage.rings.finite_rings
2141
+ sage: while True:
2142
+ ....: A = random_matrix(GF(16007), 100, 100)
2143
+ ....: if A.rank() == 100:
2144
+ ....: break
2145
+ sage: B = copy(A)
2146
+ sage: A.rank()
2147
+ 100
2148
+ sage: B == A
2149
+ True
2150
+ sage: MS = A.parent()
2151
+ sage: MS(1) == ~A*A
2152
+ True
2153
+
2154
+ TESTS::
2155
+
2156
+ sage: A = random_matrix(GF(7), 0, 0)
2157
+ sage: A.rank()
2158
+ 0
2159
+ sage: A = random_matrix(GF(7), 1, 0)
2160
+ sage: A.rank()
2161
+ 0
2162
+ sage: A = random_matrix(GF(7), 0, 1)
2163
+ sage: A.rank()
2164
+ 0
2165
+
2166
+ sage: # needs sage.rings.finite_rings
2167
+ sage: A = random_matrix(GF(16007), 0, 0)
2168
+ sage: A.rank()
2169
+ 0
2170
+ sage: A = random_matrix(GF(16007), 1, 0)
2171
+ sage: A.rank()
2172
+ 0
2173
+ sage: A = random_matrix(GF(16007), 0, 1)
2174
+ sage: A.rank()
2175
+ 0
2176
+ """
2177
+ cdef Matrix_modn_dense_template A
2178
+ if self.p > 2 and is_prime(self.p):
2179
+ x = self.fetch('rank')
2180
+ if x is not None:
2181
+ return x
2182
+ r = Integer(linbox_rank(self.p, self._entries, self._nrows, self._ncols))
2183
+ self.cache('rank', r)
2184
+ return r
2185
+ else:
2186
+ # linbox is very buggy for p=2, but this code should never
2187
+ # be called since p=2 is handled via M4RI
2188
+ return Matrix_dense.rank(self)
2189
+
2190
+ def determinant(self):
2191
+ """
2192
+ Return the determinant of this matrix.
2193
+
2194
+ EXAMPLES::
2195
+
2196
+ sage: s = set()
2197
+ sage: while s != set(GF(7)):
2198
+ ....: A = random_matrix(GF(7), 10, 10)
2199
+ ....: s.add(A.determinant())
2200
+
2201
+ ::
2202
+
2203
+ sage: A = random_matrix(GF(7), 100, 100)
2204
+ sage: A.determinant() == A.transpose().determinant()
2205
+ True
2206
+
2207
+ sage: B = random_matrix(GF(7), 100, 100)
2208
+ sage: (A*B).determinant() == A.determinant() * B.determinant()
2209
+ True
2210
+
2211
+ ::
2212
+
2213
+ sage: # needs sage.rings.finite_rings
2214
+ sage: A = random_matrix(GF(16007), 10, 10)
2215
+ sage: A.determinant().parent() is GF(16007)
2216
+ True
2217
+
2218
+ ::
2219
+
2220
+ sage: # needs sage.rings.finite_rings
2221
+ sage: A = random_matrix(GF(16007), 100, 100)
2222
+ sage: A.determinant().parent() is GF(16007)
2223
+ True
2224
+ sage: A.determinant() == A.transpose().determinant()
2225
+ True
2226
+ sage: B = random_matrix(GF(16007), 100, 100)
2227
+ sage: (A*B).determinant() == A.determinant() * B.determinant()
2228
+ True
2229
+
2230
+ Parallel computation::
2231
+
2232
+ sage: # needs sage.rings.finite_rings
2233
+ sage: A = random_matrix(GF(65521),200)
2234
+ sage: B = copy(A)
2235
+ sage: Parallelism().set('linbox', nproc=2)
2236
+ sage: d = A.determinant()
2237
+ sage: Parallelism().set('linbox', nproc=1) # switch off parallelization
2238
+ sage: e = B.determinant()
2239
+ sage: d==e
2240
+ True
2241
+
2242
+ TESTS::
2243
+
2244
+ sage: A = random_matrix(GF(7), 0, 0); A.det()
2245
+ 1
2246
+
2247
+ sage: A = random_matrix(GF(7), 0, 1); A.det()
2248
+ Traceback (most recent call last):
2249
+ ...
2250
+ ValueError: self must be a square matrix
2251
+
2252
+ sage: A = random_matrix(GF(7), 1, 0); A.det()
2253
+ Traceback (most recent call last):
2254
+ ...
2255
+ ValueError: self must be a square matrix
2256
+
2257
+ sage: A = matrix(GF(7), 5, 5); A.det() # needs sage.libs.pari
2258
+ 0
2259
+
2260
+ sage: # needs sage.rings.finite_rings
2261
+ sage: A = random_matrix(GF(16007), 0, 0); A.det()
2262
+ 1
2263
+ sage: A = random_matrix(GF(16007), 0, 1); A.det()
2264
+ Traceback (most recent call last):
2265
+ ...
2266
+ ValueError: self must be a square matrix
2267
+ sage: A = random_matrix(GF(16007), 1, 0); A.det()
2268
+ Traceback (most recent call last):
2269
+ ...
2270
+ ValueError: self must be a square matrix
2271
+ sage: A = matrix(GF(16007), 5, 5); A.det()
2272
+ 0
2273
+ """
2274
+ if self._nrows != self._ncols:
2275
+ raise ValueError("self must be a square matrix")
2276
+ if self._nrows == 0:
2277
+ return self._coerce_element(1)
2278
+
2279
+ if self.p > 2 and is_prime(self.p):
2280
+ x = self.fetch('det')
2281
+ if x is not None:
2282
+ return x
2283
+ d = linbox_det(self.p, self._entries, self._nrows)
2284
+ d2 = self._coerce_element(d)
2285
+ self.cache('det', d2)
2286
+ return d2
2287
+ else:
2288
+ return Matrix_dense.determinant(self)
2289
+
2290
+ cdef xgcd_eliminate(self, celement * row1, celement* row2, Py_ssize_t start_col):
2291
+ r"""
2292
+ Reduces ``row1`` and ``row2`` by a unimodular transformation
2293
+ using the xgcd relation between their first coefficients ``a`` and
2294
+ ``b``.
2295
+
2296
+ INPUT:
2297
+
2298
+ - ``row1``, ``row2`` -- the two rows to be transformed (within
2299
+ ``self``)
2300
+
2301
+ - ``start_col`` -- the column of the pivots in ``row1`` and
2302
+ ``row2``. It is assumed that all entries before ``start_col``
2303
+ in ``row1`` and ``row2`` are zero.
2304
+
2305
+ OUTPUT:
2306
+
2307
+ - g: the gcd of the first elements of row1 and
2308
+ row2 at column start_col
2309
+
2310
+ - put row1 = s \* row1 + t \* row2 row2 = w \*
2311
+ row1 + t \* row2 where g = sa + tb
2312
+ """
2313
+ cdef int p = <int>self.p
2314
+ cdef celement *row1_p
2315
+ cdef celement *row2_p
2316
+ cdef celement tmp
2317
+ cdef int g, s, t, v, w
2318
+ cdef Py_ssize_t nc, i
2319
+ cdef int a = <int>row1[start_col]
2320
+ cdef int b = <int>row2[start_col]
2321
+ g = ArithIntObj.c_xgcd_int(a, b, <int*>&s, <int*>&t)
2322
+ v = a/g
2323
+ w = -<int>b/g
2324
+ nc = self.ncols()
2325
+
2326
+ for i from start_col <= i < nc:
2327
+ tmp = (s * <int>row1[i] + t * <int>row2[i]) % p
2328
+ row2[i] = (w* <int>row1[i] + v*<int>row2[i]) % p
2329
+ row1[i] = tmp
2330
+ return g
2331
+
2332
+ cdef rescale_row_c(self, Py_ssize_t row, multiple, Py_ssize_t start_col):
2333
+ """
2334
+ Rescale ``self[row]`` by ``multiple`` but only start at column
2335
+ index ``start_col``.
2336
+
2337
+ INPUT:
2338
+
2339
+ - ``row`` -- integer
2340
+ - ``multiple`` -- finite field element
2341
+ - ``start_col`` -- integer
2342
+
2343
+ EXAMPLES::
2344
+
2345
+ sage: A = matrix(GF(19), 4, 4, range(16)); A
2346
+ [ 0 1 2 3]
2347
+ [ 4 5 6 7]
2348
+ [ 8 9 10 11]
2349
+ [12 13 14 15]
2350
+
2351
+ sage: A.rescale_row(1, 17, 2); A
2352
+ [ 0 1 2 3]
2353
+ [ 4 5 7 5]
2354
+ [ 8 9 10 11]
2355
+ [12 13 14 15]
2356
+
2357
+ sage: 6*17 % 19 == A[1,2]
2358
+ True
2359
+
2360
+ sage: A = matrix(Integers(2^4), 4, 4, range(16)); A
2361
+ [ 0 1 2 3]
2362
+ [ 4 5 6 7]
2363
+ [ 8 9 10 11]
2364
+ [12 13 14 15]
2365
+
2366
+ sage: A.rescale_row(1, 3, 2); A
2367
+ [ 0 1 2 3]
2368
+ [ 4 5 2 5]
2369
+ [ 8 9 10 11]
2370
+ [12 13 14 15]
2371
+
2372
+ sage: 6*3 % 16 == A[1,2]
2373
+ True
2374
+ """
2375
+ cdef celement r, p
2376
+ cdef celement* v
2377
+ cdef Py_ssize_t i
2378
+ p = self.p
2379
+ v = self._matrix[row]
2380
+ for i from start_col <= i < self._ncols:
2381
+ v[i] = (v[i]*<celement>multiple) % p
2382
+
2383
+ cdef rescale_col_c(self, Py_ssize_t col, multiple, Py_ssize_t start_row):
2384
+ """
2385
+ EXAMPLES::
2386
+
2387
+ sage: B = MatrixSpace(Integers(37),3,3)([1]*9)
2388
+ sage: B
2389
+ [1 1 1]
2390
+ [1 1 1]
2391
+ [1 1 1]
2392
+ sage: B.rescale_col(1,5)
2393
+ sage: B
2394
+ [1 5 1]
2395
+ [1 5 1]
2396
+ [1 5 1]
2397
+
2398
+ Recaling need not include the entire row.::
2399
+
2400
+ sage: B.rescale_col(0,2,1); B
2401
+ [1 5 1]
2402
+ [2 5 1]
2403
+ [2 5 1]
2404
+
2405
+ Bounds are checked.::
2406
+
2407
+ sage: B.rescale_col(3,2)
2408
+ Traceback (most recent call last):
2409
+ ...
2410
+ IndexError: matrix column index out of range
2411
+
2412
+ Rescaling by a negative number::
2413
+
2414
+ sage: B.rescale_col(2,-3); B
2415
+ [ 1 5 34]
2416
+ [ 2 5 34]
2417
+ [ 2 5 34]
2418
+ """
2419
+ cdef celement r, p
2420
+ cdef celement* v
2421
+ cdef Py_ssize_t i
2422
+ p = self.p
2423
+ for i from start_row <= i < self._nrows:
2424
+ self._matrix[i][col] = (self._matrix[i][col]*<celement>multiple) % p
2425
+
2426
+ cdef add_multiple_of_row_c(self, Py_ssize_t row_to, Py_ssize_t row_from, multiple, Py_ssize_t start_col):
2427
+ """
2428
+ Add ``multiple`` times ``self[row_from]`` to ``self[row_to]``
2429
+ statting in column ``start_col``.
2430
+
2431
+ EXAMPLES::
2432
+
2433
+ sage: A = random_matrix(GF(37), 10, 10)
2434
+ sage: B = copy(A)
2435
+
2436
+ sage: A.add_multiple_of_row(2, 3, 10)
2437
+ sage: all(A[i] == B[i] for i in range(10) if not i == 2)
2438
+ True
2439
+ sage: A[2] == B[2] + 10*B[3]
2440
+ True
2441
+
2442
+ sage: A.add_multiple_of_row(2, 3, 10, 4)
2443
+ sage: all(A[i] == B[i] for i in range(10) if not i == 2)
2444
+ True
2445
+ sage: A[2][:4] == B[2][:4] + 10*B[3][:4]
2446
+ True
2447
+ sage: A[2][4:] == B[2][4:] + 20*B[3][4:]
2448
+ True
2449
+ """
2450
+ cdef celement p
2451
+ cdef celement *v_from
2452
+ cdef celement *v_to
2453
+
2454
+ p = self.p
2455
+ v_from = self._matrix[row_from]
2456
+ v_to = self._matrix[row_to]
2457
+
2458
+ cdef Py_ssize_t i, nc
2459
+ nc = self._ncols
2460
+ for i from start_col <= i < nc:
2461
+ v_to[i] = ((<celement>multiple) * v_from[i] + v_to[i]) % p
2462
+
2463
+ cdef add_multiple_of_column_c(self, Py_ssize_t col_to, Py_ssize_t col_from, multiple, Py_ssize_t start_row):
2464
+ """
2465
+ Add ``multiple`` times ``self[row_from]`` to ``self[row_to]``
2466
+ statting in column ``start_col``.
2467
+
2468
+ EXAMPLES::
2469
+
2470
+ sage: A = random_matrix(GF(37), 10, 10)
2471
+ sage: B = copy(A)
2472
+
2473
+ sage: A.add_multiple_of_column(2, 3, 10)
2474
+ sage: all(A.column(i) == B.column(i) for i in range(10) if not i == 2)
2475
+ True
2476
+ sage: A.column(2) == B.column(2) + 10*B.column(3)
2477
+ True
2478
+
2479
+ sage: A.add_multiple_of_column(2, 3, 10, 4)
2480
+ sage: all(A.column(i) == B.column(i) for i in range(10) if not i == 2)
2481
+ True
2482
+ sage: A.column(2)[:4] == B.column(2)[:4] + 10*B.column(3)[:4]
2483
+ True
2484
+ sage: A.column(2)[4:] == B.column(2)[4:] + 20*B.column(3)[4:]
2485
+ True
2486
+ """
2487
+ cdef celement p
2488
+ cdef celement **m
2489
+
2490
+ m = self._matrix
2491
+ p = self.p
2492
+
2493
+ cdef Py_ssize_t i, nr
2494
+ nr = self._nrows
2495
+ for i from start_row <= i < self._nrows:
2496
+ m[i][col_to] = (m[i][col_to] + (<celement>multiple) * m[i][col_from]) %p
2497
+
2498
+ cdef swap_rows_c(self, Py_ssize_t row1, Py_ssize_t row2):
2499
+ """
2500
+ EXAMPLES::
2501
+
2502
+ sage: A = matrix(Integers(8), 2,[1,2,3,4])
2503
+ sage: A.swap_rows(0,1)
2504
+ sage: A
2505
+ [3 4]
2506
+ [1 2]
2507
+ """
2508
+ cdef celement* r1 = self._matrix[row1]
2509
+ cdef celement* r2 = self._matrix[row2]
2510
+ cdef celement temp
2511
+ for i in range(self._ncols):
2512
+ temp = r1[i]
2513
+ r1[i] = r2[i]
2514
+ r2[i] = temp
2515
+
2516
+ cdef swap_columns_c(self, Py_ssize_t col1, Py_ssize_t col2):
2517
+ """
2518
+ EXAMPLES::
2519
+
2520
+ sage: A = matrix(Integers(8), 2,[1,2,3,4])
2521
+ sage: A.swap_columns(0,1)
2522
+ sage: A
2523
+ [2 1]
2524
+ [4 3]
2525
+ """
2526
+ cdef Py_ssize_t i, nr
2527
+ cdef celement t
2528
+ cdef celement **m
2529
+ m = self._matrix
2530
+ nr = self._nrows
2531
+ for i from 0 <= i < nr:
2532
+ t = m[i][col1]
2533
+ m[i][col1] = m[i][col2]
2534
+ m[i][col2] = t
2535
+
2536
+ def randomize(self, density=1, nonzero=False):
2537
+ """
2538
+ Randomize ``density`` proportion of the entries of this
2539
+ matrix, leaving the rest unchanged.
2540
+
2541
+ INPUT:
2542
+
2543
+ - ``density`` -- integer; proportion (roughly) to be considered
2544
+ for changes
2545
+ - ``nonzero`` -- boolean (default: ``False``); whether the new
2546
+ entries are forced to be nonzero
2547
+
2548
+ OUTPUT: none, the matrix is modified in-space
2549
+
2550
+ EXAMPLES::
2551
+
2552
+ sage: A = matrix(GF(5), 5, 5, 0)
2553
+ sage: total_count = 0
2554
+ sage: from collections import defaultdict
2555
+ sage: dic = defaultdict(Integer)
2556
+ sage: def add_samples(density):
2557
+ ....: global dic, total_count
2558
+ ....: for _ in range(100):
2559
+ ....: A = Matrix(GF(5), 5, 5, 0)
2560
+ ....: A.randomize(density)
2561
+ ....: for a in A.list():
2562
+ ....: dic[a] += 1
2563
+ ....: total_count += 1.0
2564
+
2565
+ sage: add_samples(1.0)
2566
+ sage: while not all(abs(dic[a]/total_count - 1/5) < 0.01 for a in dic):
2567
+ ....: add_samples(1.0)
2568
+
2569
+ sage: def add_sample(density):
2570
+ ....: global density_sum, total_count
2571
+ ....: total_count += 1.0
2572
+ ....: density_sum += random_matrix(GF(5), 1000, 1000, density=density).density()
2573
+
2574
+ sage: density_sum = 0.0
2575
+ sage: total_count = 0.0
2576
+ sage: add_sample(0.5)
2577
+ sage: expected_density = 1.0 - (999/1000)^500
2578
+ sage: expected_density
2579
+ 0.3936...
2580
+ sage: while abs(density_sum/total_count - expected_density) > 0.001:
2581
+ ....: add_sample(0.5)
2582
+
2583
+ The matrix is updated instead of overwritten::
2584
+
2585
+ sage: def add_sample(density):
2586
+ ....: global density_sum, total_count
2587
+ ....: total_count += 1.0
2588
+ ....: A = random_matrix(GF(5), 1000, 1000, density=density)
2589
+ ....: A.randomize(density=density, nonzero=True)
2590
+ ....: density_sum += A.density()
2591
+
2592
+ sage: density_sum = 0.0
2593
+ sage: total_count = 0.0
2594
+ sage: add_sample(0.5)
2595
+ sage: expected_density = 1.0 - (999/1000)^1000
2596
+ sage: expected_density
2597
+ 0.6323...
2598
+ sage: while abs(density_sum/total_count - expected_density) > 0.001:
2599
+ ....: add_sample(0.5)
2600
+
2601
+ sage: density_sum = 0.0
2602
+ sage: total_count = 0.0
2603
+ sage: add_sample(0.1)
2604
+ sage: expected_density = 1.0 - (999/1000)^200
2605
+ sage: expected_density
2606
+ 0.1813...
2607
+ sage: while abs(density_sum/total_count - expected_density) > 0.001:
2608
+ ....: add_sample(0.1)
2609
+ """
2610
+ density = float(density)
2611
+ if density <= 0:
2612
+ return
2613
+ if density > 1:
2614
+ density = float(1)
2615
+
2616
+ self.check_mutability()
2617
+ self.clear_cache()
2618
+
2619
+ cdef randstate rstate = current_randstate()
2620
+
2621
+ cdef int nc, p = <int>self.p
2622
+ cdef long pm1
2623
+
2624
+ if not nonzero:
2625
+ # Original code, before adding the ``nonzero`` option.
2626
+ if density == 1:
2627
+ for i from 0 <= i < self._nrows*self._ncols:
2628
+ self._entries[i] = rstate.c_random() % p
2629
+ else:
2630
+ nc = self._ncols
2631
+ num_per_row = int(density * nc)
2632
+ sig_on()
2633
+ for i from 0 <= i < self._nrows:
2634
+ for j from 0 <= j < num_per_row:
2635
+ k = rstate.c_random() % nc
2636
+ self._matrix[i][k] = rstate.c_random() % p
2637
+ sig_off()
2638
+ else:
2639
+ # New code, to implement the ``nonzero`` option.
2640
+ pm1 = p - 1
2641
+ if density == 1:
2642
+ for i from 0 <= i < self._nrows*self._ncols:
2643
+ self._entries[i] = (rstate.c_random() % pm1) + 1
2644
+ else:
2645
+ nc = self._ncols
2646
+ num_per_row = int(density * nc)
2647
+ sig_on()
2648
+ for i from 0 <= i < self._nrows:
2649
+ for j from 0 <= j < num_per_row:
2650
+ k = rstate.c_random() % nc
2651
+ self._matrix[i][k] = (rstate.c_random() % pm1) + 1
2652
+ sig_off()
2653
+
2654
+ def _magma_init_(self, magma):
2655
+ """
2656
+ Return a string representation of ``self`` in Magma form.
2657
+
2658
+ INPUT:
2659
+
2660
+ - ``magma`` -- a Magma session
2661
+
2662
+ OUTPUT: string
2663
+
2664
+ EXAMPLES::
2665
+
2666
+ sage: a = matrix(GF(389),2,2,[1..4])
2667
+ sage: magma(a) # optional - magma
2668
+ [ 1 2]
2669
+ [ 3 4]
2670
+ sage: a._magma_init_(magma) # optional - magma
2671
+ 'Matrix(GF(389),2,2,StringToIntegerSequence("1 2 3 4"))'
2672
+
2673
+ A consistency check::
2674
+
2675
+ sage: a = random_matrix(GF(13),50); b = random_matrix(GF(13),50)
2676
+ sage: magma(a*b) == magma(a)*magma(b) # optional - magma
2677
+ True
2678
+ """
2679
+ s = self.base_ring()._magma_init_(magma)
2680
+ return 'Matrix(%s,%s,%s,StringToIntegerSequence("%s"))' % (
2681
+ s, self._nrows, self._ncols, self._export_as_string())
2682
+
2683
+ cpdef _export_as_string(self):
2684
+ """
2685
+ Return space separated string of the entries in this matrix.
2686
+
2687
+ EXAMPLES::
2688
+
2689
+ sage: A = matrix(GF(997),2,3,[1,2,5,-3,8,2]); A
2690
+ [ 1 2 5]
2691
+ [994 8 2]
2692
+ sage: A._export_as_string()
2693
+ '1 2 5 994 8 2'
2694
+ """
2695
+ cdef int ndigits = len(str(self.p))
2696
+
2697
+ cdef Py_ssize_t i, n
2698
+ cdef char *s
2699
+ cdef char *t
2700
+
2701
+ if self._nrows == 0 or self._ncols == 0:
2702
+ data = ''
2703
+ else:
2704
+ n = self._nrows*self._ncols*(ndigits + 1) + 2 # spaces between each number plus trailing null
2705
+ s = <char*>check_malloc(n * sizeof(char))
2706
+ t = s
2707
+ sig_on()
2708
+ for i in range(self._nrows * self._ncols):
2709
+ t += snprintf(t, ndigits+2, "%ld ", <long>self._entries[i])
2710
+
2711
+ sig_off()
2712
+ data = char_to_str(s)[:-1]
2713
+ sig_free(s)
2714
+ return data
2715
+
2716
+ def _list(self):
2717
+ """
2718
+ Return list of elements of ``self``. This method is called by ``self.list()``.
2719
+
2720
+ EXAMPLES::
2721
+
2722
+ sage: w = matrix(GF(19), 2, 3, [1..6])
2723
+ sage: w.list()
2724
+ [1, 2, 3, 4, 5, 6]
2725
+ sage: w._list()
2726
+ [1, 2, 3, 4, 5, 6]
2727
+ sage: w.list()[0].parent()
2728
+ Finite Field of size 19
2729
+
2730
+ TESTS::
2731
+
2732
+ sage: w = random_matrix(GF(3),100)
2733
+ sage: w.parent()(w.list()) == w
2734
+ True
2735
+ """
2736
+ cdef Py_ssize_t i
2737
+ F = self.base_ring()
2738
+ return [F(<int>self._entries[i]) for i in range(self._nrows*self._ncols)]
2739
+
2740
+ def lift(self):
2741
+ """
2742
+ Return the lift of this matrix to the integers.
2743
+
2744
+ EXAMPLES::
2745
+
2746
+ sage: A = matrix(GF(7),2,3,[1..6])
2747
+ sage: A.lift()
2748
+ [1 2 3]
2749
+ [4 5 6]
2750
+ sage: A.lift().parent()
2751
+ Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
2752
+
2753
+ sage: # needs sage.rings.finite_rings
2754
+ sage: A = matrix(GF(16007),2,3,[1..6])
2755
+ sage: A.lift()
2756
+ [1 2 3]
2757
+ [4 5 6]
2758
+ sage: A.lift().parent()
2759
+ Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
2760
+
2761
+ Subdivisions are preserved when lifting::
2762
+
2763
+ sage: A.subdivide([], [1,1]); A
2764
+ [1||2 3]
2765
+ [4||5 6]
2766
+ sage: A.lift()
2767
+ [1||2 3]
2768
+ [4||5 6]
2769
+ """
2770
+ cdef Py_ssize_t i, j
2771
+
2772
+ cdef Matrix_integer_dense L
2773
+ cdef object P = matrix_space.MatrixSpace(ZZ, self._nrows,
2774
+ self._ncols, sparse=False)
2775
+ L = Matrix_integer_dense(P, ZZ(0), False, False)
2776
+ cdef celement* A_row
2777
+ for i in range(self._nrows):
2778
+ A_row = self._matrix[i]
2779
+ for j in range(self._ncols):
2780
+ L.set_unsafe_double(i, j, A_row[j])
2781
+ if self._subdivisions is not None:
2782
+ L.subdivide(*self.subdivisions())
2783
+ return L
2784
+
2785
+ def transpose(self):
2786
+ """
2787
+ Return the transpose of ``self``, without changing ``self``.
2788
+
2789
+ EXAMPLES:
2790
+
2791
+ We create a matrix, compute its transpose, and note that
2792
+ the original matrix is not changed. ::
2793
+
2794
+ sage: M = MatrixSpace(GF(41), 2)
2795
+ sage: A = M([1,2,3,4])
2796
+ sage: B = A.transpose()
2797
+ sage: B
2798
+ [1 3]
2799
+ [2 4]
2800
+ sage: A
2801
+ [1 2]
2802
+ [3 4]
2803
+
2804
+ ``.T`` is a convenient shortcut for the transpose::
2805
+
2806
+ sage: A.T
2807
+ [1 3]
2808
+ [2 4]
2809
+
2810
+ ::
2811
+
2812
+ sage: A.subdivide(None, 1); A
2813
+ [1|2]
2814
+ [3|4]
2815
+ sage: A.transpose()
2816
+ [1 3]
2817
+ [---]
2818
+ [2 4]
2819
+ """
2820
+ cdef Py_ssize_t nrows = self._nrows
2821
+ cdef Py_ssize_t ncols = self._ncols
2822
+
2823
+ cdef Matrix_modn_dense_template M = self.new_matrix(nrows=ncols, ncols=nrows)
2824
+ cdef Py_ssize_t i, j
2825
+
2826
+ for i from 0 <= i < ncols:
2827
+ for j from 0 <= j < nrows:
2828
+ M._entries[j+i*nrows] = self._entries[i+j*ncols]
2829
+
2830
+ if self._subdivisions is not None:
2831
+ row_divs, col_divs = self.subdivisions()
2832
+ M.subdivide(col_divs, row_divs)
2833
+
2834
+ return M
2835
+
2836
+ cdef _stack_impl(self, bottom):
2837
+ r"""
2838
+ Implementation of :meth:`stack` by returning a new matrix
2839
+ formed by appending the matrix ``bottom`` beneath ``self``.
2840
+
2841
+ Assume that ``self`` and ``other`` are compatible in the sense
2842
+ that they have the same base ring and that both are dense.
2843
+
2844
+ INPUT:
2845
+
2846
+ - ``bottom`` -- a matrix compatible with ``self``
2847
+
2848
+ EXAMPLES:
2849
+
2850
+ Stacking with a matrix::
2851
+
2852
+ sage: A = matrix(GF(41), 4, 3, range(12))
2853
+ sage: B = matrix(GF(41), 3, 3, range(9))
2854
+ sage: A.stack(B)
2855
+ [ 0 1 2]
2856
+ [ 3 4 5]
2857
+ [ 6 7 8]
2858
+ [ 9 10 11]
2859
+ [ 0 1 2]
2860
+ [ 3 4 5]
2861
+ [ 6 7 8]
2862
+
2863
+ Stacking with a vector::
2864
+
2865
+ sage: A = matrix(GF(41), 3, 2, [0, 2, 4, 6, 8, 10])
2866
+ sage: v = vector(GF(41), 2, [100, 200])
2867
+ sage: A.stack(v)
2868
+ [ 0 2]
2869
+ [ 4 6]
2870
+ [ 8 10]
2871
+ [18 36]
2872
+
2873
+ Errors are raised if the sizes are incompatible::
2874
+
2875
+ sage: A = matrix(GF(41), [[1, 2],[3, 4]])
2876
+ sage: B = matrix(GF(41), [[10, 20, 30], [40, 50, 60]])
2877
+ sage: A.stack(B)
2878
+ Traceback (most recent call last):
2879
+ ...
2880
+ TypeError: number of columns must be the same, not 2 and 3
2881
+
2882
+ sage: v = vector(GF(41), [100, 200, 300])
2883
+ sage: A.stack(v)
2884
+ Traceback (most recent call last):
2885
+ ...
2886
+ TypeError: number of columns must be the same, not 2 and 3
2887
+
2888
+ Setting ``subdivide`` to ``True`` will, in its simplest form,
2889
+ add a subdivision between ``self`` and ``bottom``::
2890
+
2891
+ sage: A = matrix(GF(41), 2, 5, range(10))
2892
+ sage: B = matrix(GF(41), 3, 5, range(15))
2893
+ sage: A.stack(B, subdivide=True)
2894
+ [ 0 1 2 3 4]
2895
+ [ 5 6 7 8 9]
2896
+ [--------------]
2897
+ [ 0 1 2 3 4]
2898
+ [ 5 6 7 8 9]
2899
+ [10 11 12 13 14]
2900
+
2901
+ Row subdivisions are preserved by stacking, and enriched,
2902
+ if subdivisions are requested. (So multiple stackings can
2903
+ be recorded.) ::
2904
+
2905
+ sage: A = matrix(GF(41), 2, 4, range(8))
2906
+ sage: A.subdivide([1], None)
2907
+ sage: B = matrix(GF(41), 3, 4, range(12))
2908
+ sage: B.subdivide([2], None)
2909
+ sage: A.stack(B, subdivide=True)
2910
+ [ 0 1 2 3]
2911
+ [-----------]
2912
+ [ 4 5 6 7]
2913
+ [-----------]
2914
+ [ 0 1 2 3]
2915
+ [ 4 5 6 7]
2916
+ [-----------]
2917
+ [ 8 9 10 11]
2918
+
2919
+ Column subdivisions can be preserved, but only if they are identical.
2920
+ Otherwise, this information is discarded and must be managed
2921
+ separately. ::
2922
+
2923
+ sage: A = matrix(GF(41), 2, 5, range(10))
2924
+ sage: A.subdivide(None, [2,4])
2925
+ sage: B = matrix(GF(41), 3, 5, range(15))
2926
+ sage: B.subdivide(None, [2,4])
2927
+ sage: A.stack(B, subdivide=True)
2928
+ [ 0 1| 2 3| 4]
2929
+ [ 5 6| 7 8| 9]
2930
+ [-----+-----+--]
2931
+ [ 0 1| 2 3| 4]
2932
+ [ 5 6| 7 8| 9]
2933
+ [10 11|12 13|14]
2934
+
2935
+ sage: A.subdivide(None, [1,2])
2936
+ sage: A.stack(B, subdivide=True)
2937
+ [ 0 1 2 3 4]
2938
+ [ 5 6 7 8 9]
2939
+ [--------------]
2940
+ [ 0 1 2 3 4]
2941
+ [ 5 6 7 8 9]
2942
+ [10 11 12 13 14]
2943
+
2944
+ The result retains the base ring of ``self`` by coercing
2945
+ the elements of ``bottom`` into the base ring of ``self``::
2946
+
2947
+ sage: A = matrix(GF(41), 1, 2, [1,2])
2948
+ sage: B = matrix(ZZ, 1, 2, [100, 100])
2949
+ sage: C = A.stack(B); C
2950
+ [ 1 2]
2951
+ [18 18]
2952
+
2953
+ sage: C.parent()
2954
+ Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 41
2955
+
2956
+ sage: D = B.stack(A); D
2957
+ [18 18]
2958
+ [ 1 2]
2959
+
2960
+ sage: D.parent()
2961
+ Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 41
2962
+ """
2963
+ cdef Matrix_modn_dense_template other = <Matrix_modn_dense_template> bottom
2964
+ cdef Matrix_modn_dense_template M = self.new_matrix(nrows=self._nrows+other._nrows,
2965
+ ncols=self._ncols)
2966
+ cdef Py_ssize_t selfsize = self._ncols * self._nrows
2967
+ memcpy(M._entries, self._entries, sizeof(celement)*selfsize)
2968
+ memcpy(M._entries+selfsize, other._entries, sizeof(celement)*other._ncols*other._nrows)
2969
+ return M
2970
+
2971
+ def submatrix(self,
2972
+ Py_ssize_t row=0, Py_ssize_t col=0,
2973
+ Py_ssize_t nrows=-1, Py_ssize_t ncols=-1):
2974
+ r"""
2975
+ Return the matrix constructed from ``self`` using the specified
2976
+ range of rows and columns.
2977
+
2978
+ INPUT:
2979
+
2980
+ - ``row``, ``col`` -- index of the starting row and column;
2981
+ indices start at zero
2982
+
2983
+ - ``nrows``, ``ncols`` -- (optional) number of rows and columns to
2984
+ take; if not provided, take all rows below and all columns to
2985
+ the right of the starting entry
2986
+
2987
+ .. SEEALSO::
2988
+
2989
+ The functions :func:`matrix_from_rows`,
2990
+ :func:`matrix_from_columns`, and
2991
+ :func:`matrix_from_rows_and_columns` allow one to select
2992
+ arbitrary subsets of rows and/or columns.
2993
+
2994
+ EXAMPLES:
2995
+
2996
+ Take the `3 \times 3` submatrix starting from entry `(1,1)` in a
2997
+ `4 \times 4` matrix::
2998
+
2999
+ sage: m = matrix(GF(17),4, [1..16])
3000
+ sage: m.submatrix(1, 1)
3001
+ [ 6 7 8]
3002
+ [10 11 12]
3003
+ [14 15 16]
3004
+
3005
+ Same thing, except take only two rows::
3006
+
3007
+ sage: m.submatrix(1, 1, 2)
3008
+ [ 6 7 8]
3009
+ [10 11 12]
3010
+
3011
+ And now take only one column::
3012
+
3013
+ sage: m.submatrix(1, 1, 2, 1)
3014
+ [ 6]
3015
+ [10]
3016
+
3017
+ You can take zero rows or columns if you want::
3018
+
3019
+ sage: m.submatrix(0, 0, 0)
3020
+ []
3021
+ sage: parent(m.submatrix(0, 0, 0))
3022
+ Full MatrixSpace of 0 by 4 dense matrices over Finite Field of size 17
3023
+ """
3024
+ if ncols == -1:
3025
+ ncols = self._ncols - col
3026
+
3027
+ if nrows == -1:
3028
+ nrows = self._nrows - row
3029
+
3030
+ if nrows < 0 or row < 0 or row + nrows > self._nrows:
3031
+ raise IndexError("rows out of range")
3032
+ if ncols < 0 or col < 0 or col + ncols > self._ncols:
3033
+ raise IndexError("columns out of range")
3034
+
3035
+ cdef Matrix_modn_dense_template M = self.new_matrix(nrows=nrows, ncols=ncols)
3036
+
3037
+ if col == 0 and ncols == self._ncols:
3038
+ memcpy(M._entries, self._matrix[row], sizeof(celement)*ncols*nrows)
3039
+ return M
3040
+
3041
+ cdef Py_ssize_t i, r
3042
+ for i, r in enumerate(range(row, row+nrows)) :
3043
+ memcpy(M._matrix[i], self._matrix[r]+col, sizeof(celement)*ncols)
3044
+
3045
+ return M
3046
+
3047
+ def _matrices_from_rows(self, Py_ssize_t nrows, Py_ssize_t ncols):
3048
+ """
3049
+ Make a list of matrix from the rows of this matrix. This is a
3050
+ fairly technical function which is used internally, e.g., by
3051
+ the cyclotomic field linear algebra code.
3052
+
3053
+ INPUT:
3054
+
3055
+ - ``nrows`` -- integer
3056
+
3057
+ - ``ncols`` -- integer
3058
+
3059
+ EXAMPLES::
3060
+
3061
+ sage: A = matrix(GF(127), 4, 4, range(16))
3062
+ sage: A
3063
+ [ 0 1 2 3]
3064
+ [ 4 5 6 7]
3065
+ [ 8 9 10 11]
3066
+ [12 13 14 15]
3067
+ sage: A._matrices_from_rows(2,2)
3068
+ [
3069
+ [0 1] [4 5] [ 8 9] [12 13]
3070
+ [2 3], [6 7], [10 11], [14 15]
3071
+ ]
3072
+
3073
+ OUTPUT: list of matrices
3074
+ """
3075
+ if nrows * ncols != self._ncols:
3076
+ raise ValueError("nrows * ncols must equal self's number of columns")
3077
+
3078
+ cdef Matrix_modn_dense_template M
3079
+ cdef Py_ssize_t i
3080
+ cdef Py_ssize_t n = nrows * ncols
3081
+ ans = []
3082
+ for i from 0 <= i < self._nrows:
3083
+ M = self.new_matrix(nrows = nrows, ncols = ncols)
3084
+ memcpy(M._entries, self._entries+i*n, sizeof(celement)*n)
3085
+ ans.append(M)
3086
+ return ans
3087
+
3088
+ def matrix_from_columns(self, columns):
3089
+ """
3090
+ Return the matrix constructed from ``self`` using columns with indices
3091
+ in the columns list.
3092
+
3093
+ EXAMPLES::
3094
+
3095
+ sage: M = MatrixSpace(Integers(8),3,3)
3096
+ sage: A = M(range(9)); A
3097
+ [0 1 2]
3098
+ [3 4 5]
3099
+ [6 7 0]
3100
+ sage: A.matrix_from_columns([2,1])
3101
+ [2 1]
3102
+ [5 4]
3103
+ [0 7]
3104
+ """
3105
+ cdef Py_ssize_t ncols = len(columns)
3106
+
3107
+ # Construct new matrix
3108
+ cdef Matrix_modn_dense_template A = self.new_matrix(ncols=ncols)
3109
+ cdef Py_ssize_t i, j, col
3110
+ for j, col in enumerate(columns):
3111
+ if col < 0 or col >= self._ncols:
3112
+ raise IndexError("column index out of range")
3113
+ for i in range(self._nrows):
3114
+ A._matrix[i][j] = self._matrix[i][col]
3115
+
3116
+ return A
3117
+
3118
+ def matrix_from_rows(self, rows):
3119
+ """
3120
+ Return the matrix constructed from ``self`` using rows with indices in
3121
+ the rows list.
3122
+
3123
+ EXAMPLES::
3124
+
3125
+ sage: M = MatrixSpace(Integers(8),3,3)
3126
+ sage: A = M(range(9)); A
3127
+ [0 1 2]
3128
+ [3 4 5]
3129
+ [6 7 0]
3130
+ sage: A.matrix_from_rows([2,1])
3131
+ [6 7 0]
3132
+ [3 4 5]
3133
+ """
3134
+ cdef Py_ssize_t nrows = len(rows)
3135
+
3136
+ # Construct new matrix
3137
+ cdef Matrix_modn_dense_template A = self.new_matrix(nrows=nrows)
3138
+
3139
+ cdef Py_ssize_t i, row
3140
+ for i, row in enumerate(rows):
3141
+ if row < 0 or row >= self._nrows:
3142
+ raise IndexError("row index out of range")
3143
+ memcpy(A._matrix[i], self._matrix[row], sizeof(celement)*self._ncols)
3144
+
3145
+ return A
3146
+
3147
+ def matrix_from_rows_and_columns(self, rows, columns):
3148
+ """
3149
+ Return the matrix constructed from ``self`` from the given rows and
3150
+ columns.
3151
+
3152
+ EXAMPLES::
3153
+
3154
+ sage: M = MatrixSpace(Integers(8),3,3)
3155
+ sage: A = M(range(9)); A
3156
+ [0 1 2]
3157
+ [3 4 5]
3158
+ [6 7 0]
3159
+ sage: A.matrix_from_rows_and_columns([1], [0,2])
3160
+ [3 5]
3161
+ sage: A.matrix_from_rows_and_columns([1,2], [1,2])
3162
+ [4 5]
3163
+ [7 0]
3164
+
3165
+ Note that row and column indices can be reordered or repeated::
3166
+
3167
+ sage: A.matrix_from_rows_and_columns([2,1], [2,1])
3168
+ [0 7]
3169
+ [5 4]
3170
+
3171
+ For example here we take from row 1 columns 2 then 0 twice, and do
3172
+ this 3 times::
3173
+
3174
+ sage: A.matrix_from_rows_and_columns([1,1,1],[2,0,0])
3175
+ [5 3 3]
3176
+ [5 3 3]
3177
+ [5 3 3]
3178
+
3179
+ AUTHORS:
3180
+
3181
+ - Jaap Spies (2006-02-18)
3182
+
3183
+ - Didier Deshommes: some Pyrex speedups implemented
3184
+ """
3185
+ cdef Py_ssize_t ncols = len(columns)
3186
+ cdef Py_ssize_t nrows = len(rows)
3187
+
3188
+ # Check whether column indices are valid
3189
+ cdef Py_ssize_t i, j, row, col
3190
+ for col in columns:
3191
+ if col < 0 or col >= self._ncols:
3192
+ raise IndexError("column index out of range")
3193
+
3194
+ # Construct new matrix
3195
+ cdef Matrix_modn_dense_template A = self.new_matrix(nrows=nrows, ncols=ncols)
3196
+ for i, row in enumerate(rows):
3197
+ if row < 0 or row >= self._nrows:
3198
+ raise IndexError("row index out of range")
3199
+ for j, col in enumerate(columns):
3200
+ A._matrix[i][j] = self._matrix[row][col]
3201
+
3202
+ return A
3203
+
3204
+ def __bool__(self):
3205
+ """
3206
+ Test whether this matrix is zero.
3207
+
3208
+ EXAMPLES::
3209
+
3210
+ sage: A = matrix(GF(7), 10, 10, range(100))
3211
+ sage: A == 0 # indirect doctest
3212
+ False
3213
+ sage: A.is_zero()
3214
+ False
3215
+
3216
+ sage: A = matrix(Integers(10), 10, 10)
3217
+ sage: bool(A)
3218
+ False
3219
+
3220
+ sage: # needs sage.rings.finite_rings
3221
+ sage: A = matrix(GF(16007), 0, 0)
3222
+ sage: A.is_zero()
3223
+ True
3224
+ sage: A = matrix(GF(16007), 1, 0)
3225
+ sage: A.is_zero()
3226
+ True
3227
+ sage: A = matrix(GF(16007), 0, 1)
3228
+ sage: A.is_zero()
3229
+ True
3230
+ """
3231
+ return not linbox_is_zero(self.p, self._entries, self._nrows, self._ncols)
3232
+
3233
+ _matrix_from_rows_of_matrices = staticmethod(__matrix_from_rows_of_matrices)
3234
+
3235
+ cdef int _copy_row_to_mod_int_array(self, mod_int *to, Py_ssize_t i) noexcept:
3236
+ cdef Py_ssize_t j
3237
+ cdef celement *_from = self._entries+(i*self._ncols)
3238
+ for j in range(self._ncols):
3239
+ to[j] = <mod_int>_from[j]
3240
+
3241
+ cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1:
3242
+ r"""
3243
+ Return 1 if the entry ``(i, j)`` is zero, otherwise 0.
3244
+
3245
+ EXAMPLES::
3246
+
3247
+ sage: M = Matrix(GF(49), 2, [1,2,-2,0]) # needs sage.rings.finite_rings
3248
+ sage: M.zero_pattern_matrix() # indirect doctest # needs sage.rings.finite_rings
3249
+ [0 0]
3250
+ [0 1]
3251
+
3252
+ sage: M = Matrix(Integers(10), 2, [1,2,-2,0])
3253
+ sage: M.zero_pattern_matrix() # indirect doctest
3254
+ [0 0]
3255
+ [0 1]
3256
+ """
3257
+ return self._entries[j+i*self._ncols] == 0