Skip to content

Add faster implementations of matrix_from_* constructors to GF(2) and GF(2^e) #40435

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/sage/matrix/matrix0.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ cdef class Matrix(sage.structure.element.Matrix):
# Unsafe entry access
cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, object x)
cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j)
cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc)
cdef _coerce_element(self, x)
cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1

Expand Down
22 changes: 22 additions & 0 deletions src/sage/matrix/matrix0.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,28 @@ cdef class Matrix(sage.structure.element.Matrix):
"""
raise NotImplementedError("this must be defined in the derived type.")

cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc):
"""
Copy element (iSrc, jSrc) from ``src`` to position (iDst, jDst) in
``self``. It is assumed ``src`` is the same type of matrix as``self``,
with the same base ring.

This should generally be reimplemented in subclasses to avoid the type
conversion that often is necessary in ``get_unsafe`` and
``set_unsafe``.

INPUT:

- ``iDst`` - the row to be copied to in ``self``.
- ``jDst`` - the column to be copied to in ``self``.
- ``src`` - the matrix to copy from. Should be the same type as
``self`` with the same base ring.
- ``iSrc`` - the row to be copied from in ``src``.
- ``jSrc`` - the column to be copied from in ``src``.
"""
cdef Matrix _src = <Matrix>src
self.set_unsafe(iDst, jDst, _src.get_unsafe(iSrc, jSrc))

cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1:
"""
Return 1 if the entry ``(i, j)`` is zero, otherwise 0.
Expand Down
6 changes: 3 additions & 3 deletions src/sage/matrix/matrix1.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2043,7 +2043,7 @@ cdef class Matrix(Matrix0):
if col < 0 or col >= self._ncols:
raise IndexError("column index out of range")
for i in range(self._nrows):
A.set_unsafe(i, j, self.get_unsafe(i, col))
A.copy_from_unsafe(i, j, self, i, col)
return A

def delete_columns(self, dcols, check=True):
Expand Down Expand Up @@ -2141,7 +2141,7 @@ cdef class Matrix(Matrix0):
if row < 0 or row >= self._nrows:
raise IndexError("row index out of range")
for j in range(self._ncols):
A.set_unsafe(i, j, self.get_unsafe(row, j))
A.copy_from_unsafe(i, j, self, row, j)
return A

def delete_rows(self, drows, check=True):
Expand Down Expand Up @@ -2268,7 +2268,7 @@ cdef class Matrix(Matrix0):
if row < 0 or row >= self._nrows:
raise IndexError("row index out of range")
for j, col in enumerate(columns):
A.set_unsafe(i, j, self.get_unsafe(row, col))
A.copy_from_unsafe(i, j, self, row, col)
return A

def submatrix(self, Py_ssize_t row=0, Py_ssize_t col=0,
Expand Down
47 changes: 47 additions & 0 deletions src/sage/matrix/matrix_complex_ball_dense.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,53 @@ cdef class Matrix_complex_ball_dense(Matrix_dense):
acb_set(z.value, acb_mat_entry(self.value, i, j))
return z

cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc):
"""
Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)``
entry of ``self``.

.. warning::

This is very unsafe; it assumes ``iSrc``, ``jSrc``, ``iDst`` and
``jDst`` are in the right range, and that ``src`` is a
Matrix_complex_ball_dense with the same base ring as ``self``.

INPUT:

- ``iDst`` - the row to be copied to in ``self``.
- ``jDst`` - the column to be copied to in ``self``.
- ``src`` - the matrix to copy from. Should be a
Matrix_complex_ball_dense with the same base ring as
``self``.
- ``iSrc`` - the row to be copied from in ``src``.
- ``jSrc`` - the column to be copied from in ``src``.

TESTS::

sage: m = MatrixSpace(CBF,3,4)(range(12))
sage: m
[ 0 1.000000000000000 2.000000000000000 3.000000000000000]
[4.000000000000000 5.000000000000000 6.000000000000000 7.000000000000000]
[8.000000000000000 9.000000000000000 10.00000000000000 11.00000000000000]
sage: m.transpose()
[ 0 4.000000000000000 8.000000000000000]
[1.000000000000000 5.000000000000000 9.000000000000000]
[2.000000000000000 6.000000000000000 10.00000000000000]
[3.000000000000000 7.000000000000000 11.00000000000000]
sage: m.matrix_from_rows([0,2])
[ 0 1.000000000000000 2.000000000000000 3.000000000000000]
[8.000000000000000 9.000000000000000 10.00000000000000 11.00000000000000]
sage: m.matrix_from_columns([1,3])
[1.000000000000000 3.000000000000000]
[5.000000000000000 7.000000000000000]
[9.000000000000000 11.00000000000000]
sage: m.matrix_from_rows_and_columns([1,2],[0,3])
[4.000000000000000 7.000000000000000]
[8.000000000000000 11.00000000000000]
"""
cdef Matrix_complex_ball_dense _src = <Matrix_complex_ball_dense> src
acb_set(acb_mat_entry(self.value, iDst, jDst), acb_mat_entry(_src.value, iSrc, jSrc))

