passagemath-linbox 10.6.32__cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of passagemath-linbox might be problematic. Click here for more details.

Files changed (73) hide show
  1. passagemath_linbox-10.6.32.dist-info/METADATA +100 -0
  2. passagemath_linbox-10.6.32.dist-info/RECORD +73 -0
  3. passagemath_linbox-10.6.32.dist-info/WHEEL +6 -0
  4. passagemath_linbox-10.6.32.dist-info/top_level.txt +2 -0
  5. passagemath_linbox.libs/libfflas-d452d784.so.1.0.0 +0 -0
  6. passagemath_linbox.libs/libffpack-32579c9b.so.1.0.0 +0 -0
  7. passagemath_linbox.libs/libflint-66e12231.so.21.0.0 +0 -0
  8. passagemath_linbox.libs/libgd-76eb082b.so.3.0.11 +0 -0
  9. passagemath_linbox.libs/libgfortran-83c28eba.so.5.0.0 +0 -0
  10. passagemath_linbox.libs/libgivaro-fc554fc9.so.9.2.1 +0 -0
  11. passagemath_linbox.libs/libgmp-6e109695.so.10.5.0 +0 -0
  12. passagemath_linbox.libs/libgmpxx-ecb9d6e3.so.4.7.0 +0 -0
  13. passagemath_linbox.libs/libiml-aeb1d147.so.0.1.1 +0 -0
  14. passagemath_linbox.libs/liblinbox-f1d24fc1.so.0.0.0 +0 -0
  15. passagemath_linbox.libs/libm4ri-9da2b874.so.1.0.0 +0 -0
  16. passagemath_linbox.libs/libm4rie-cf8cc058.so.1.0.0 +0 -0
  17. passagemath_linbox.libs/libmpfr-82690d50.so.6.2.1 +0 -0
  18. passagemath_linbox.libs/libopenblasp-r0-6dcb67f9.3.29.so +0 -0
  19. passagemath_linbox.libs/libpng16-b4a91cd1.so.16.43.0 +0 -0
  20. passagemath_linbox.libs/libquadmath-2284e583.so.0.0.0 +0 -0
  21. sage/all__sagemath_linbox.py +2 -0
  22. sage/geometry/all__sagemath_linbox.py +1 -0
  23. sage/geometry/integral_points.pxi +1426 -0
  24. sage/geometry/integral_points_integer_dense.cpython-313-x86_64-linux-gnu.so +0 -0
  25. sage/geometry/integral_points_integer_dense.pyx +7 -0
  26. sage/libs/all__sagemath_linbox.py +1 -0
  27. sage/libs/iml.pxd +10 -0
  28. sage/libs/linbox/__init__.py +1 -0
  29. sage/libs/linbox/conversion.pxd +185 -0
  30. sage/libs/linbox/fflas.pxd +189 -0
  31. sage/libs/linbox/givaro.pxd +109 -0
  32. sage/libs/linbox/linbox.pxd +219 -0
  33. sage/libs/linbox/linbox_flint_interface.cpython-313-x86_64-linux-gnu.so +0 -0
  34. sage/libs/linbox/linbox_flint_interface.pxd +18 -0
  35. sage/libs/linbox/linbox_flint_interface.pyx +192 -0
  36. sage/libs/m4ri.pxd +198 -0
  37. sage/libs/m4rie.pxd +204 -0
  38. sage/matrix/all__sagemath_linbox.py +1 -0
  39. sage/matrix/matrix_cyclo_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
  40. sage/matrix/matrix_cyclo_linbox.pyx +361 -0
  41. sage/matrix/matrix_gf2e_dense.cpython-313-x86_64-linux-gnu.so +0 -0
  42. sage/matrix/matrix_gf2e_dense.pxd +15 -0
  43. sage/matrix/matrix_gf2e_dense.pyx +1573 -0
  44. sage/matrix/matrix_integer_iml.cpython-313-x86_64-linux-gnu.so +0 -0
  45. sage/matrix/matrix_integer_iml.pyx +316 -0
  46. sage/matrix/matrix_integer_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
  47. sage/matrix/matrix_integer_linbox.pxd +5 -0
  48. sage/matrix/matrix_integer_linbox.pyx +358 -0
  49. sage/matrix/matrix_integer_sparse_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
  50. sage/matrix/matrix_integer_sparse_linbox.pyx +465 -0
  51. sage/matrix/matrix_mod2_dense.cpython-313-x86_64-linux-gnu.so +0 -0
  52. sage/matrix/matrix_mod2_dense.pxd +14 -0
  53. sage/matrix/matrix_mod2_dense.pyx +2789 -0
  54. sage/matrix/matrix_modn_dense_double.cpython-313-x86_64-linux-gnu.so +0 -0
  55. sage/matrix/matrix_modn_dense_double.pyx +179 -0
  56. sage/matrix/matrix_modn_dense_float.cpython-313-x86_64-linux-gnu.so +0 -0
  57. sage/matrix/matrix_modn_dense_float.pyx +154 -0
  58. sage/matrix/matrix_modn_sparse.cpython-313-x86_64-linux-gnu.so +0 -0
  59. sage/matrix/matrix_modn_sparse.pyx +871 -0
  60. sage/matrix/matrix_rational_linbox.cpython-313-x86_64-linux-gnu.so +0 -0
  61. sage/matrix/matrix_rational_linbox.pyx +36 -0
  62. sage/matrix/misc.cpython-313-x86_64-linux-gnu.so +0 -0
  63. sage/matrix/misc.pyx +418 -0
  64. sage/modules/all__sagemath_linbox.py +1 -0
  65. sage/modules/numpy_util.cpython-313-x86_64-linux-gnu.so +0 -0
  66. sage/modules/numpy_util.pxd +10 -0
  67. sage/modules/numpy_util.pyx +136 -0
  68. sage/modules/vector_mod2_dense.cpython-313-x86_64-linux-gnu.so +0 -0
  69. sage/modules/vector_mod2_dense.pxd +11 -0
  70. sage/modules/vector_mod2_dense.pyx +547 -0
  71. sage/rings/all__sagemath_linbox.py +1 -0
  72. sage/rings/finite_rings/all__sagemath_linbox.py +1 -0
  73. sage/rings/polynomial/all__sagemath_linbox.py +1 -0
