Skip to content

Commit 45e6ea4

Browse files
author
Release Manager
committed
gh-40423: Fix GF(2) matrix transpose with subdivisions <!-- ^ Please provide a concise and informative title. --> <!-- ^ Don't put issue numbers in the title, do this in the PR description below. --> <!-- ^ For example, instead of "Fixes #12345" use "Introduce new method to calculate 1 + 2". --> <!-- v Describe your changes below in detail. --> <!-- v Why is this change required? What problem does it solve? --> <!-- v If this PR resolves an open issue, please link to it here. For example, "Fixes #12345". --> ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [X] The title is concise and informative. - [X] The description explains in detail what this PR is about. - [ ] I have linked a relevant issue or discussion. - [ ] I have created tests covering the changes. - [ ] I have updated the documentation and checked the documentation preview. A small bug I noticed when looking at the code for transposing matrices. GF(2) does not properly transpose its subdivisions, meaning transposed matrices can have incorrect subdivisions or cause errors if the indices fall out of range. sage: M = matrix.random(GF(2),3,3) sage: N = matrix.block([[M,M,M]]) sage: M [1 0 0] [0 0 1] [0 1 0] sage: N [1 0 0|1 0 0|1 0 0] [0 0 1|0 0 1|0 0 1] [0 1 0|0 1 0|0 1 0] sage: N.transpose() <repr(<sage.matrix.matrix_mod2_dense.Matrix_mod2_dense at 0x7f1eb7f0c1c0>) failed: IndexError: list index out of range> This also adds subdivision handling to transposes of matrix_complex_ball_dense, matrix_gap, and fixes subdivisions for transposes of empty matrices of type matrix_mod2_dense, matrix_numpy_dense URL: #40423 Reported by: Biffo89 Reviewer(s): Xavier Caruso
2 parents 98e19c1 + 1cec240 commit 45e6ea4

File tree

4 files changed

+115
-9
lines changed

4 files changed

+115
-9
lines changed

src/sage/matrix/matrix_complex_ball_dense.pyx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,11 +558,42 @@ cdef class Matrix_complex_ball_dense(Matrix_dense):
558558
[3.000000000000000 6.000000000000000]
559559
sage: m.transpose().parent()
560560
Full MatrixSpace of 3 by 2 dense matrices over Complex ball field with 53 bits of precision
561+
562+
TESTS::
563+
564+
sage: m = matrix(CBF,2,3,range(6))
565+
sage: m.subdivide([1],[2])
566+
sage: m
567+
[ 0 1.000000000000000|2.000000000000000]
568+
[-----------------------------------+-----------------]
569+
[3.000000000000000 4.000000000000000|5.000000000000000]
570+
sage: m.transpose()
571+
[ 0|3.000000000000000]
572+
[1.000000000000000|4.000000000000000]
573+
[-----------------+-----------------]
574+
[2.000000000000000|5.000000000000000]
575+
576+
sage: m = matrix(CBF,0,2)
577+
sage: m.subdivide([],[1])
578+
sage: m.subdivisions()
579+
([], [1])
580+
sage: m.transpose().subdivisions()
581+
([1], [])
582+
583+
sage: m = matrix(CBF,2,0)
584+
sage: m.subdivide([1],[])
585+
sage: m.subdivisions()
586+
([1], [])
587+
sage: m.transpose().subdivisions()
588+
([], [1])
561589
"""
562590
cdef Py_ssize_t nc = self._ncols
563591
cdef Py_ssize_t nr = self._nrows
564592
cdef Matrix_complex_ball_dense trans = self._new(nc, nr)
565593
acb_mat_transpose(trans.value, self.value)
594+
if self._subdivisions is not None:
595+
row_divs, col_divs = self.subdivisions()
596+
trans.subdivide(col_divs, row_divs)
566597
return trans
567598

568599
def _solve_right_nonsingular_square(self, Matrix_complex_ball_dense rhs, check_rank=None):

src/sage/matrix/matrix_gap.pyx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,10 +342,44 @@ cdef class Matrix_gap(Matrix_dense):
342342
[ 4]
343343
[ 2]
344344
[52]
345+
346+
TESTS::
347+
348+
sage: M = MatrixSpace(QQ, 2, 3, implementation='gap')
349+
sage: m = M(range(6))
350+
sage: m.subdivide([1],[2])
351+
sage: m
352+
[0 1|2]
353+
[---+-]
354+
[3 4|5]
355+
sage: m.transpose()
356+
[0|3]
357+
[1|4]
358+
[-+-]
359+
[2|5]
360+
361+
sage: M = MatrixSpace(QQ, 0, 2, implementation='gap')
362+
sage: m = M([])
363+
sage: m.subdivide([],[1])
364+
sage: m.subdivisions()
365+
([], [1])
366+
sage: m.transpose().subdivisions()
367+
([1], [])
368+
369+
sage: M = MatrixSpace(QQ, 2, 0, implementation='gap')
370+
sage: m = M([])
371+
sage: m.subdivide([1],[])
372+
sage: m.subdivisions()
373+
([1], [])
374+
sage: m.transpose().subdivisions()
375+
([], [1])
345376
"""
346377
cdef Matrix_gap M
347378
M = self._new(self._ncols, self._nrows)
348379
M._libgap = self._libgap.TransposedMat()
380+
if self._subdivisions is not None:
381+
row_divs, col_divs = self.subdivisions()
382+
M.subdivide(col_divs, row_divs)
349383
return M
350384