cpdef _richcmp_(left, right, int op):
r"""
EXAMPLES::
Expand Down
47 changes: 47 additions & 0 deletions src/sage/matrix/matrix_cyclo_dense.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,53 @@ cdef class Matrix_cyclo_dense(Matrix_dense):

return x

cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc):
"""
Copy the (iSrc,jSrc)-th entry of ``src`` to the (iDst,jDst)-th entry
``self``.

WARNING: As the name suggests, expect segfaults if iSrc,jSrc,iDst,jDst
are out of bounds!! This is for internal use only. This method assumes
``src`` is a Matrix_cyclo_dense with the same base ring as ``self``.

INPUT:

- ``iDst`` - the row to be copied to in ``self``.
- ``jDst`` - the column to be copied to in ``self``.
- ``src`` - the matrix to copy from. Should be a Matrix_cyclo_dense
with the same base ring as ``self``.
- ``iSrc`` - the row to be copied from in ``src``.
- ``jSrc`` - the column to be copied from in ``src``.

TESTS::

sage: K.<z> = CyclotomicField(3)
sage: M = matrix(K,3,4,[i + z/(i+1) for i in range(12)])
sage: M
[ z 1/2*z + 1 1/3*z + 2 1/4*z + 3]
[ 1/5*z + 4 1/6*z + 5 1/7*z + 6 1/8*z + 7]
[ 1/9*z + 8 1/10*z + 9 1/11*z + 10 1/12*z + 11]
sage: M.transpose()
[ z 1/5*z + 4 1/9*z + 8]
[ 1/2*z + 1 1/6*z + 5 1/10*z + 9]
[ 1/3*z + 2 1/7*z + 6 1/11*z + 10]
[ 1/4*z + 3 1/8*z + 7 1/12*z + 11]
sage: M.matrix_from_rows([0,2])
[ z 1/2*z + 1 1/3*z + 2 1/4*z + 3]
[ 1/9*z + 8 1/10*z + 9 1/11*z + 10 1/12*z + 11]
sage: M.matrix_from_columns([1,3])
[ 1/2*z + 1 1/4*z + 3]
[ 1/6*z + 5 1/8*z + 7]
[ 1/10*z + 9 1/12*z + 11]
sage: M.matrix_from_rows_and_columns([1,2],[0,3])
[ 1/5*z + 4 1/8*z + 7]
[ 1/9*z + 8 1/12*z + 11]
"""
cdef Matrix_cyclo_dense _src = src
cdef int a
for a in range(self._degree):
self._matrix.copy_from_unsafe(a, jDst + iDst*self._ncols, _src._matrix, a, jSrc + iSrc*_src._ncols)

cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1:
r"""
Return 1 if the entry ``(i, j)`` is zero, otherwise 0.
Expand Down
4 changes: 2 additions & 2 deletions src/sage/matrix/matrix_dense.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ cdef class Matrix_dense(matrix.Matrix):
cdef Py_ssize_t i, j
for j from 0<= j < nc:
for i from 0<= i < nr:
trans.set_unsafe(j,i,self.get_unsafe(i,j))
trans.copy_from_unsafe(j, i, self, i, j)