@@ -0,0 +1,1573 @@
1
+ # sage_setup: distribution = sagemath-linbox
2
+ # distutils: libraries = m4rie M4RI_LIBRARIES M_LIBRARIES
3
+ # distutils: library_dirs = M4RI_LIBDIR
4
+ # distutils: include_dirs = M4RI_INCDIR
5
+ # distutils: extra_compile_args = M4RI_CFLAGS
6
+ # sage.doctest: needs sage.rings.finite_rings
7
+ r"""
8
+ Dense matrices over `\GF{2^e}` for `2 \leq e \leq 16` using the M4RIE library
9
+
10
+ The M4RIE library offers two matrix representations:
11
+
12
+ 1) ``mzed_t``
13
+
14
+ m x n matrices over `\GF{2^e}` are internally represented roughly as
15
+ m x (en) matrices over `\GF{2}`. Several elements are packed into
16
+ words such that each element is filled with zeroes until the next
17
+ power of two. Thus, for example, elements of `\GF{2^3}` are
18
+ represented as ``[0xxx|0xxx|0xxx|0xxx|...]``. This representation is
19
+ wrapped as :class:`Matrix_gf2e_dense` in Sage.
20
+
21
+ Multiplication and elimination both use "Newton-John" tables. These
22
+ tables are simply all possible multiples of a given row in a matrix
23
+ such that a scale+add operation is reduced to a table lookup +
24
+ add. On top of Newton-John multiplication M4RIE implements
25
+ asymptotically fast Strassen-Winograd multiplication. Elimination
26
+ uses simple Gaussian elimination which requires `O(n^3)` additions
27
+ but only `O(n^2 * 2^e)` multiplications.
28
+
29
+ 2) ``mzd_slice_t``
30
+
31
+ m x n matrices over `\GF{2^e}` are internally represented as slices
32
+ of m x n matrices over `\GF{2}`. This representation allows for very
33
+ fast matrix times matrix products using Karatsuba's polynomial
34
+ multiplication for polynomials over matrices. However, it is not
35
+ feature complete yet and hence not wrapped in Sage for now.
36
+
37
+ See http://m4ri.sagemath.org for more details on the M4RIE library.
38
+
39
+ EXAMPLES::
40
+
41
+ sage: K.<a> = GF(2^8)
42
+ sage: A = random_matrix(K, 3,4)
43
+ sage: E = A.echelon_form()
44
+ sage: A.row_space() == E.row_space()
45
+ True
46
+ sage: all(r[r.nonzero_positions()[0]] == 1 for r in E.rows() if r)
47
+ True
48
+
49
+ AUTHOR:
50
+
51
+ * Martin Albrecht <martinralbrecht@googlemail.com>
52
+
53
+ TESTS::
54
+
55
+ sage: TestSuite(sage.matrix.matrix_gf2e_dense.Matrix_gf2e_dense).run(verbose=True)
56
+ running ._test_new() . . . pass
57
+ running ._test_pickling() . . . pass
58
+
59
+ Test hashing::
60
+
61
+ sage: K.<a> = GF(2^4)
62
+ sage: A = random_matrix(K, 1000, 1000)
63
+ sage: A.set_immutable()
64
+ sage: {A:1}
65
+ {1000 x 1000 dense matrix over Finite Field in a of size 2^4: 1}
66
+
67
+ .. TODO::
68
+
69
+ Wrap ``mzd_slice_t``.
70
+
71
+ REFERENCES:
72
+
73
+ - [BB2009]_
74
+ """
75
+
76
+ #*****************************************************************************
77
+ # Copyright (C) 2010 Martin Albrecht <martinralbrecht@googlemail.com>
78
+ #
79
+ # This program is free software: you can redistribute it and/or modify
80
+ # it under the terms of the GNU General Public License as published by
81
+ # the Free Software Foundation, either version 2 of the License, or
82
+ # (at your option) any later version.
83
+ # https://www.gnu.org/licenses/
84
+ #*****************************************************************************
85
+
86
+ from cysignals.signals cimport sig_on, sig_off
87
+
88
+ cimport sage.matrix.matrix_dense as matrix_dense
89
+ from sage.structure.element cimport Matrix
90
+ from sage.structure.element cimport Element
91
+ from sage.structure.richcmp cimport rich_to_bool
92
+ from sage.rings.finite_rings.element_base cimport Cache_base
93
+
94
+ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
95
+ from sage.misc.randstate cimport randstate, current_randstate
96
+
97
+ from sage.matrix.matrix_mod2_dense cimport Matrix_mod2_dense
98
+ from sage.matrix.args cimport SparseEntry, MatrixArgs_init
99
+
100
+ from sage.libs.m4ri cimport m4ri_word, mzd_copy
101
+ from sage.libs.m4rie cimport *
102
+ from sage.libs.m4rie cimport mzed_t
103
+
104
+
105
+ # we must keep a copy of the internal finite field representation
106
+ # around to avoid re-creating it over and over again. Furthermore,
107
+ # M4RIE assumes pointer equivalence of identical fields.
108
+
109
+ _m4rie_finite_field_cache = {}
110
+
111
+ cdef class M4RIE_finite_field:
112
+ """
113
+ A thin wrapper around the M4RIE finite field class such that we
114
+ can put it in a hash table. This class is not meant for public
115
+ consumption.
116
+ """
117
+ cdef gf2e *ff
118
+
119
+ def __dealloc__(self):
120
+ """
121
+ EXAMPLES::
122
+
123
+ sage: from sage.matrix.matrix_gf2e_dense import M4RIE_finite_field
124
+ sage: K = M4RIE_finite_field(); K
125
+ <sage.matrix.matrix_gf2e_dense.M4RIE_finite_field object at 0x...>
126
+ sage: del K
127
+ """
128
+ if self.ff:
129
+ gf2e_free(self.ff)
130
+
131
+ cdef m4ri_word poly_to_word(f) noexcept:
132
+ return f.to_integer()
133
+
134
+
135
+ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense):
136
+ def __cinit__(self, *args, bint alloc=True, **kwds):
137
+ """
138
+ INPUT:
139
+
140
+ - ``alloc`` -- if ``True`` the matrix is allocated first (default: ``True``)
141
+
142
+ EXAMPLES::
143
+
144
+ sage: K.<a> = GF(2^4)
145
+ sage: A = Matrix(K, 3, 4); A
146
+ [0 0 0 0]
147
+ [0 0 0 0]
148
+ [0 0 0 0]
149
+
150
+ sage: A.randomize()
151
+ sage: TestSuite(A).run()
152
+
153
+ sage: K.<a> = GF(2^3)
154
+ sage: A = Matrix(K,3,4); A
155
+ [0 0 0 0]
156
+ [0 0 0 0]
157
+ [0 0 0 0]
158
+
159
+ sage: A.randomize()
160
+ sage: TestSuite(A).run()
161
+ """
162
+ cdef M4RIE_finite_field FF
163
+
164
+ R = self._base_ring
165
+ f = R.polynomial()
166
+
167
+ cdef long i
168
+ cdef m4ri_word poly = sum(((<m4ri_word>c) << i) for (i, c) in enumerate(f))
169
+
170
+ if alloc and self._nrows and self._ncols:
171
+ if poly in _m4rie_finite_field_cache:
172
+ self._entries = mzed_init((<M4RIE_finite_field>_m4rie_finite_field_cache[poly]).ff, self._nrows, self._ncols)
173
+ else:
174
+ FF = M4RIE_finite_field.__new__(M4RIE_finite_field)
175
+ FF.ff = gf2e_init(poly)
176
+ self._entries = mzed_init(FF.ff, self._nrows, self._ncols)
177
+ _m4rie_finite_field_cache[poly] = FF
178
+
179
+ # cache elements
180
+ self._zero = self._base_ring(0)
181
+ self._zero_word = poly_to_word(self._zero)
182
+ self._one = self._base_ring(1)
183
+
184
+ def __dealloc__(self):
185
+ """
186
+ TESTS::
187
+
188
+ sage: K.<a> = GF(2^4)
189
+ sage: A = Matrix(K, 1000, 1000)
190
+ sage: del A
191
+ sage: A = Matrix(K, 1000, 1000)
192
+ sage: del A
193
+ """
194
+ if self._entries:
195
+ mzed_free(self._entries)
196
+ self._entries = NULL
197
+
198
+ def __init__(self, parent, entries=None, copy=None, bint coerce=True):
199
+ r"""
200
+ Create new matrix over `GF(2^e)` for `2 \leq e \leq 16`.
201
+
202
+ INPUT:
203
+
204
+ - ``parent`` -- a matrix space over ``GF(2^e)``
205
+
206
+ - ``entries`` -- see :func:`matrix`
207
+
208
+ - ``copy`` -- ignored (for backwards compatibility)
209
+
210
+ - ``coerce`` -- if ``False``, assume without checking that the
211
+ entries lie in the base ring
212
+
213
+ EXAMPLES::
214
+
215
+ sage: K.<a> = GF(2^4)
216
+ sage: l = [K.random_element() for _ in range(3*4)]
217
+
218
+ sage: A = Matrix(K, 3, 4, l)
219
+ sage: l == A.list()
220
+ True
221
+
222
+ sage: l[0] == A[0,0]
223
+ True
224
+
225
+ sage: A = Matrix(K, 3, 3, a); A
226
+ [a 0 0]
227
+ [0 a 0]
228
+ [0 0 a]
229
+ """
230
+ ma = MatrixArgs_init(parent, entries)
231
+ for t in ma.iter(coerce, True):
232
+ se = <SparseEntry>t
233
+ mzed_write_elem(self._entries, se.i, se.j, poly_to_word(se.entry))
234
+
235
+ cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, value):
236
+ """
237
+ A[i,j] = value without bound checks.
238
+
239
+ INPUT:
240
+
241
+ - ``i`` -- row index
242
+ - ``j`` -- column index
243
+ - ``value`` -- a finite field element (not checked but assumed)
244
+
245
+ EXAMPLES::
246
+
247
+ sage: K.<a> = GF(2^4)
248
+ sage: l = [K.random_element() for _ in range(3*4)]
249
+ sage: A = Matrix(K, 3, 4, l)
250
+
251
+ sage: i = randrange(3)
252
+ sage: j = randrange(4)
253
+ sage: A[i,j] = a # indirect doctest
254
+ sage: A[i,j] == a == A.list()[j + 4*i]
255
+ True
256
+ sage: A.list()[:j + 4*i] == l[:j + 4*i]
257
+ True
258
+ sage: A.list()[j + 4*i + 1:] == l[j + 4*i + 1:]
259
+ True
260
+ """
261
+ mzed_write_elem(self._entries, i, j, poly_to_word(value))
262
+
263
+ cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
264
+ """
265
+ Get A[i,j] without bound checks.
266
+
267
+ INPUT:
268
+
269
+ - ``i`` -- row index
270
+ - ``j`` -- column index
271
+
272
+ EXAMPLES::
273
+
274
+ sage: K.<a> = GF(2^4)
275
+ sage: l = [K.random_element() for _ in range(3*4)]
276
+ sage: A = Matrix(K, 3, 4, l)
277
+ sage: A[2,3] == l[3 + 4*2] # indirect doctest
278
+ True
279
+ sage: K.<a> = GF(2^3)
280
+ sage: l = [K.random_element() for _ in range(3*4)]
281
+ sage: A = Matrix(K, 3, 4, l)
282
+ sage: A.list() == l
283
+ True
284
+ """
285
+ cdef int r = mzed_read_elem(self._entries, i, j)
286
+ cdef Cache_base cache = <Cache_base> self._base_ring._cache
287
+ return cache.fetch_int(r)
288
+
289
+ cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1:
290
+ r"""
291
+ Return 1 if the entry ``(i, j)`` is zero, otherwise 0.
292
+
293
+ EXAMPLES::
294
+
295
+ sage: K.<a> = GF(2^4)
296
+ sage: A = Matrix(K, 2, 2, a)
297
+ sage: A.zero_pattern_matrix() # indirect doctest
298
+ [0 1]
299
+ [1 0]
300
+ """
301
+ return mzed_read_elem(self._entries, i, j) == self._zero_word
302
+
303
+ cpdef _add_(self, right):
304
+ r"""
305
+ Return ``A+B``.
306
+
307
+ INPUT:
308
+
309
+ - ``right`` -- a matrix
310
+
311
+ EXAMPLES::
312
+
313
+ sage: K.<a> = GF(2^4)
314
+ sage: A = random_matrix(K,3,4)
315
+ sage: B = random_matrix(K,3,4)
316
+
317
+ sage: C = A + B # indirect doctest
318
+ sage: all(C.list()[i] == A.list()[i] + B.list()[i] for i in range(12))
319
+ True
320
+ """
321
+ cdef Matrix_gf2e_dense A
322
+ A = Matrix_gf2e_dense.__new__(Matrix_gf2e_dense, self._parent, 0, 0, 0, alloc=False)
323
+ if self._nrows == 0 or self._ncols == 0:
324
+ return A
325
+ A._entries = mzed_add(NULL, self._entries, (<Matrix_gf2e_dense>right)._entries)
326
+
327
+ return A
328
+
329
+ cpdef _sub_(self, right):
330
+ """
331
+ EXAMPLES::
332
+
333
+ sage: from sage.matrix.matrix_gf2e_dense import Matrix_gf2e_dense
334
+ sage: K.<a> = GF(2^4)
335
+ sage: A = random_matrix(K,3,4)
336
+ sage: B = random_matrix(K,3,4)
337
+ sage: C = A - B # indirect doctest
338
+ sage: all(C.list()[i] == A.list()[i] - B.list()[i] for i in range(12))
339
+ True
340
+ """
341
+ return self._add_(right)
342
+
343
+ def _multiply_classical(self, Matrix right):
344
+ """
345
+ Classical cubic matrix multiplication.
346
+
347
+ EXAMPLES::
348
+
349
+ sage: K.<a> = GF(2^2)
350
+ sage: A = random_matrix(K, 50, 50)
351
+ sage: B = random_matrix(K, 50, 50)
352
+ sage: A*B == A._multiply_classical(B)
353
+ True
354
+
355
+ sage: K.<a> = GF(2^4)
356
+ sage: A = random_matrix(K, 50, 50)
357
+ sage: B = random_matrix(K, 50, 50)
358
+ sage: A*B == A._multiply_classical(B)
359
+ True
360
+
361
+ sage: K.<a> = GF(2^8)
362
+ sage: A = random_matrix(K, 50, 50)
363
+ sage: B = random_matrix(K, 50, 50)
364
+ sage: A*B == A._multiply_classical(B)
365
+ True
366
+
367
+ sage: K.<a> = GF(2^10)
368
+ sage: A = random_matrix(K, 50, 50)
369
+ sage: B = random_matrix(K, 50, 50)
370
+ sage: A*B == A._multiply_classical(B)
371
+ True
372
+
373
+ .. NOTE::
374
+
375
+ This function is very slow. Use ``*`` operator instead.
376
+ """
377
+ if self._ncols != right._nrows:
378
+ raise ArithmeticError("left ncols must match right nrows")
379
+
380
+ cdef Matrix_gf2e_dense ans
381
+
382
+ ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols())
383
+ if self._nrows == 0 or self._ncols == 0 or right._ncols == 0:
384
+ return ans
385
+ sig_on()
386
+ ans._entries = mzed_mul_naive(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries)
387
+ sig_off()
388
+ return ans
389
+
390
+ cdef _matrix_times_matrix_(self, Matrix right):
391
+ r"""
392
+ Return ``A*B``.
393
+
394
+ Uses the M4RIE machinery to decide which function to call.
395
+
396
+ INPUT:
397
+
398
+ - ``right`` -- a matrix
399
+
400
+ EXAMPLES::
401
+
402
+ sage: K.<a> = GF(2^3)
403
+ sage: A = random_matrix(K, 51, 50)
404
+ sage: B = random_matrix(K, 50, 52)
405
+ sage: A*B == A._multiply_newton_john(B) # indirect doctest
406
+ True
407
+
408
+ sage: K.<a> = GF(2^5)
409
+ sage: A = random_matrix(K, 10, 50)
410
+ sage: B = random_matrix(K, 50, 12)
411
+ sage: A*B == A._multiply_newton_john(B)
412
+ True
413
+
414
+ sage: K.<a> = GF(2^7)
415
+ sage: A = random_matrix(K,100, 50)
416
+ sage: B = random_matrix(K, 50, 17)
417
+ sage: A*B == A._multiply_classical(B)
418
+ True
419
+ """
420
+ if self._ncols != right._nrows:
421
+ raise ArithmeticError("left ncols must match right nrows")
422
+
423
+ cdef Matrix_gf2e_dense ans
424
+
425
+ ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols())
426
+ if self._nrows == 0 or self._ncols == 0 or right._ncols == 0:
427
+ return ans
428
+ sig_on()
429
+ ans._entries = mzed_mul(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries)
430
+ sig_off()
431
+ return ans
432
+
433
+ cpdef Matrix_gf2e_dense _multiply_newton_john(Matrix_gf2e_dense self, Matrix_gf2e_dense right):
434
+ """
435
+ Return A*B using Newton-John tables.
436
+
437
+ We can write classical cubic multiplication (``C=A*B``) as::
438
+
439
+ for i in range(A.ncols()):
440
+ for j in range(A.nrows()):
441
+ C[j] += A[j,i] * B[j]
442
+
443
+ Hence, in the inner-most loop we compute multiples of ``B[j]``
444
+ by the values ``A[j,i]``. If the matrix ``A`` is big and the
445
+ finite field is small, there is a very high chance that
446
+ ``e * B[j]`` is computed more than once for any ``e`` in the finite
447
+ field. Instead, we compute all possible
448
+ multiples of ``B[j]`` and reuse this data in the inner loop.
449
+ This is what is called a "Newton-John" table in M4RIE.
450
+
451
+ INPUT:
452
+
453
+ - ``right`` -- a matrix
454
+
455
+ EXAMPLES::
456
+
457
+ sage: K.<a> = GF(2^2)
458
+ sage: A = random_matrix(K, 50, 50)
459
+ sage: B = random_matrix(K, 50, 50)
460
+ sage: A._multiply_newton_john(B) == A._multiply_classical(B) # indirect doctest
461
+ True
462
+
463
+ sage: K.<a> = GF(2^4)
464
+ sage: A = random_matrix(K, 50, 50)
465
+ sage: B = random_matrix(K, 50, 50)
466
+ sage: A._multiply_newton_john(B) == A._multiply_classical(B)
467
+ True
468
+
469
+ sage: K.<a> = GF(2^8)
470
+ sage: A = random_matrix(K, 50, 50)
471
+ sage: B = random_matrix(K, 50, 50)
472
+ sage: A._multiply_newton_john(B) == A._multiply_classical(B)
473
+ True
474
+
475
+ sage: K.<a> = GF(2^10)
476
+ sage: A = random_matrix(K, 50, 50)
477
+ sage: B = random_matrix(K, 50, 50)
478
+ sage: A._multiply_newton_john(B) == A._multiply_classical(B)
479
+ True
480
+ """
481
+ if self._ncols != right._nrows:
482
+ raise ArithmeticError("left ncols must match right nrows")
483
+
484
+ cdef Matrix_gf2e_dense ans
485
+
486
+ ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols())
487
+ if self._nrows == 0 or self._ncols == 0 or right._ncols == 0:
488
+ return ans
489
+
490
+ sig_on()
491
+ ans._entries = mzed_mul_newton_john(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries)
492
+ sig_off()
493
+ return ans
494
+
495
+ cpdef Matrix_gf2e_dense _multiply_karatsuba(Matrix_gf2e_dense self, Matrix_gf2e_dense right):
496
+ r"""
497
+ Matrix multiplication using Karatsuba over polynomials with
498
+ matrix coefficients over GF(2).
499
+
500
+ The idea behind Karatsuba multiplication for matrices over
501
+ `\GF{p^n}` is to treat these matrices as polynomials with
502
+ coefficients of matrices over `\GF{p}`. Then, Karatsuba-style
503
+ formulas can be used to perform multiplication, cf. [BB2009]_.
504
+
505
+ INPUT:
506
+
507
+ - ``right`` -- a matrix
508
+
509
+ EXAMPLES::
510
+
511
+ sage: K.<a> = GF(2^2)
512
+ sage: A = random_matrix(K, 50, 50)
513
+ sage: B = random_matrix(K, 50, 50)
514
+ sage: A._multiply_karatsuba(B) == A._multiply_classical(B) # indirect doctest
515
+ True
516
+
517
+ sage: K.<a> = GF(2^2)
518
+ sage: A = random_matrix(K, 137, 11)
519
+ sage: B = random_matrix(K, 11, 23)
520
+ sage: A._multiply_karatsuba(B) == A._multiply_classical(B)
521
+ True
522
+
523
+ sage: K.<a> = GF(2^10)
524
+ sage: A = random_matrix(K, 50, 50)
525
+ sage: B = random_matrix(K, 50, 50)
526
+ sage: A._multiply_karatsuba(B) == A._multiply_classical(B)
527
+ True
528
+ """
529
+ if self._ncols != right._nrows:
530
+ raise ArithmeticError("left ncols must match right nrows")
531
+
532
+ cdef Matrix_gf2e_dense ans
533
+
534
+ ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols())
535
+ if self._nrows == 0 or self._ncols == 0 or right._ncols == 0:
536
+ return ans
537
+
538
+ sig_on()
539
+ ans._entries = mzed_mul_karatsuba(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries)
540
+ sig_off()
541
+ return ans
542
+
543
+ cpdef Matrix_gf2e_dense _multiply_strassen(Matrix_gf2e_dense self, Matrix_gf2e_dense right, cutoff=0):
544
+ """
545
+ Winograd-Strassen matrix multiplication with Newton-John
546
+ multiplication as base case.
547
+
548
+ INPUT:
549
+
550
+ - ``right`` -- a matrix
551
+ - ``cutoff`` -- row or column dimension to switch over to
552
+ Newton-John multiplication (default: 64)
553
+
554
+ EXAMPLES::
555
+
556
+ sage: K.<a> = GF(2^2)
557
+ sage: A = random_matrix(K, 50, 50)
558
+ sage: B = random_matrix(K, 50, 50)
559
+ sage: A._multiply_strassen(B) == A._multiply_classical(B) # indirect doctest
560
+ True
561
+
562
+ sage: K.<a> = GF(2^4)
563
+ sage: A = random_matrix(K, 50, 50)
564
+ sage: B = random_matrix(K, 50, 50)
565
+ sage: A._multiply_strassen(B) == A._multiply_classical(B)
566
+ True
567
+
568
+ sage: K.<a> = GF(2^8)
569
+ sage: A = random_matrix(K, 50, 50)
570
+ sage: B = random_matrix(K, 50, 50)
571
+ sage: A._multiply_strassen(B) == A._multiply_classical(B)
572
+ True
573
+
574
+ sage: K.<a> = GF(2^10)
575
+ sage: A = random_matrix(K, 50, 50)
576
+ sage: B = random_matrix(K, 50, 50)
577
+ sage: A._multiply_strassen(B) == A._multiply_classical(B)
578
+ True
579
+ """
580
+ if self._ncols != right._nrows:
581
+ raise ArithmeticError("left ncols must match right nrows")
582
+
583
+ cdef Matrix_gf2e_dense ans
584
+
585
+ ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols())
586
+ if self._nrows == 0 or self._ncols == 0 or right._ncols == 0:
587
+ return ans
588
+
589
+ if cutoff == 0:
590
+ cutoff = _mzed_strassen_cutoff(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries)
591
+
592
+ sig_on()
593
+ ans._entries = mzed_mul_strassen(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries, cutoff)
594
+ sig_off()
595
+ return ans
596
+
597
+ cpdef _lmul_(self, Element right):
598
+ """
599
+ Return ``a*B`` for ``a`` an element of the base field.
600
+
601
+ INPUT:
602
+
603
+ - ``right`` -- an element of the base field
604
+
605
+ EXAMPLES::
606
+
607
+ sage: K.<a> = GF(4)
608
+ sage: A = random_matrix(K,10,10)
609
+ sage: B = a*A # indirect doctest
610
+ sage: all(B.list()[i] == a*A.list()[i] for i in range(100))
611
+ True
612
+ """
613
+ cdef m4ri_word a = poly_to_word(right)
614
+ cdef Matrix_gf2e_dense C = Matrix_gf2e_dense.__new__(Matrix_gf2e_dense, self._parent, 0, 0, 0)
615
+ mzed_mul_scalar(C._entries, a, self._entries)
616
+ return C
617
+
618
+ def __neg__(self):
619
+ """
620
+ EXAMPLES::
621
+
622
+ sage: K.<a> = GF(2^4)
623
+ sage: A = random_matrix(K, 3, 4)
624
+ sage: B = -A
625
+ sage: all(B.list()[i] == -A.list()[i] for i in range(12))
626
+ True
627
+ """
628
+ return self.__copy__()
629
+
630
+ cpdef _richcmp_(self, right, int op):
631
+ """
632
+ EXAMPLES::
633
+
634
+ sage: K.<a> = GF(2^4)
635
+ sage: A = random_matrix(K,3,4)
636
+ sage: A[0,0] = 0
637
+ sage: B = copy(A)
638
+ sage: A == B
639
+ True
640
+ sage: A[0,0] = a
641
+ sage: A == B
642
+ False
643
+ """
644
+ if self._nrows == 0 or self._ncols == 0:
645
+ return rich_to_bool(op, 0)
646
+ return rich_to_bool(op, mzed_cmp(self._entries,
647
+ (<Matrix_gf2e_dense>right)._entries))
648
+
649
+ def __copy__(self):
650
+ """
651
+ EXAMPLES::
652
+
653
+ sage: K.<a> = GF(2^4)
654
+ sage: m,n = 3, 4
655
+ sage: A = random_matrix(K,3,4)
656
+ sage: A2 = copy(A)
657
+ sage: A2.list() == A.list()
658
+ True
659
+
660
+ sage: A[0,0] = 1 if A[0,0] != 1 else 0
661
+ sage: A2[0,0] == A[0,0]
662
+ False
663
+ """
664
+ cdef Matrix_gf2e_dense A
665
+ A = Matrix_gf2e_dense.__new__(Matrix_gf2e_dense, self._parent, 0, 0, 0)
666
+
667
+ if self._nrows and self._ncols:
668
+ mzed_copy(A._entries, <const_mzed_t *>self._entries)
669
+
670
+ return A
671
+
672
+ def __bool__(self):
673
+ """
674
+ Return if ``self`` is a zero matrix or not.
675
+
676
+ EXAMPLES::
677
+
678
+ sage: K.<a> = GF(2^4)
679
+ sage: A = Matrix(K, 2, 2, a)
680
+ sage: bool(A)
681
+ True
682
+ sage: zero = MatrixSpace(K, 3, 3).zero()
683
+ sage: bool(zero)
684
+ False
685
+ """
686
+ if self._nrows and self._ncols:
687
+ return not mzed_is_zero(self._entries)
688
+ return False
689
+
690
+ def _list(self):
691
+ """
692
+ EXAMPLES::
693
+
694
+ sage: K.<a> = GF(2^4)
695
+ sage: l = [K.random_element() for _ in range(3*4)]
696
+ sage: A = Matrix(K, 3, 4, l)
697
+ sage: A.list() == l # indirect doctest
698
+ True
699
+ """
700
+ cdef Py_ssize_t i,j
701
+ l = []
702
+ for i from 0 <= i < self._nrows:
703
+ for j from 0 <= j < self._ncols:
704
+ l.append(self.get_unsafe(i,j))
705
+ return l
706
+
707
+ def randomize(self, density=1, nonzero=False, *args, **kwds):
708
+ """
709
+ Randomize ``density`` proportion of the entries of this matrix,
710
+ leaving the rest unchanged.
711
+
712
+ INPUT:
713
+
714
+ - ``density`` -- float; proportion (roughly) to be considered for
715
+ changes
716
+ - ``nonzero`` -- boolean (default: ``False``); whether the new entries
717
+ are forced to be nonzero
718
+
719
+ OUTPUT: none, the matrix is modified in-place
720
+
721
+ EXAMPLES::
722
+
723
+ sage: K.<a> = GF(2^4)
724
+ sage: total_count = 0
725
+ sage: from collections import defaultdict
726
+ sage: dic = defaultdict(Integer)
727
+ sage: def add_samples():
728
+ ....: global dic, total_count
729
+ ....: for _ in range(100):
730
+ ....: A = Matrix(K,3,3)
731
+ ....: A.randomize()
732
+ ....: for a in A.list():
733
+ ....: dic[a] += 1
734
+ ....: total_count += 1.0
735
+ sage: add_samples()
736
+ sage: while not all(abs(dic[a]/total_count - 1/16) < 0.01 for a in dic):
737
+ ....: add_samples()
738
+
739
+ sage: def add_sample(density):
740
+ ....: global density_sum, total_count
741
+ ....: total_count += 1.0
742
+ ....: density_sum += random_matrix(K, 1000, 1000, density=density).density()
743
+
744
+ sage: density_sum = 0.0
745
+ sage: total_count = 0.0
746
+ sage: add_sample(0.1)
747
+ sage: while abs(density_sum/total_count - 0.1) > 0.001:
748
+ ....: add_sample(0.1)
749
+
750
+ sage: density_sum = 0.0
751
+ sage: total_count = 0.0
752
+ sage: add_sample(1.0)
753
+ sage: while abs(density_sum/total_count - 1.0) > 0.001:
754
+ ....: add_sample(1.0)
755
+
756
+ sage: density_sum = 0.0
757
+ sage: total_count = 0.0
758
+ sage: add_sample(0.5)
759
+ sage: while abs(density_sum/total_count - 0.5) > 0.001:
760
+ ....: add_sample(0.5)
761
+
762
+ Note, that the matrix is updated and not zero-ed out before
763
+ being randomized::
764
+
765
+ sage: def add_sample(density, nonzero):
766
+ ....: global density_sum, total_count
767
+ ....: total_count += 1.0
768
+ ....: A = matrix(K, 1000, 1000)
769
+ ....: A.randomize(nonzero=nonzero, density=density)
770
+ ....: A.randomize(nonzero=nonzero, density=density)
771
+ ....: density_sum += A.density()
772
+
773
+ sage: density_sum = 0.0
774
+ sage: total_count = 0.0
775
+ sage: add_sample(0.1, True)
776
+ sage: while abs(density_sum/total_count - (1 - 0.9^2)) > 0.001:
777
+ ....: add_sample(0.1, True)
778
+
779
+ sage: density_sum = 0.0
780
+ sage: total_count = 0.0
781
+ sage: add_sample(0.1, False)
782
+ sage: while abs(density_sum/total_count - (1 - 0.9^2)*15/16) > 0.001:
783
+ ....: add_sample(0.1, False)
784
+
785
+ sage: density_sum = 0.0
786
+ sage: total_count = 0.0
787
+ sage: add_sample(0.05, True)
788
+ sage: while abs(density_sum/total_count - (1 - 0.95^2)) > 0.001:
789
+ ....: add_sample(0.05, True)
790
+
791
+ sage: density_sum = 0.0
792
+ sage: total_count = 0.0
793
+ sage: add_sample(0.5, True)
794
+ sage: while abs(density_sum/total_count - (1 - 0.5^2)) > 0.001:
795
+ ....: add_sample(0.5, True)
796
+ """
797
+ if self._ncols == 0 or self._nrows == 0:
798
+ return
799
+
800
+ cdef Py_ssize_t i,j
801
+ self.check_mutability()
802
+ self.clear_cache()
803
+
804
+ cdef m4ri_word mask = (1<<(self._parent.base_ring().degree())) - 1
805
+
806
+ cdef randstate rstate = current_randstate()
807
+
808
+ if self._ncols == 0 or self._nrows == 0:
809
+ return
810
+
811
+ cdef float _density = density
812
+ if _density <= 0:
813
+ return
814
+ if _density > 1:
815
+ _density = 1.0
816
+
817
+ if _density == 1:
818
+ if not nonzero:
819
+ sig_on()
820
+ for i in range(self._nrows):
821
+ for j in range(self._ncols):
822
+ tmp = rstate.c_random() & mask
823
+ mzed_write_elem(self._entries, i, j, tmp)
824
+ sig_off()
825
+ else:
826
+ sig_on()
827
+ for i in range(self._nrows):
828
+ for j in range(self._ncols):
829
+ tmp = rstate.c_random() & mask
830
+ while tmp == 0:
831
+ tmp = rstate.c_random() & mask
832
+ mzed_write_elem(self._entries, i, j, tmp)
833
+ sig_off()
834
+ else:
835
+ if not nonzero:
836
+ sig_on()
837
+ for i in range(self._nrows):
838
+ for j in range(self._ncols):
839
+ if rstate.c_rand_double() <= _density:
840
+ tmp = rstate.c_random() & mask
841
+ mzed_write_elem(self._entries, i, j, tmp)
842
+ sig_off()
843
+ else:
844
+ sig_on()
845
+ for i in range(self._nrows):
846
+ for j in range(self._ncols):
847
+ if rstate.c_rand_double() <= _density:
848
+ tmp = rstate.c_random() & mask
849
+ while tmp == 0:
850
+ tmp = rstate.c_random() & mask
851
+ mzed_write_elem(self._entries, i, j, tmp)
852
+ sig_off()
853
+
854
+ def echelonize(self, algorithm='heuristic', reduced=True, **kwds):
855
+ """
856
+ Compute the row echelon form of ``self`` in place.
857
+
858
+ INPUT:
859
+
860
+ - ``algorithm`` -- one of the following
861
+ - ``heuristic`` -- let M4RIE decide (default)
862
+ - ``newton_john`` -- use newton_john table based algorithm
863
+ - ``ple`` -- use PLE decomposition
864
+ - ``naive`` -- use naive cubic Gaussian elimination (M4RIE implementation)
865
+ - ``builtin`` -- use naive cubic Gaussian elimination (Sage implementation)
866
+ - ``reduced`` -- if ``True`` return reduced echelon form. No
867
+ guarantee is given that the matrix is *not* reduced if
868
+ ``False`` (default: ``True``)
869
+
870
+ EXAMPLES::
871
+
872
+ sage: K.<a> = GF(2^4)
873
+ sage: m,n = 3, 5
874
+ sage: A = random_matrix(K, 3, 5)
875
+ sage: R = A.row_space()
876
+ sage: A.echelonize()
877
+ sage: all(r[r.nonzero_positions()[0]] == 1 for r in A.rows() if r)
878
+ True
879
+ sage: A.row_space() == R
880
+ True
881
+
882
+ sage: K.<a> = GF(2^3)
883
+ sage: m,n = 3, 5
884
+ sage: MS = MatrixSpace(K,m,n)
885
+ sage: A = random_matrix(K, 3, 5)
886
+ sage: B = copy(A).echelon_form('newton_john')
887
+ sage: C = copy(A).echelon_form('naive')
888
+ sage: D = copy(A).echelon_form('builtin')
889
+ sage: B == C == D
890
+ True
891
+ sage: all(r[r.nonzero_positions()[0]] == 1 for r in B.rows() if r)
892
+ True
893
+ """
894
+ if self._nrows == 0 or self._ncols == 0:
895
+ self.cache('in_echelon_form',True)
896
+ self.cache('rank', 0)
897
+ self.cache('pivots', [])
898
+ return self
899
+
900
+ cdef int full
901
+
902
+ full = int(reduced)
903
+
904
+ x = self.fetch('in_echelon_form')
905
+ if x is not None:
906
+ return # already known to be in echelon form
907
+
908
+ self.check_mutability()
909
+ self.clear_cache()
910
+
911
+ if algorithm == 'naive':
912
+ sig_on()
913
+ r = mzed_echelonize_naive(self._entries, full)
914
+ sig_off()
915
+
916
+ elif algorithm == 'newton_john':
917
+ sig_on()
918
+ r = mzed_echelonize_newton_john(self._entries, full)
919
+ sig_off()
920
+
921
+ elif algorithm == 'ple':
922
+ sig_on()
923
+ r = mzed_echelonize_ple(self._entries, full)
924
+ sig_off()
925
+
926
+ elif algorithm == 'heuristic':
927
+ sig_on()
928
+ r = mzed_echelonize(self._entries, full)
929
+ sig_off()
930
+
931
+ elif algorithm == 'builtin':
932
+ self._echelon_in_place(algorithm='classical')
933
+
934
+ else:
935
+ raise ValueError("No algorithm '%s'." % algorithm)
936
+
937
+ self.cache('in_echelon_form',True)
938
+ self.cache('rank', r)
939
+ self.cache('pivots', self._pivots())
940
+
941
+ def _pivots(self):
942
+ """
943
+ EXAMPLES::
944
+
945
+ sage: K.<a> = GF(2^8)
946
+ sage: A = random_matrix(K, 15, 15)
947
+ sage: while A.rank() != 15:
948
+ ....: A = random_matrix(K, 15, 15)
949
+ sage: A.pivots() # indirect doctest
950
+ (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
951
+ """
952
+ if not self.fetch('in_echelon_form'):
953
+ raise ValueError("self must be in reduced row echelon form first.")
954
+ pivots = []
955
+ cdef Py_ssize_t i, j, nc
956
+ nc = self._ncols
957
+ i = 0
958
+ while i < self._nrows:
959
+ for j from i <= j < nc:
960
+ if not self.get_is_zero_unsafe(i,j):
961
+ pivots.append(j)
962
+ i += 1
963
+ break
964
+ if j == nc:
965
+ break
966
+ return pivots
967
+
968
+ def __invert__(self):
969
+ """
970
+ EXAMPLES::
971
+
972
+ sage: K.<a> = GF(2^3)
973
+ sage: A = random_matrix(K, 3, 3)
974
+ sage: while A.rank() != 3:
975
+ ....: A = random_matrix(K, 3, 3)
976
+ sage: B = ~A
977
+ sage: A*B
978
+ [1 0 0]
979
+ [0 1 0]
980
+ [0 0 1]
981
+ """
982
+ cdef Matrix_gf2e_dense A
983
+ A = Matrix_gf2e_dense.__new__(Matrix_gf2e_dense, self._parent, 0, 0, 0)
984
+
985
+ if self.rank() != self._nrows:
986
+ raise ZeroDivisionError("Matrix does not have full rank.")
987
+
988
+ if self._nrows:
989
+ sig_on()
990
+ mzed_invert_newton_john(A._entries, self._entries)
991
+ sig_off()
992
+
993
+ return A
994
+
995
+ cdef rescale_row_c(self, Py_ssize_t row, multiple, Py_ssize_t start_col):
996
+ """
997
+ Return ``multiple * self[row][start_col:]``.
998
+
999
+ INPUT:
1000
+
1001
+ - ``row`` -- row index for row to rescale
1002
+ - ``multiple`` -- finite field element to scale by
1003
+ - ``start_col`` -- only start at this column index
1004
+
1005
+ EXAMPLES::
1006
+
1007
+ sage: K.<a> = GF(2^3)
1008
+ sage: A = random_matrix(K,3,3)
1009
+ sage: B = copy(A)
1010
+ sage: B.rescale_row(0, a, 0)
1011
+ sage: B[0] == a*A[0]
1012
+ True
1013
+ sage: B[1:] == A[1:]
1014
+ True
1015
+
1016
+ sage: B = copy(A)
1017
+ sage: B.rescale_row(1, 0, 0)
1018
+ sage: B[0] == A[0]
1019
+ True
1020
+ sage: B[2] == A[2]
1021
+ True
1022
+ sage: B[1].is_zero()
1023
+ True
1024
+
1025
+ sage: B = copy(A)
1026
+ sage: B.rescale_row(2, a^2, 2)
1027
+ sage: B.list()[:-1] == A.list()[:-1]
1028
+ True
1029
+ sage: B[2,2] == a^2*A[2,2]
1030
+ True
1031
+ """
1032
+ cdef m4ri_word x = poly_to_word(multiple)
1033
+ mzed_rescale_row(self._entries, row, start_col, x)
1034
+
1035
+ cdef add_multiple_of_row_c(self, Py_ssize_t row_to, Py_ssize_t row_from, multiple, Py_ssize_t start_col):
1036
+ """
1037
+ Compute ``self[row_to][start_col:] += multiple * self[row_from][start_col:]``.
1038
+
1039
+ INPUT:
1040
+
1041
+ - ``row_to`` -- row index of source
1042
+ - ``row_from`` -- row index of destination
1043
+ - ``multiple`` -- finite field element
1044
+ - ``start_col`` -- only start at this column index
1045
+
1046
+ EXAMPLES::
1047
+
1048
+ sage: K.<a> = GF(2^3)
1049
+ sage: A = random_matrix(K,3,3)
1050
+ sage: B = copy(A)
1051
+ sage: B.add_multiple_of_row(0,1,a,0)
1052
+ sage: B[1:] == A[1:]
1053
+ True
1054
+ sage: B[0] == A[0] + a*A[1]
1055
+ True
1056
+
1057
+ sage: B = copy(A)
1058
+ sage: B.add_multiple_of_row(2,1,a,2)
1059
+ sage: B.list()[:-1] == A.list()[:-1]
1060
+ True
1061
+ sage: B[2,2] == A[2,2] + a*A[1,2]
1062
+ True
1063
+ """
1064
+
1065
+ cdef m4ri_word x = poly_to_word(multiple)
1066
+ mzed_add_multiple_of_row(self._entries, row_to, self._entries, row_from, x, start_col)
1067
+
1068
+ cdef swap_rows_c(self, Py_ssize_t row1, Py_ssize_t row2):
1069
+ """
1070
+ Swap rows ``row1`` and ``row2``.
1071
+
1072
+ INPUT:
1073
+
1074
+ - ``row1`` -- row index
1075
+ - ``row2`` -- row index
1076
+
1077
+ EXAMPLES::
1078
+
1079
+ sage: K.<a> = GF(2^3)
1080
+ sage: A = random_matrix(K,3,3)
1081
+ sage: B = copy(A)
1082
+ sage: B.swap_rows(0,1)
1083
+ sage: B[0] == A[1]
1084
+ True
1085
+ sage: B[1] == A[0]
1086
+ True
1087
+ sage: B[2] == A[2]
1088
+ True
1089
+ """
1090
+ mzed_row_swap(self._entries, row1, row2)
1091
+
1092
+ cdef swap_columns_c(self, Py_ssize_t col1, Py_ssize_t col2):
1093
+ """
1094
+ Swap columns ``col1`` and ``col2``.
1095
+
1096
+ INPUT:
1097
+
1098
+ - ``col1`` -- column index
1099
+ - ``col2`` -- column index
1100
+
1101
+ EXAMPLES::
1102
+
1103
+ sage: K.<a> = GF(2^3)
1104
+ sage: A = random_matrix(K,3,3)
1105
+ sage: B = copy(A)
1106
+ sage: B.swap_columns(0,1)
1107
+ sage: B.column(0) == A.column(1)
1108
+ True
1109
+ sage: B.column(1) == A.column(0)
1110
+ True
1111
+ sage: B.column(2) == A.column(2)
1112
+ True
1113
+
1114
+ sage: A = random_matrix(K,4,16)
1115
+ sage: B = copy(A)
1116
+ sage: B.swap_columns(0,1)
1117
+ sage: B.swap_columns(0,1)
1118
+ sage: A == B
1119
+ True
1120
+
1121
+ sage: A.swap_columns(0,15)
1122
+ sage: A.column(0) == B.column(15)
1123
+ True
1124
+ sage: A.swap_columns(14,15)
1125
+ sage: A.column(14) == B.column(0)
1126
+ True
1127
+ """
1128
+ mzed_col_swap(self._entries, col1, col2)
1129
+
1130
+ def augment(self, right):
1131
+ """
1132
+ Augments ``self`` with ``right``.
1133
+
1134
+ INPUT:
1135
+
1136
+ - ``right`` -- a matrix
1137
+
1138
+ EXAMPLES::
1139
+
1140
+ sage: K.<a> = GF(2^4)
1141
+ sage: MS = MatrixSpace(K,3,3)
1142
+ sage: A = random_matrix(K,3,3)
1143
+ sage: B = A.augment(MS(1))
1144
+ sage: B.echelonize()
1145
+ sage: C = B.matrix_from_columns([3,4,5])
1146
+ sage: A.rank() < 3 or C == ~A
1147
+ True
1148
+ sage: A.rank() < 3 or C*A == MS(1)
1149
+ True
1150
+
1151
+ TESTS::
1152
+
1153
+ sage: K.<a> = GF(2^4)
1154
+ sage: A = random_matrix(K,2,3)
1155
+ sage: B = random_matrix(K,2,0)
1156
+ sage: A.augment(B) == A
1157
+ True
1158
+
1159
+ sage: B.augment(A) == A
1160
+ True
1161
+
1162
+ sage: M = Matrix(K, 0, 0, 0)
1163
+ sage: N = Matrix(K, 0, 19, 0)
1164
+ sage: W = M.augment(N)
1165
+ sage: W.ncols()
1166
+ 19
1167
+
1168
+ sage: M = Matrix(K, 0, 1, 0)
1169
+ sage: N = Matrix(K, 0, 1, 0)
1170
+ sage: M.augment(N)
1171
+ []
1172
+
1173
+ sage: A = matrix(K, 3, range(12))
1174
+ sage: B = vector(QQ, [2,5/7,1.2]) # see issue: 38448
1175
+ sage: A.augment(B).ncols()
1176
+ 5
1177
+
1178
+ sage: B = vector([])
1179
+ sage: A.augment(B) == A
1180
+ True
1181
+ """
1182
+ cdef Matrix_gf2e_dense _right
1183
+ cdef Matrix_gf2e_dense A
1184
+
1185
+ if not isinstance(right, Matrix_gf2e_dense):
1186
+ # See issue: #36761 - Allow Vectors to be augmented
1187
+ if hasattr(right, '_vector_'):
1188
+ rsize = len(right)
1189
+ if rsize==0:
1190
+ return self.__copy__()
1191
+ if self._nrows != rsize:
1192
+ raise TypeError("Both numbers of rows must match.")
1193
+ if self.base_ring() is not right.base_ring():
1194
+ right = right.change_ring(self.base_ring())
1195
+ from sage.matrix.matrix_space import MatrixSpace
1196
+ M = MatrixSpace(self.base_ring(), nrows=rsize, ncols=1)
1197
+ _right = <Matrix_gf2e_dense>(M(right))
1198
+ else:
1199
+ raise TypeError("a matrix must be augmented with another matrix, "
1200
+ "or a vector")
1201
+ else:
1202
+ _right = <Matrix_gf2e_dense>right
1203
+
1204
+ if self._nrows != _right._nrows:
1205
+ raise TypeError("Both numbers of rows must match.")
1206
+
1207
+ if self._ncols == 0:
1208
+ return _right.__copy__()
1209
+ if _right._ncols == 0:
1210
+ return self.__copy__()
1211
+
1212
+ A = self.new_matrix(ncols = self._ncols + _right._ncols)
1213
+ if self._nrows == 0:
1214
+ return A
1215
+ A._entries = mzed_concat(A._entries, self._entries, _right._entries)
1216
+ return A
1217
+
1218
+ cdef _stack_impl(self, bottom):
1219
+ r"""
1220
+ Stack ``self`` on top of ``bottom``.
1221
+
1222
+ INPUT:
1223
+
1224
+ - ``bottom`` -- a matrix with the same number of columns as ``self``
1225
+
1226
+ EXAMPLES::
1227
+
1228
+ sage: K.<a> = GF(2^4)
1229
+ sage: A = random_matrix(K,2,2)
1230
+ sage: B = random_matrix(K,2,2)
1231
+ sage: C = A.stack(B)
1232
+ sage: C[:2] == A
1233
+ True
1234
+ sage: C[2:] == B
1235
+ True
1236
+ sage: D = B.stack(A)
1237
+ sage: D[:2] == B
1238
+ True
1239
+ sage: D[2:] == A
1240
+ True
1241
+
1242
+ TESTS::
1243
+
1244
+ sage: A = random_matrix(K,0,3)
1245
+ sage: B = random_matrix(K,3,3)
1246
+ sage: A.stack(B) == B
1247
+ True
1248
+ sage: B.stack(A) == B
1249
+ True
1250
+
1251
+ sage: M = Matrix(K, 0, 0, 0)
1252
+ sage: N = Matrix(K, 19, 0, 0)
1253
+ sage: W = M.stack(N)
1254
+ sage: W.nrows()
1255
+ 19
1256
+ sage: M = Matrix(K, 1, 0, 0)
1257
+ sage: N = Matrix(K, 1, 0, 0)
1258
+ sage: M.stack(N)
1259
+ []
1260
+
1261
+ Check that we can stack a vector (:issue:`31708`)::
1262
+
1263
+ sage: R.<a> = GF(2^3)
1264
+ sage: M = matrix(R, [[1,1],[0,a+1]])
1265
+ sage: M.stack(vector(R, [a,0]))
1266
+ [ 1 1]
1267
+ [ 0 a + 1]
1268
+ [ a 0]
1269
+ """
1270
+ cdef Matrix_gf2e_dense other = <Matrix_gf2e_dense> bottom
1271
+
1272
+ if self._nrows == 0:
1273
+ return other.__copy__()
1274
+ if other._nrows == 0:
1275
+ return self.__copy__()
1276
+
1277
+ cdef Matrix_gf2e_dense A
1278
+ A = self.new_matrix(nrows=self._nrows + other._nrows)
1279
+ if self._ncols == 0:
1280
+ return A
1281
+ A._entries = mzed_stack(A._entries, self._entries, other._entries)
1282
+ return A
1283
+
1284
+ def submatrix(self, Py_ssize_t row=0, Py_ssize_t col=0,
1285
+ Py_ssize_t nrows=-1, Py_ssize_t ncols=-1):
1286
+ """
1287
+ Return submatrix from the index ``row,col`` (inclusive) with
1288
+ dimension ``nrows x ncols``.
1289
+
1290
+ INPUT:
1291
+
1292
+ - ``row`` -- index of start row
1293
+ - ``col`` -- index of start column
1294
+ - ``nrows`` -- number of rows of submatrix
1295
+ - ``ncols`` -- number of columns of submatrix
1296
+
1297
+ EXAMPLES::
1298
+
1299
+ sage: K.<a> = GF(2^10)
1300
+ sage: A = random_matrix(K,200,200)
1301
+ sage: A[0:2,0:2] == A.submatrix(0,0,2,2)
1302
+ True
1303
+ sage: A[0:100,0:100] == A.submatrix(0,0,100,100)
1304
+ True
1305
+ sage: A == A.submatrix(0,0,200,200)
1306
+ True
1307
+
1308
+ sage: A[1:3,1:3] == A.submatrix(1,1,2,2)
1309
+ True
1310
+ sage: A[1:100,1:100] == A.submatrix(1,1,99,99)
1311
+ True
1312
+ sage: A[1:200,1:200] == A.submatrix(1,1,199,199)
1313
+ True
1314
+
1315
+ TESTS for handling of default arguments (:issue:`18761`)::
1316
+
1317
+ sage: A.submatrix(17,15) == A.submatrix(17,15,183,185)
1318
+ True
1319
+ sage: A.submatrix(row=100,col=37,nrows=1,ncols=3) == A.submatrix(100,37,1,3)
1320
+ True
1321
+ """
1322
+ if nrows < 0:
1323
+ nrows = self._nrows - row
1324
+
1325
+ if ncols < 0:
1326
+ ncols = self._ncols - col
1327
+
1328
+ cdef int highr = row + nrows
1329
+ cdef int highc = col + ncols
1330
+
1331
+ if row < 0:
1332
+ raise TypeError("Expected row >= 0, but got %d instead." % row)
1333
+
1334
+ if col < 0:
1335
+ raise TypeError("Expected col >= 0, but got %d instead." % col)
1336
+
1337
+ if highc > self._entries.ncols:
1338
+ raise TypeError("Expected highc <= self.ncols(), but got %d > %d instead." % (highc, self._entries.ncols))
1339
+
1340
+ if highr > self._entries.nrows:
1341
+ raise TypeError("Expected highr <= self.nrows(), but got %d > %d instead." % (highr, self._entries.nrows))
1342
+
1343
+ cdef Matrix_gf2e_dense A = self.new_matrix(nrows=nrows, ncols=ncols)
1344
+ if ncols == 0 or nrows == 0:
1345
+ return A
1346
+ A._entries = mzed_submatrix(A._entries, self._entries, row, col, highr, highc)
1347
+ return A
1348
+
1349
+ def rank(self):
1350
+ """
1351
+ Return the rank of this matrix (cached).
1352
+
1353
+ EXAMPLES::
1354
+
1355
+ sage: K.<a> = GF(2^4)
1356
+ sage: A = random_matrix(K, 10, 10, algorithm='unimodular')
1357
+ sage: A.rank()
1358
+ 10
1359
+ sage: A = matrix(K, 10, 0)
1360
+ sage: A.rank()
1361
+ 0
1362
+ """
1363
+ x = self.fetch('rank')
1364
+ if x is not None:
1365
+ return x
1366
+ if self._nrows == 0 or self._ncols == 0:
1367
+ return 0
1368
+ cdef mzed_t *A = mzed_copy(NULL, self._entries)
1369
+
1370
+ cdef size_t r = mzed_echelonize(A, 0)
1371
+ mzed_free(A)
1372
+ self.cache('rank', r)
1373
+ return r
1374
+
1375
+ def __reduce__(self):
1376
+ """
1377
+ EXAMPLES::
1378
+
1379
+ sage: K.<a> = GF(2^8)
1380
+ sage: A = random_matrix(K,70,70)
1381
+ sage: f, s= A.__reduce__()
1382
+ sage: from sage.matrix.matrix_gf2e_dense import unpickle_matrix_gf2e_dense_v0
1383
+ sage: f == unpickle_matrix_gf2e_dense_v0
1384
+ True
1385
+ sage: f(*s) == A
1386
+ True
1387
+
1388
+ See :issue:`21669`::
1389
+
1390
+ sage: all(f(*s) == B
1391
+ ....: for r,c in [(0,0),(0,1),(1,0)]
1392
+ ....: for B in [Matrix(GF(4, 'a'), r,c)]
1393
+ ....: for f,s in [B.__reduce__()])
1394
+ True
1395
+ """
1396
+ from sage.matrix.matrix_space import MatrixSpace
1397
+
1398
+ cdef Matrix_mod2_dense A
1399
+ cdef int r,c
1400
+
1401
+ r, c = self.nrows(), self.ncols()
1402
+ if r == 0 or c == 0:
1403
+ return unpickle_matrix_gf2e_dense_v0, (None, self.base_ring(), r, c)
1404
+ MS = MatrixSpace(GF(2), self._entries.x.nrows, self._entries.x.ncols)
1405
+ A = Matrix_mod2_dense.__new__(Matrix_mod2_dense, MS, 0, 0, 0, alloc = False)
1406
+ A._entries = mzd_copy( NULL, self._entries.x)
1407
+ return unpickle_matrix_gf2e_dense_v0, (A, self.base_ring(), self.nrows(), self.ncols())
1408
+
1409
+ def slice(self):
1410
+ r"""
1411
+ Unpack this matrix into matrices over `\GF{2}`.
1412
+
1413
+ Elements in `\GF{2^e}` can be represented as `\sum c_i a^i`
1414
+ where `a` is a root the minimal polynomial. This function
1415
+ returns a tuple of matrices `C` whose entry `C_i[x,y]` is the
1416
+ coefficient of `c_i` in `A[x,y]` if this matrix is `A`.
1417
+
1418
+ EXAMPLES::
1419
+
1420
+ sage: K.<a> = GF(2^2)
1421
+ sage: A = random_matrix(K, 5, 5)
1422
+ sage: A0, A1 = A.slice()
1423
+ sage: all(A.list()[i] == A0.list()[i] + a*A1.list()[i] for i in range(25))
1424
+ True
1425
+
1426
+ sage: K.<a> = GF(2^3)
1427
+ sage: A = random_matrix(K, 5, 5)
1428
+ sage: A0, A1, A2 = A.slice()
1429
+ sage: all(A.list()[i] == A0.list()[i] + a*A1.list()[i] + a^2*A2.list()[i] for i in range(25))
1430
+ True
1431
+
1432
+ Slicing and clinging are inverse operations::
1433
+
1434
+ sage: B = matrix(K, 5, 5)
1435
+ sage: B.cling(A0, A1, A2)
1436
+ sage: B == A
1437
+ True
1438
+ """
1439
+ if self._entries.finite_field.degree > 4:
1440
+ raise NotImplementedError("Slicing is only implemented for degree <= 4.")
1441
+
1442
+ from sage.matrix.matrix_space import MatrixSpace
1443
+
1444
+ MS = MatrixSpace(GF(2), self._nrows, self._ncols)
1445
+ cdef mzd_slice_t *a = mzed_slice(NULL, self._entries)
1446
+
1447
+ cdef Matrix_mod2_dense A0, A1, A2, A3
1448
+ A0 = Matrix_mod2_dense.__new__(Matrix_mod2_dense, MS, 0, 0, 0, alloc = True)
1449
+ A1 = Matrix_mod2_dense.__new__(Matrix_mod2_dense, MS, 0, 0, 0, alloc = True)
1450
+ mzd_copy(A0._entries, a.x[0])
1451
+ mzd_copy(A1._entries, a.x[1])
1452
+ if self._entries.finite_field.degree > 2:
1453
+ A2 = Matrix_mod2_dense.__new__(Matrix_mod2_dense, MS, 0, 0, 0, alloc = True)
1454
+ mzd_copy(A2._entries, a.x[2])
1455
+ if self._entries.finite_field.degree > 3:
1456
+ A3 = Matrix_mod2_dense.__new__(Matrix_mod2_dense, MS, 0, 0, 0, alloc = True)
1457
+ mzd_copy(A3._entries, a.x[3])
1458
+
1459
+ mzd_slice_free(a)
1460
+ if self._entries.finite_field.degree == 2:
1461
+ return A0,A1
1462
+ elif self._entries.finite_field.degree == 3:
1463
+ return A0,A1,A2
1464
+ elif self._entries.finite_field.degree == 4:
1465
+ return A0,A1,A2,A3
1466
+
1467
+ def cling(self, *C):
1468
+ r"""
1469
+ Pack the matrices over `\GF{2}` into this matrix over `\GF{2^e}`.
1470
+
1471
+ Elements in `\GF{2^e}` can be represented as `\sum c_i a^i` where
1472
+ `a` is a root the minimal polynomial. If this matrix is `A`
1473
+ then this function writes `c_i a^i` to the entry `A[x,y]`
1474
+ where `c_i` is the entry `C_i[x,y]`.
1475
+
1476
+ INPUT:
1477
+
1478
+ - ``C`` -- list of matrices over GF(2)
1479
+
1480
+ EXAMPLES::
1481
+
1482
+ sage: K.<a> = GF(2^2)
1483
+ sage: A = matrix(K, 5, 5)
1484
+ sage: A0 = random_matrix(GF(2), 5, 5)
1485
+ sage: A1 = random_matrix(GF(2), 5, 5)
1486
+ sage: A.cling(A0, A1)
1487
+ sage: all(A.list()[i] == A0.list()[i] + a*A1.list()[i] for i in range(25))
1488
+ True
1489
+
1490
+ Slicing and clinging are inverse operations::
1491
+
1492
+ sage: B0, B1 = A.slice()
1493
+ sage: B0 == A0 and B1 == A1
1494
+ True
1495
+
1496
+ TESTS::
1497
+
1498
+ sage: K.<a> = GF(2^2)
1499
+ sage: A = matrix(K, 5, 5)
1500
+ sage: A0 = random_matrix(GF(2), 5, 5)
1501
+ sage: A1 = random_matrix(GF(2), 5, 5)
1502
+ sage: A.cling(A0, A1)
1503
+ sage: B = copy(A)
1504
+ sage: A.cling(A0, A1)
1505
+ sage: A == B
1506
+ True
1507
+
1508
+ sage: A.cling(A0)
1509
+ Traceback (most recent call last):
1510
+ ...
1511
+ ValueError: The number of input matrices must be equal to the degree of the base field.
1512
+
1513
+ sage: K.<a> = GF(2^5)
1514
+ sage: A = matrix(K, 5, 5)
1515
+ sage: A0 = random_matrix(GF(2), 5, 5)
1516
+ sage: A1 = random_matrix(GF(2), 5, 5)
1517
+ sage: A2 = random_matrix(GF(2), 5, 5)
1518
+ sage: A3 = random_matrix(GF(2), 5, 5)
1519
+ sage: A4 = random_matrix(GF(2), 5, 5)
1520
+ sage: A.cling(A0, A1, A2, A3, A4)
1521
+ Traceback (most recent call last):
1522
+ ...
1523
+ NotImplementedError: Cling is only implemented for degree <= 4.
1524
+ """
1525
+ cdef Py_ssize_t i
1526
+
1527
+ if self._entries.finite_field.degree > 4:
1528
+ raise NotImplementedError("Cling is only implemented for degree <= 4.")
1529
+
1530
+ if self._is_immutable:
1531
+ raise TypeError("Immutable matrices cannot be modified.")
1532
+
1533
+ if len(C) != self._entries.finite_field.degree:
1534
+ raise ValueError("The number of input matrices must be equal to the degree of the base field.")
1535
+
1536
+ cdef mzd_slice_t *v = mzd_slice_init(self._entries.finite_field, self._nrows, self._ncols)
1537
+ for i in range(self._entries.finite_field.degree):
1538
+ if not isinstance(C[i], Matrix_mod2_dense):
1539
+ mzd_slice_free(v)
1540
+ raise TypeError("All input matrices must be over GF(2).")
1541
+ mzd_copy(v.x[i], (<Matrix_mod2_dense>C[i])._entries)
1542
+ mzed_set_ui(self._entries, 0)
1543
+ mzed_cling(self._entries, v)
1544
+ mzd_slice_free(v)
1545
+
1546
+
1547
+ def unpickle_matrix_gf2e_dense_v0(Matrix_mod2_dense a, base_ring, nrows, ncols):
1548
+ r"""
1549
+ EXAMPLES::
1550
+
1551
+ sage: K.<a> = GF(2^2)
1552
+ sage: A = random_matrix(K,10,10)
1553
+ sage: f, s= A.__reduce__()
1554
+ sage: from sage.matrix.matrix_gf2e_dense import unpickle_matrix_gf2e_dense_v0
1555
+ sage: f == unpickle_matrix_gf2e_dense_v0
1556
+ True
1557
+ sage: f(*s) == A
1558
+ True
1559
+
1560
+ We can still unpickle pickles from before :issue:`19240`::
1561
+
1562
+ sage: old_pickle = b'x\x9c\x85RKo\xd3@\x10\xae\xdd$$\xdb&\xe5U\x1e-\x8f\xc2\xc9\x12RD#$\xce\xa0\xb4\x80\x07\xa2\xca\xc2\x07\x0e\xd5\xe2:\x1b\xdb\x8acg\x1c\xa7J\x85*!\xa4\x90\xe6\x07p\xe0\xc4\x01q\xe5\xc4\x19\xf5\xd0?\xc1\x81\xdf\x80\xb8q\x0b\xb3\x8eMS\xa1\x82V;;\xb3\xdf\xce\xf7\xcd\x8e\xe6\xb5j\xf7,GT;V\x1cy\x83\xf4\xe0\x9d\xb0Y\x13\xbc)\x82\x9e`\xfd\xa0\xeb\xd9m_\xf0\xbf1\xbe{\x97\xa1\xa2\x9d\xc6\xf0\x0f\x82,\x7f\x9d\xa1\xaa\x81\n\xb9m\x9c\xd7\xf4\xf1d2\x81-h\xc0#(\x03\x83\x15\xdas\xc9*\xc3\x13x\x0cu0\xd28\x97\x9e*(0\x9f\xfa\x1b\xd0\xd2\x7fH\x82\xb5\xf4\xa2@TO\xe19\x01I\xac\x136\x991\x9f\xa4\xf9&\xcd\x07i\xbe\xcb\xd4ib\t\xba\xa4\xf6\x02zIT\xd1\x8f2(u\x15\xfd\x9d<\xee@\x05V\xd3\x94E*\xb0\x0e\x0fH\xad\xa8\xbf\x97\xa0\r\x03\xfd\xf0\xb8\x1aU\xff\x92\x90\xe8?\xa5\xd6\x814_\xa5\xf9(\xcd\xafc\xe99\xe2\xd9\xa0\x06\xd4\xf5\xcf\xf2\xf2!\xbc\xd4\xdf\x90#\xc0\x8f\r\xccM\x1b\xdd\x8b\xa3\xbe\x1d\xf7#QmYv\x1cF{\xcc\x11\x81\x88<\x9b\xa71\xcf:\xce0\xaf\x9d\x96\xe3\x87a\xbb\xdf\xe5\x8e\x1f\xeeX>\xc3\x82\xb9\xb0\xe9\x05^,6=\xe17\xf1\xcc\xd0\xc0"u\xb0d\xe6wDl\xdd\x1fa)e\x8a\xbc\xc0\xe9U\xbd \x16\x8e\x88X\xc7j\x0b\x9e\x05\xc8L\xe5\x1e%.\x98\x8a5\xc4\xc5\xd9\xf7\xdd\xd0\xdf\x0b\xc2\x8eg\xf93.wZ\xb5\xc1\x94B\xf8\xa2#\x82\x98a\xf9\xffY\x12\xe3v\x18L\xff\x14Fl\xeb\x0ff\x10\xc4\xb0\xa2\xb9y\xcd-\xba%\xcd\xa5\x8ajT\xd1\x92\xa9\x0c\x86x\xb6a\xe6h\xf8\x02<g\xaa\xaf\xf6\xdd%\x89\xae\x13z\xfe \xc6\x0b\xfb1^4p\x99\x1e6\xc6\xd4\xebK\xdbx\xf9\xc4\x8f[Iw\xf8\x89\xef\xcbQf\xcfh\xe3\x95\x8c\xebj&\xb9\xe2.\x8f\x0c\\ui\x89\xf1x\xf4\xd6\xc0kf\xc1\xf1v\xad(\xc4\xeb\x89~\xfa\xf0\x06\xa8\xa4\x7f\x93\xf4\xd7\x0c\xbcE#\xad\x92\xfc\xed\xeao\xefX\\\x03'
1563
+ sage: loads(old_pickle)
1564
+ [ 0 a]
1565
+ [a + 1 1]
1566
+ """
1567
+ from sage.matrix.matrix_space import MatrixSpace
1568
+
1569
+ MS = MatrixSpace(base_ring, nrows, ncols)
1570
+ cdef Matrix_gf2e_dense A = Matrix_gf2e_dense.__new__(Matrix_gf2e_dense, MS, 0, 0, 0)
1571
+ if nrows != 0 and ncols != 0:
1572
+ mzd_copy(A._entries.x, a._entries)
1573
+ return A