351385
def determinant(self):

src/sage/matrix/matrix_mod2_dense.pyx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,15 +1493,29 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse
14931493
sage: A[0,0] = 0
14941494
sage: B[0,0]
14951495
1
1496+
1497+
sage: m = matrix(GF(2),0,2)
1498+
sage: m.subdivide([],[1])
1499+
sage: m.subdivisions()
1500+
([], [1])
1501+
sage: m.transpose().subdivisions()
1502+
([1], [])
1503+
1504+
sage: m = matrix(GF(2),2,0)
1505+
sage: m.subdivide([1],[])
1506+
sage: m.subdivisions()
1507+
([1], [])
1508+
sage: m.transpose().subdivisions()
1509+
([], [1])
14961510
"""
14971511
cdef Matrix_mod2_dense A = self.new_matrix(ncols=self._nrows,
14981512
nrows=self._ncols)
1499-
if self._nrows == 0 or self._ncols == 0:
1500-
return A
1513+
if self._nrows != 0 and self._ncols != 0:
1514+
A._entries = mzd_transpose(A._entries, self._entries)
15011515

1502-
A._entries = mzd_transpose(A._entries, self._entries)
15031516
if self._subdivisions is not None:
1504-
A.subdivide(*self.subdivisions())
1517+
row_divs, col_divs = self.subdivisions()
1518+
A.subdivide(col_divs, row_divs)
15051519
return A
15061520

15071521
cpdef _richcmp_(self, right, int op):

src/sage/matrix/matrix_numpy_dense.pyx

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -266,13 +266,40 @@ cdef class Matrix_numpy_dense(Matrix_dense):
266266
[]
267267
sage: m.transpose().parent()
268268
Full MatrixSpace of 3 by 0 dense matrices over Real Double Field
269+
270+
TESTS::
271+
272+
sage: m = matrix(RDF,2,3,range(6))
273+
sage: m.subdivide([1],[2])
274+
sage: m
275+
[0.0 1.0|2.0]
276+
[-------+---]
277+
[3.0 4.0|5.0]
278+
sage: m.transpose()
279+
[0.0|3.0]
280+
[1.0|4.0]
281+
[---+---]
282+
[2.0|5.0]
283+
284+
sage: m = matrix(RDF,0,2)
285+
sage: m.subdivide([],[1])
286+
sage: m.subdivisions()
287+
([], [1])
288+
sage: m.transpose().subdivisions()
289+
([1], [])
290+
291+
sage: m = matrix(RDF,2,0)
292+
sage: m.subdivide([1],[])
293+
sage: m.subdivisions()
294+
([1], [])
295+
sage: m.transpose().subdivisions()
296+
([], [1])
269297
"""
270-
if self._nrows == 0 or self._ncols == 0:
271-
return self.new_matrix(self._ncols, self._nrows)
298+
cdef Matrix_numpy_dense trans = self._new(self._ncols, self._nrows)
299+
300+
if self._nrows != 0 and self._ncols != 0:
301+
trans._matrix_numpy = self._matrix_numpy.transpose().copy()
272302

273-
cdef Matrix_numpy_dense trans
274-
trans = self._new(self._ncols, self._nrows)
275-
trans._matrix_numpy = self._matrix_numpy.transpose().copy()
276303
if self._subdivisions is not None:
277304
row_divs, col_divs = self.subdivisions()
278305
trans.subdivide(col_divs, row_divs)

0 commit comments

Comments
 (0)