if self._subdivisions is not None:
row_divs, col_divs = self.subdivisions()
Expand Down Expand Up @@ -183,7 +183,7 @@ cdef class Matrix_dense(matrix.Matrix):
rj -= 1
for i from 0 <= i < nr:
ri -= 1
atrans.set_unsafe(j, i, self.get_unsafe(ri, rj))
atrans.copy_from_unsafe(j, i, self, ri, rj)

if self._subdivisions is not None:
row_divs, col_divs = self.subdivisions()
Expand Down
40 changes: 40 additions & 0 deletions src/sage/matrix/matrix_gap.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,46 @@ cdef class Matrix_gap(Matrix_dense):
"""
self._libgap[i,j] = x

cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc):
r"""
Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)``
entry of ``self``.

INPUT:

- ``iDst`` - the row to be copied to in ``self``.
- ``jDst`` - the column to be copied to in ``self``.
- ``src`` - the matrix to copy from. Should be a Matrix_gap with the
same base ring as ``self``.
- ``iSrc`` - the row to be copied from in ``src``.
- ``jSrc`` - the column to be copied from in ``src``.

TESTS::

sage: M = MatrixSpace(ZZ, 3, 4, implementation='gap')(range(12))
sage: M
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
sage: M.transpose()
[ 0 4 8]
[ 1 5 9]
[ 2 6 10]
[ 3 7 11]
sage: M.matrix_from_rows([0,2])
[ 0 1 2 3]
[ 8 9 10 11]
sage: M.matrix_from_columns([1,3])
[ 1 3]
[ 5 7]
[ 9 11]
sage: M.matrix_from_rows_and_columns([1,2],[0,3])
[ 4 7]
[ 8 11]
"""
cdef Matrix_gap _src = <Matrix_gap>src
self._libgap[iDst,jDst] = _src._libgap[iSrc,jSrc]

cpdef _richcmp_(self, other, int op):
r"""
Compare ``self`` and ``right``.
Expand Down
41 changes: 41 additions & 0 deletions src/sage/matrix/matrix_generic_dense.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,47 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense):
cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
return self._entries[i*self._ncols + j]

cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc):
r"""
Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)``
entry of ``self``.

INPUT:

- ``iDst`` - the row to be copied to in ``self``.
- ``jDst`` - the column to be copied to in ``self``.
- ``src`` - the matrix to copy from. Should be a Matrix_generic_dense
with the same base ring as ``self``.
- ``iSrc`` - the row to be copied from in ``src``.
- ``jSrc`` - the column to be copied from in ``src``.

TESTS::

sage: K.<z> = GF(9)
sage: m = matrix(K,3,4,[((i%9)//3)*z + i%3 for i in range(12)])
sage: m
[ 0 1 2 z]
[ z + 1 z + 2 2*z 2*z + 1]
[2*z + 2 0 1 2]
sage: m.transpose()
[ 0 z + 1 2*z + 2]
[ 1 z + 2 0]
[ 2 2*z 1]
[ z 2*z + 1 2]
sage: m.matrix_from_rows([0,2])
[ 0 1 2 z]
[2*z + 2 0 1 2]
sage: m.matrix_from_columns([1,3])
[ 1 z]
[ z + 2 2*z + 1]
[ 0 2]
sage: m.matrix_from_rows_and_columns([1,2],[0,3])
[ z + 1 2*z + 1]
[2*z + 2 2]
"""
cdef Matrix_generic_dense _src = <Matrix_generic_dense>src
self._entries[iDst*self._ncols + jDst] = _src._entries[iSrc*_src._ncols + jSrc]

