Skip to content

Commit

Permalink
gh-38152: Improve performance of computing columns of matrices over G…
Browse files Browse the repository at this point in the history
…F(2)

    
In response to issue #38150 I
have adjusted the request for columns over dense matrices over GF(2) by
replacing the standard call to columns with a transpose followed by a
request of rows.

This results in almost a 1000x speed up for large matrices (for the
example in the issue).

### Old Implementation

```py
sage: M2 = random_matrix(GF(2), 2, 2)
sage: %time _  = M2.columns()
CPU times: user 4.14 ms, sys: 1.67 ms, total: 5.81 ms
Wall time: 10.9 ms
sage: %time _  = M2.rows()
CPU times: user 109 µs, sys: 130 µs, total: 239 µs
Wall time: 1.39 ms
sage: M2 = random_matrix(GF(2), 200, 200)
sage: %time _  = M2.columns()
CPU times: user 87.9 ms, sys: 1.32 ms, total: 89.2 ms
Wall time: 88.3 ms
sage: %time _  = M2.rows()
CPU times: user 811 µs, sys: 96 µs, total: 907 µs
Wall time: 912 µs
sage: M2 = random_matrix(GF(2), 2000, 2000)
sage: %time _  = M2.columns()
CPU times: user 7.94 s, sys: 9.11 ms, total: 7.95 s
Wall time: 7.97 s
sage: %time _  = M2.rows()
CPU times: user 7.49 ms, sys: 770 µs, total: 8.26 ms
Wall time: 7.97 ms
```

### New Implementation

```py
sage: M2 = random_matrix(GF(2), 2, 2)
sage: %time _  = M2.columns()
CPU times: user 1.01 ms, sys: 261 µs, total: 1.27 ms
Wall time: 3.75 ms
sage: %time _  = M2.rows()
CPU times: user 54 µs, sys: 8 µs, total: 62 µs
Wall time: 65.1 µs
sage: M2 = random_matrix(GF(2), 200, 200)
sage: %time _  = M2.columns()
CPU times: user 1.09 ms, sys: 40 µs, total: 1.13 ms
Wall time: 1.13 ms
sage: %time _  = M2.rows()
CPU times: user 712 µs, sys: 15 µs, total: 727 µs
Wall time: 732 µs
sage: M2 = random_matrix(GF(2), 2000, 2000)
sage: %time _  = M2.columns()
CPU times: user 9.07 ms, sys: 746 µs, total: 9.82 ms
Wall time: 9.54 ms
sage: %time _  = M2.rows()
CPU times: user 7.82 ms, sys: 687 µs, total: 8.51 ms
Wall time: 8.18 ms
```

Fixes #38150
    
URL: #38152
Reported by: Giacomo Pope
Reviewer(s): grhkm21
  • Loading branch information
Release Manager committed Jun 7, 2024
2 parents 23d0e29 + 6d3a233 commit ec43912
Showing 1 changed file with 39 additions and 0 deletions.
39 changes: 39 additions & 0 deletions src/sage/matrix/matrix_mod2_dense.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,45 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse
mzd_submatrix(z._entries, self._entries, i, 0, i+1, self._ncols)
return z

def columns(self, copy=True):
"""
Return list of the columns of self.
INPUT:
- ``copy`` -- (default: ``True``) if True, return a copy so you can
modify it safely
EXAMPLES:
An example with a small 3x3 matrix::
sage: M2 = Matrix(GF(2), [[1, 0, 0], [0, 1, 0], [0, 1, 1]])
sage: M2.columns()
[(1, 0, 0), (0, 1, 1), (0, 0, 1)]
"""
x = self.fetch('columns')
if x is not None:
if copy: return list(x)
return x
cdef Py_ssize_t i

# Note: due to the way M4ri represents values, extracting rows
# is fast, but columns are slow. Therefore we transpose
# then take rows. For more information, see the issue
# https://github.com/sagemath/sage/issues/38150
C = self.transpose().rows()

# Make the vectors immutable since we are caching them
for x in C:
x.set_immutable()

# cache result
self.cache('columns', C)
if copy:
return list(C)
return C

########################################################################
# LEVEL 2 functionality
# * def _pickle
Expand Down

0 comments on commit ec43912

Please sign in to comment.