def _reverse_unsafe(self):
r"""
TESTS::
Expand Down
44 changes: 44 additions & 0 deletions src/sage/matrix/matrix_generic_sparse.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,50 @@ cdef class Matrix_generic_sparse(matrix_sparse.Matrix_sparse):
cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
return self._entries.get((i,j), self._zero)

cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc):
r"""
Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)``
entry of ``self``.

INPUT:

- ``iDst`` - the row to be copied to in ``self``.
- ``jDst`` - the column to be copied to in ``self``.
- ``src`` - the matrix to copy from. Should be a Matrix_generic_sparse
with the same base ring as ``self``.
- ``iSrc`` - the row to be copied from in ``src``.
- ``jSrc`` - the column to be copied from in ``src``.

TESTS::

sage: K.<z> = GF(9)
sage: m = matrix(K,3,4,[((i%9)//3)*z + i%3 if is_prime(i) else 0 for i in range(12)],sparse=True)
sage: m
[ 0 0 2 z]
[ 0 z + 2 0 2*z + 1]
[ 0 0 0 2]
sage: m.transpose()
[ 0 0 0]
[ 0 z + 2 0]
[ 2 0 0]
[ z 2*z + 1 2]
sage: m.matrix_from_rows([0,2])
[0 0 2 z]
[0 0 0 2]
sage: m.matrix_from_columns([1,3])
[ 0 z]
[ z + 2 2*z + 1]
[ 0 2]
sage: m.matrix_from_rows_and_columns([1,2],[0,3])
[ 0 2*z + 1]
[ 0 2]
"""
cdef Matrix_generic_sparse _src = <Matrix_generic_sparse>src
if (iSrc,jSrc) in _src._entries:
self._entries[(iDst,jDst)] = _src._entries.get((iSrc, jSrc), _src._zero)
elif (iDst,jDst) in self._entries:
del self._entries[(iDst,jDst)]

cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1:
"""
Return 1 if the entry ``(i, j)`` is zero, otherwise 0.
Expand Down
41 changes: 41 additions & 0 deletions src/sage/matrix/matrix_gf2e_dense.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,47 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense):
cdef Cache_base cache = <Cache_base> self._base_ring._cache
return cache.fetch_int(r)

cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc):
r"""
Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)``
entry of ``self``.

INPUT:

- ``iDst`` - the row to be copied to in ``self``.
- ``jDst`` - the column to be copied to in ``self``.
- ``src`` - the matrix to copy from. Should be a Matrix_gf2e_dense with
the same base ring as ``self``.
- ``iSrc`` - the row to be copied from in ``src``.
- ``jSrc`` - the column to be copied from in ``src``.

TESTS::

sage: K.<z> = GF(512)
sage: m = matrix(K,3,4,[sum([(i//(2^j))%2 * z^j for j in range(4)]) for i in range(12)])
sage: m
[ 0 1 z z + 1]
[ z^2 z^2 + 1 z^2 + z z^2 + z + 1]
[ z^3 z^3 + 1 z^3 + z z^3 + z + 1]
sage: m.transpose()
[ 0 z^2 z^3]
[ 1 z^2 + 1 z^3 + 1]
[ z z^2 + z z^3 + z]
[ z + 1 z^2 + z + 1 z^3 + z + 1]
sage: m.matrix_from_rows([0,2])
[ 0 1 z z + 1]
[ z^3 z^3 + 1 z^3 + z z^3 + z + 1]
sage: m.matrix_from_columns([1,3])
[ 1 z + 1]
[ z^2 + 1 z^2 + z + 1]
[ z^3 + 1 z^3 + z + 1]
sage: m.matrix_from_rows_and_columns([1,2],[0,3])
[ z^2 z^2 + z + 1]
[ z^3 z^3 + z + 1]
"""
cdef Matrix_gf2e_dense _src = <Matrix_gf2e_dense>src
mzed_write_elem(self._entries, iDst, jDst, mzed_read_elem(_src._entries, iSrc, jSrc))

cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1:
r"""
Return 1 if the entry ``(i, j)`` is zero, otherwise 0.
Expand Down
Loading
Loading