From e5b8fd4bbe566bcd8f908944f9e9ffd880b16557 Mon Sep 17 00:00:00 2001 From: Nicholas Bell Date: Thu, 17 Jul 2025 23:19:58 +0200 Subject: [PATCH 1/5] add faster implementations of matrix_from_* constructors --- src/sage/matrix/matrix_gf2e_dense.pyx | 96 +++++++++++++++++++++++++++ src/sage/matrix/matrix_mod2_dense.pyx | 96 +++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) diff --git a/src/sage/matrix/matrix_gf2e_dense.pyx b/src/sage/matrix/matrix_gf2e_dense.pyx index e90ce0b71cb..17f849124c9 100644 --- a/src/sage/matrix/matrix_gf2e_dense.pyx +++ b/src/sage/matrix/matrix_gf2e_dense.pyx @@ -82,6 +82,7 @@ REFERENCES: #***************************************************************************** from cysignals.signals cimport sig_on, sig_off +from cpython.sequence cimport PySequence_Fast cimport sage.matrix.matrix_dense as matrix_dense from sage.structure.element cimport Matrix @@ -1348,6 +1349,101 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): A._entries = mzed_submatrix(A._entries, self._entries, row, col, highr, highc) return A + def matrix_from_rows(self, rows): + r""" + Return the matrix constructed from ``self`` using rows with indices in + the rows list. + + EXAMPLES:: + + sage: M = matrix(GF(4),[[0,[0,1],0],[0,[1,1],1],[1,0,1]]) + sage: M + [ 0 z2 0] + [ 0 z2 + 1 1] + [ 1 0 1] + sage: M.matrix_from_rows([2,1]) + [ 1 0 1] + [ 0 z2 + 1 1] + """ + rows = PySequence_Fast(rows, "rows is not iterable") + if any(0 > row or row >= self._nrows for row in rows): + raise TypeError("Rows are not all in range") + + cdef Py_ssize_t nrows = len(rows) + + cdef Matrix_gf2e_dense A = self.new_matrix(nrows=nrows) + + cdef Py_ssize_t i, j, row + for i, row in enumerate(rows): + for j in range(self._ncols): + mzed_write_elem(A._entries, i, j, mzed_read_elem(self._entries, row, j)) + return A + + def matrix_from_columns(self, cols): + r""" + Return the matrix constructed from ``self`` using columns with indices + in the columns list. + + EXAMPLES:: + + sage: M = matrix(GF(4),[[0,[0,1],0],[0,[1,1],1],[1,0,1]]) + sage: M + [ 0 z2 0] + [ 0 z2 + 1 1] + [ 1 0 1] + sage: M.matrix_from_columns([2,1]) + [ 0 z2] + [ 1 z2 + 1] + [ 1 0] + """ + cols = PySequence_Fast(cols, "cols is not iterable") + if any(0 > col or col >= self._ncols for col in cols): + raise TypeError("Columns are not all in range") + + cdef Py_ssize_t ncols = len(cols) + + cdef Matrix_gf2e_dense A = self.new_matrix(ncols=ncols) + + cdef Py_ssize_t i, j, col + for i in range(self._nrows): + for j, col in enumerate(cols): + mzed_write_elem(A._entries, i, j, mzed_read_elem(self._entries, i, col)) + return A + + def matrix_from_rows_and_columns(self, rows, cols): + r""" + Return the matrix constructed from ``self`` from the given rows and + columns. + + EXAMPLES:: + + sage: M = matrix(GF(4),[[0,[0,1],0],[0,[1,1],1],[1,0,1]]) + sage: M + [ 0 z2 0] + [ 0 z2 + 1 1] + [ 1 0 1] + sage: M.matrix_from_rows_and_columns([0,1],[2,1]) + [ 0 z2] + [ 1 z2 + 1] + """ + rows = PySequence_Fast(rows, "rows is not iterable") + cols = PySequence_Fast(cols, "cols is not iterable") + if any(0 > row or row >= self._nrows for row in rows): + raise TypeError("Rows are not all in range") + if any(0 > col or col >= self._ncols for col in cols): + raise TypeError("Columns are not all in range") + + cdef Py_ssize_t nrows = len(rows) + cdef Py_ssize_t ncols = len(cols) + + cdef Matrix_gf2e_dense A = self.new_matrix(nrows=nrows, ncols=ncols) + + cdef Py_ssize_t i, j, row, col + for i,row in enumerate(rows): + for j, col in enumerate(cols): + mzed_write_elem(A._entries, i, j, mzed_read_elem(self._entries, row, col)) + return A + def rank(self): """ Return the rank of this matrix (cached). diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index f3fb83827ba..219d1774729 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -106,6 +106,7 @@ TESTS:: from cysignals.memory cimport check_malloc, sig_free from cysignals.signals cimport sig_on, sig_str, sig_off +from cpython.sequence cimport PySequence_Fast cimport sage.matrix.matrix_dense as matrix_dense from sage.matrix.args cimport SparseEntry, MatrixArgs_init, MA_ENTRIES_NDARRAY @@ -1794,6 +1795,101 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse A._entries = mzd_submatrix(A._entries, self._entries, row, col, highr, highc) return A + def matrix_from_rows(self, rows): + r""" + Return the matrix constructed from ``self`` using rows with indices in + the rows list. + + EXAMPLES:: + + sage: M = matrix(GF(2),[[0,1,0],[0,1,1],[1,0,1]]) + sage: M + [0 1 0] + [0 1 1] + [1 0 1] + sage: M.matrix_from_rows([2,1]) + [1 0 1] + [0 1 1] + """ + rows = PySequence_Fast(rows, "rows is not iterable") + if any(0 > row or row >= self._nrows for row in rows): + raise TypeError("Rows are not all in range") + + cdef Py_ssize_t nrows = len(rows) + + cdef Matrix_mod2_dense A = self.new_matrix(nrows=nrows) + + cdef Py_ssize_t i, j, row + for i, row in enumerate(rows): + for j in range(self._ncols): + mzd_write_bit(A._entries, i, j, mzd_read_bit(self._entries, row, j)) + return A + + def matrix_from_columns(self, cols): + r""" + Return the matrix constructed from ``self`` using columns with indices + in the columns list. + + EXAMPLES:: + + sage: M = matrix(GF(2),[[0,1,0],[0,1,1],[1,0,1]]) + sage: M + [0 1 0] + [0 1 1] + [1 0 1] + sage: M.matrix_from_columns([2,1]) + [0 1] + [1 1] + [1 0] + """ + cols = PySequence_Fast(cols, "cols is not iterable") + if any(0 > col or col >= self._ncols for col in cols): + raise TypeError("Columns are not all in range") + + cdef Py_ssize_t ncols = len(cols) + + cdef Matrix_mod2_dense A = self.new_matrix(ncols=ncols) + + cdef Py_ssize_t i, j, col + for i in range(self._nrows): + for j, col in enumerate(cols): + mzd_write_bit(A._entries, i, j, mzd_read_bit(self._entries, i, col)) + return A + + def matrix_from_rows_and_columns(self, rows, cols): + r""" + Return the matrix constructed from ``self`` from the given rows and + columns. + + EXAMPLES:: + + sage: M = matrix(GF(2),[[0,1,0],[0,1,1],[1,0,1]]) + sage: M + [0 1 0] + [0 1 1] + [1 0 1] + sage: M.matrix_from_rows_and_columns([0,1],[2,1]) + [0 1] + [1 1] + """ + rows = PySequence_Fast(rows, "rows is not iterable") + cols = PySequence_Fast(cols, "cols is not iterable") + if any(0 > row or row >= self._nrows for row in rows): + raise TypeError("Rows are not all in range") + if any(0 > col or col >= self._ncols for col in cols): + raise TypeError("Columns are not all in range") + + cdef Py_ssize_t nrows = len(rows) + cdef Py_ssize_t ncols = len(cols) + + cdef Matrix_mod2_dense A = self.new_matrix(nrows=nrows, ncols=ncols) + + cdef Py_ssize_t i, j, row, col + for i,row in enumerate(rows): + for j, col in enumerate(cols): + mzd_write_bit(A._entries, i, j, mzd_read_bit(self._entries, row, col)) + return A + def __reduce__(self): """ Serialize ``self``. From cf86bdf92061caef48366eb84255cb8129adb958 Mon Sep 17 00:00:00 2001 From: Nicholas Bell Date: Wed, 23 Jul 2025 18:21:30 +0200 Subject: [PATCH 2/5] replace transpose and matrix_from_ copies with copy_from_unsafe --- src/sage/matrix/matrix0.pxd | 1 + src/sage/matrix/matrix0.pyx | 8 ++ src/sage/matrix/matrix1.pyx | 6 +- src/sage/matrix/matrix_complex_ball_dense.pyx | 13 +++ src/sage/matrix/matrix_cyclo_dense.pyx | 12 ++ src/sage/matrix/matrix_dense.pyx | 2 +- src/sage/matrix/matrix_gap.pyx | 4 + src/sage/matrix/matrix_generic_dense.pyx | 4 + src/sage/matrix/matrix_generic_sparse.pyx | 7 ++ src/sage/matrix/matrix_gf2e_dense.pyx | 110 +++--------------- src/sage/matrix/matrix_gfpn_dense.pyx | 7 ++ src/sage/matrix/matrix_integer_dense.pyx | 16 +++ src/sage/matrix/matrix_integer_sparse.pyx | 7 ++ src/sage/matrix/matrix_mod2_dense.pyx | 99 +--------------- src/sage/matrix/matrix_modn_dense_double.pyx | 10 ++ src/sage/matrix/matrix_modn_dense_float.pyx | 9 ++ src/sage/matrix/matrix_modn_sparse.pyx | 4 + src/sage/matrix/matrix_numpy_dense.pyx | 10 ++ src/sage/matrix/matrix_rational_dense.pyx | 4 + src/sage/matrix/matrix_rational_sparse.pyx | 7 ++ src/sage/matrix/matrix_sparse.pyx | 2 +- 21 files changed, 147 insertions(+), 195 deletions(-) diff --git a/src/sage/matrix/matrix0.pxd b/src/sage/matrix/matrix0.pxd index 00e0bb5b196..f8dd8158125 100644 --- a/src/sage/matrix/matrix0.pxd +++ b/src/sage/matrix/matrix0.pxd @@ -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 diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index 22a7a02d9e0..8cdc65918a5 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -556,6 +556,14 @@ 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 from one matrix to another. It is assumed ``src`` is the same type of matrix as ``self``, with the same base ring. + + This is fast because it avoids the type conversion that often is necessary in ``get_unsafe`` and ``set_unsafe``. + """ + raise NotImplementedError("this must be defined in the derived type.") + 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. diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index 85c9833a3d6..df1cfe5f298 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -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): @@ -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): @@ -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, diff --git a/src/sage/matrix/matrix_complex_ball_dense.pyx b/src/sage/matrix/matrix_complex_ball_dense.pyx index b8b193145c7..6131c69cd71 100644 --- a/src/sage/matrix/matrix_complex_ball_dense.pyx +++ b/src/sage/matrix/matrix_complex_ball_dense.pyx @@ -307,6 +307,19 @@ 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 this matrix. + + .. 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``. + """ + cdef Matrix_complex_ball_dense _src = 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:: diff --git a/src/sage/matrix/matrix_cyclo_dense.pyx b/src/sage/matrix/matrix_cyclo_dense.pyx index 5519882cd12..98766f2b140 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pyx +++ b/src/sage/matrix/matrix_cyclo_dense.pyx @@ -407,6 +407,18 @@ 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``. + """ + 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. diff --git a/src/sage/matrix/matrix_dense.pyx b/src/sage/matrix/matrix_dense.pyx index 471fe521bf0..952adb88ad6 100644 --- a/src/sage/matrix/matrix_dense.pyx +++ b/src/sage/matrix/matrix_dense.pyx @@ -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() diff --git a/src/sage/matrix/matrix_gap.pyx b/src/sage/matrix/matrix_gap.pyx index f5a6e1d10e7..2920b76f61b 100644 --- a/src/sage/matrix/matrix_gap.pyx +++ b/src/sage/matrix/matrix_gap.pyx @@ -204,6 +204,10 @@ 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): + cdef Matrix_gap _src = src + self._libgap[iDst,jDst] = _src._libgap[iSrc,jSrc] + cpdef _richcmp_(self, other, int op): r""" Compare ``self`` and ``right``. diff --git a/src/sage/matrix/matrix_generic_dense.pyx b/src/sage/matrix/matrix_generic_dense.pyx index 28603b5a930..2980605037a 100644 --- a/src/sage/matrix/matrix_generic_dense.pyx +++ b/src/sage/matrix/matrix_generic_dense.pyx @@ -99,6 +99,10 @@ 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): + cdef Matrix_generic_dense _src = src + self._entries[iDst*self._ncols + jDst] = _src._entries[iSrc*_src._ncols + jSrc] + def _reverse_unsafe(self): r""" TESTS:: diff --git a/src/sage/matrix/matrix_generic_sparse.pyx b/src/sage/matrix/matrix_generic_sparse.pyx index 0fba0426cf2..969e9155cb2 100644 --- a/src/sage/matrix/matrix_generic_sparse.pyx +++ b/src/sage/matrix/matrix_generic_sparse.pyx @@ -200,6 +200,13 @@ 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): + cdef Matrix_generic_sparse _src = 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. diff --git a/src/sage/matrix/matrix_gf2e_dense.pyx b/src/sage/matrix/matrix_gf2e_dense.pyx index 17f849124c9..3bed85adde5 100644 --- a/src/sage/matrix/matrix_gf2e_dense.pyx +++ b/src/sage/matrix/matrix_gf2e_dense.pyx @@ -285,6 +285,21 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): cdef Cache_base cache = 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): + """ + A[iDst,jDst] = B[iSrc,jSrc] without bound checks. + + INPUT: + + - ``iDst`` -- row index + - ``jDst`` -- column index + - ``src`` -- source matrix, assumed to be a Matrix_gf2e_dense, with same base ring + - ``iSrc`` -- row index + - ``jSrc`` -- column index + """ + cdef Matrix_gf2e_dense _src = 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. @@ -1349,101 +1364,6 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): A._entries = mzed_submatrix(A._entries, self._entries, row, col, highr, highc) return A - def matrix_from_rows(self, rows): - r""" - Return the matrix constructed from ``self`` using rows with indices in - the rows list. - - EXAMPLES:: - - sage: M = matrix(GF(4),[[0,[0,1],0],[0,[1,1],1],[1,0,1]]) - sage: M - [ 0 z2 0] - [ 0 z2 + 1 1] - [ 1 0 1] - sage: M.matrix_from_rows([2,1]) - [ 1 0 1] - [ 0 z2 + 1 1] - """ - rows = PySequence_Fast(rows, "rows is not iterable") - if any(0 > row or row >= self._nrows for row in rows): - raise TypeError("Rows are not all in range") - - cdef Py_ssize_t nrows = len(rows) - - cdef Matrix_gf2e_dense A = self.new_matrix(nrows=nrows) - - cdef Py_ssize_t i, j, row - for i, row in enumerate(rows): - for j in range(self._ncols): - mzed_write_elem(A._entries, i, j, mzed_read_elem(self._entries, row, j)) - return A - - def matrix_from_columns(self, cols): - r""" - Return the matrix constructed from ``self`` using columns with indices - in the columns list. - - EXAMPLES:: - - sage: M = matrix(GF(4),[[0,[0,1],0],[0,[1,1],1],[1,0,1]]) - sage: M - [ 0 z2 0] - [ 0 z2 + 1 1] - [ 1 0 1] - sage: M.matrix_from_columns([2,1]) - [ 0 z2] - [ 1 z2 + 1] - [ 1 0] - """ - cols = PySequence_Fast(cols, "cols is not iterable") - if any(0 > col or col >= self._ncols for col in cols): - raise TypeError("Columns are not all in range") - - cdef Py_ssize_t ncols = len(cols) - - cdef Matrix_gf2e_dense A = self.new_matrix(ncols=ncols) - - cdef Py_ssize_t i, j, col - for i in range(self._nrows): - for j, col in enumerate(cols): - mzed_write_elem(A._entries, i, j, mzed_read_elem(self._entries, i, col)) - return A - - def matrix_from_rows_and_columns(self, rows, cols): - r""" - Return the matrix constructed from ``self`` from the given rows and - columns. - - EXAMPLES:: - - sage: M = matrix(GF(4),[[0,[0,1],0],[0,[1,1],1],[1,0,1]]) - sage: M - [ 0 z2 0] - [ 0 z2 + 1 1] - [ 1 0 1] - sage: M.matrix_from_rows_and_columns([0,1],[2,1]) - [ 0 z2] - [ 1 z2 + 1] - """ - rows = PySequence_Fast(rows, "rows is not iterable") - cols = PySequence_Fast(cols, "cols is not iterable") - if any(0 > row or row >= self._nrows for row in rows): - raise TypeError("Rows are not all in range") - if any(0 > col or col >= self._ncols for col in cols): - raise TypeError("Columns are not all in range") - - cdef Py_ssize_t nrows = len(rows) - cdef Py_ssize_t ncols = len(cols) - - cdef Matrix_gf2e_dense A = self.new_matrix(nrows=nrows, ncols=ncols) - - cdef Py_ssize_t i, j, row, col - for i,row in enumerate(rows): - for j, col in enumerate(cols): - mzed_write_elem(A._entries, i, j, mzed_read_elem(self._entries, row, col)) - return A - def rank(self): """ Return the rank of this matrix (cached). diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index ea56e04afbe..f3ec2fdf157 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -673,6 +673,13 @@ cdef class Matrix_gfpn_dense(Matrix_dense): finally: sig_off() + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + """ + Copies values without bound or type checking. + """ + cdef Matrix_gfpn_dense _src = src + FfInsert(FfGetPtr(self.Data.Data, iDst), jDst, FfExtract(MatGetPtr(_src.Data,iSrc), jSrc)) + def randomize(self, density=None, nonzero=False, *args, **kwds): """ Fill the matrix with random values. diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index aacd02d1aeb..f139b0e773a 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -476,6 +476,22 @@ cdef class Matrix_integer_dense(Matrix_dense): """ return fmpz_is_zero(fmpz_mat_entry(self._matrix, i,j)) + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + """Copy position iSrc,jSrc of ``src`` to position iDst,jDst of this matrix. + + The object ``src`` must be of type ``Matrix_integer_dense`` and have the same base ring as ``self``. + + INPUT: + + - ``iDst`` -- row + + - ``jDst`` -- column + + - ``src`` -- must be Matrix_integer_dense! The value to set ``self[i,j]`` to. + """ + cdef Matrix_integer_dense _src = src + fmpz_set(fmpz_mat_entry(self._matrix, iDst, jDst), fmpz_mat_entry(_src._matrix, iSrc, jSrc)) + def _pickle(self): """ EXAMPLES:: diff --git a/src/sage/matrix/matrix_integer_sparse.pyx b/src/sage/matrix/matrix_integer_sparse.pyx index a5f982a19e6..a242750a78f 100644 --- a/src/sage/matrix/matrix_integer_sparse.pyx +++ b/src/sage/matrix/matrix_integer_sparse.pyx @@ -118,6 +118,13 @@ cdef class Matrix_integer_sparse(Matrix_sparse): mpz_vector_get_entry(x.value, &self._matrix[i], j) return x + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + cdef Integer x + x = Integer() + cdef Matrix_integer_sparse _src = src + mpz_vector_get_entry(x.value, &_src._matrix[iSrc], jSrc) + mpz_vector_set_entry(&self._matrix[iDst], jDst, x.value) + 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. diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 219d1774729..7ae6cd23dd2 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -361,6 +361,10 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse else: return self._zero + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + cdef Matrix_mod2_dense _src = src + mzd_write_bit(self._entries, iDst, jDst, mzd_read_bit(_src._entries, iSrc, jSrc)) + def str(self, rep_mapping=None, zero=None, plus_one=None, minus_one=None, *, unicode=False, shape=None, character_art=False, left_border=None, right_border=None, @@ -1795,101 +1799,6 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse A._entries = mzd_submatrix(A._entries, self._entries, row, col, highr, highc) return A - def matrix_from_rows(self, rows): - r""" - Return the matrix constructed from ``self`` using rows with indices in - the rows list. - - EXAMPLES:: - - sage: M = matrix(GF(2),[[0,1,0],[0,1,1],[1,0,1]]) - sage: M - [0 1 0] - [0 1 1] - [1 0 1] - sage: M.matrix_from_rows([2,1]) - [1 0 1] - [0 1 1] - """ - rows = PySequence_Fast(rows, "rows is not iterable") - if any(0 > row or row >= self._nrows for row in rows): - raise TypeError("Rows are not all in range") - - cdef Py_ssize_t nrows = len(rows) - - cdef Matrix_mod2_dense A = self.new_matrix(nrows=nrows) - - cdef Py_ssize_t i, j, row - for i, row in enumerate(rows): - for j in range(self._ncols): - mzd_write_bit(A._entries, i, j, mzd_read_bit(self._entries, row, j)) - return A - - def matrix_from_columns(self, cols): - r""" - Return the matrix constructed from ``self`` using columns with indices - in the columns list. - - EXAMPLES:: - - sage: M = matrix(GF(2),[[0,1,0],[0,1,1],[1,0,1]]) - sage: M - [0 1 0] - [0 1 1] - [1 0 1] - sage: M.matrix_from_columns([2,1]) - [0 1] - [1 1] - [1 0] - """ - cols = PySequence_Fast(cols, "cols is not iterable") - if any(0 > col or col >= self._ncols for col in cols): - raise TypeError("Columns are not all in range") - - cdef Py_ssize_t ncols = len(cols) - - cdef Matrix_mod2_dense A = self.new_matrix(ncols=ncols) - - cdef Py_ssize_t i, j, col - for i in range(self._nrows): - for j, col in enumerate(cols): - mzd_write_bit(A._entries, i, j, mzd_read_bit(self._entries, i, col)) - return A - - def matrix_from_rows_and_columns(self, rows, cols): - r""" - Return the matrix constructed from ``self`` from the given rows and - columns. - - EXAMPLES:: - - sage: M = matrix(GF(2),[[0,1,0],[0,1,1],[1,0,1]]) - sage: M - [0 1 0] - [0 1 1] - [1 0 1] - sage: M.matrix_from_rows_and_columns([0,1],[2,1]) - [0 1] - [1 1] - """ - rows = PySequence_Fast(rows, "rows is not iterable") - cols = PySequence_Fast(cols, "cols is not iterable") - if any(0 > row or row >= self._nrows for row in rows): - raise TypeError("Rows are not all in range") - if any(0 > col or col >= self._ncols for col in cols): - raise TypeError("Columns are not all in range") - - cdef Py_ssize_t nrows = len(rows) - cdef Py_ssize_t ncols = len(cols) - - cdef Matrix_mod2_dense A = self.new_matrix(nrows=nrows, ncols=ncols) - - cdef Py_ssize_t i, j, row, col - for i,row in enumerate(rows): - for j, col in enumerate(cols): - mzd_write_bit(A._entries, i, j, mzd_read_bit(self._entries, row, col)) - return A - def __reduce__(self): """ Serialize ``self``. diff --git a/src/sage/matrix/matrix_modn_dense_double.pyx b/src/sage/matrix/matrix_modn_dense_double.pyx index ecb41e7d5dd..50d02c21759 100644 --- a/src/sage/matrix/matrix_modn_dense_double.pyx +++ b/src/sage/matrix/matrix_modn_dense_double.pyx @@ -175,3 +175,13 @@ cdef class Matrix_modn_dense_double(Matrix_modn_dense_template): return (_self._get_template)._new_c(result) else: return (_self._get_template)._new_c(result) + + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copies the (iSrc,jSrc) entry of ``src`` to the (iDst,jDst) entry of ``self`` with no bounds-checking, or any other checks. + + Assumes that ``src`` is a Matrix_modn_dense_double with the same base ring as ``self``. + """ + cdef Matrix_modn_dense_double _src = src + self._matrix[iDst][jDst] = _src._matrix[iSrc][jSrc] + \ No newline at end of file diff --git a/src/sage/matrix/matrix_modn_dense_float.pyx b/src/sage/matrix/matrix_modn_dense_float.pyx index 13dedf8441c..537f350e84b 100644 --- a/src/sage/matrix/matrix_modn_dense_float.pyx +++ b/src/sage/matrix/matrix_modn_dense_float.pyx @@ -151,3 +151,12 @@ cdef class Matrix_modn_dense_float(Matrix_modn_dense_template): """ cdef float result = (self)._matrix[i][j] return (self)._get_template._new_c(result) + + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + """ + Copies the (iSrc,jSrc) entry of ``src`` to the (iDst,jDst) entry of ``self`` with no bounds-checking, or any other checks. + + Assumes that ``src`` is a Matrix_modn_dense_float with the same base ring as ``self``. + """ + cdef Matrix_modn_dense_float _src = src + self._matrix[iDst][jDst] = _src._matrix[iSrc][jSrc] diff --git a/src/sage/matrix/matrix_modn_sparse.pyx b/src/sage/matrix/matrix_modn_sparse.pyx index 9b7cdcd2dcb..ad63ab6faf3 100644 --- a/src/sage/matrix/matrix_modn_sparse.pyx +++ b/src/sage/matrix/matrix_modn_sparse.pyx @@ -182,6 +182,10 @@ cdef class Matrix_modn_sparse(Matrix_sparse): n.ivalue = get_entry(&self.rows[i], j) return n + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + cdef Matrix_modn_sparse _src = src + set_entry(&self.rows[iDst], jDst, get_entry(&_src.rows[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. diff --git a/src/sage/matrix/matrix_numpy_dense.pyx b/src/sage/matrix/matrix_numpy_dense.pyx index e6420bf29c8..64034d5dd0c 100644 --- a/src/sage/matrix/matrix_numpy_dense.pyx +++ b/src/sage/matrix/matrix_numpy_dense.pyx @@ -177,6 +177,16 @@ cdef class Matrix_numpy_dense(Matrix_dense): return self._sage_dtype(cnumpy.PyArray_GETITEM(self._matrix_numpy, cnumpy.PyArray_GETPTR2(self._matrix_numpy, i, j))) + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + """ + Copy the (iDst,jDst) entry of ``src`` to the ``(iSrc,jSrc)`` entry of ``self`` without any bounds checking, + mutability checking, etc. + + ``src`` is assumed to be a Matrix_numpy_dense + """ + cdef Matrix_numpy_dense _src = src + cnumpy.PyArray_SETITEM(self._matrix_numpy, cnumpy.PyArray_GETPTR2(self._matrix_numpy, iDst, jDst), cnumpy.PyArray_GETITEM(_src._matrix_numpy, cnumpy.PyArray_GETPTR2(_src._matrix_numpy, iSrc, jSrc))) + cdef Matrix_numpy_dense _new(self, int nrows=-1, int ncols=-1): """ Return a new uninitialized matrix with same parent as ``self``. diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index aa941292787..aae528d1985 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -264,6 +264,10 @@ cdef class Matrix_rational_dense(Matrix_dense): fmpq_get_mpq(x.value, fmpq_mat_entry(self._matrix, i, j)) return x + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + cdef Matrix_rational_dense _src = src + fmpq_set(fmpq_mat_entry(self._matrix, iDst, jDst), fmpq_mat_entry(_src._matrix, 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. diff --git a/src/sage/matrix/matrix_rational_sparse.pyx b/src/sage/matrix/matrix_rational_sparse.pyx index 8d86b09258a..73b01004034 100644 --- a/src/sage/matrix/matrix_rational_sparse.pyx +++ b/src/sage/matrix/matrix_rational_sparse.pyx @@ -102,6 +102,13 @@ cdef class Matrix_rational_sparse(Matrix_sparse): mpq_vector_get_entry(x.value, &self._matrix[i], j) return x + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + cdef Rational x + x = Rational() + cdef Matrix_rational_sparse _src = src + mpq_vector_get_entry(x.value, &_src._matrix[iSrc], jSrc) + mpq_vector_set_entry(&self._matrix[iDst], jDst, x.value) + 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. diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index 2ed725679f7..684ff6c501a 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -432,7 +432,7 @@ cdef class Matrix_sparse(matrix.Matrix): for k from 0 <= k < len(nz): i = get_ij(nz, k, 0) j = get_ij(nz, k, 1) - A.set_unsafe(j,i,self.get_unsafe(i,j)) + A.copy_from_unsafe(j, i, self, i, j) if self._subdivisions is not None: row_divs, col_divs = self.subdivisions() A.subdivide(col_divs, row_divs) From fc7856a0d330e63113429b96e48dc7cddd6661aa Mon Sep 17 00:00:00 2001 From: Nicholas Bell Date: Wed, 23 Jul 2025 18:51:21 +0200 Subject: [PATCH 3/5] replace get set in antitranspose with copy --- src/sage/matrix/matrix_dense.pyx | 2 +- src/sage/matrix/matrix_sparse.pyx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_dense.pyx b/src/sage/matrix/matrix_dense.pyx index 952adb88ad6..d52b5e2d3e7 100644 --- a/src/sage/matrix/matrix_dense.pyx +++ b/src/sage/matrix/matrix_dense.pyx @@ -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() diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index 684ff6c501a..be8d3dff702 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -464,7 +464,7 @@ cdef class Matrix_sparse(matrix.Matrix): for k from 0 <= k < len(nz): i = get_ij(nz, k, 0) j = get_ij(nz, k, 1) - A.set_unsafe(self._ncols-j-1, self._nrows-i-1,self.get_unsafe(i,j)) + A.copy_from_unsafe(self._ncols-j-1, self._nrows-i-1, self, i, j) if self._subdivisions is not None: row_divs, col_divs = self.subdivisions() A.subdivide(list(reversed([self._ncols - t for t in col_divs])), From 4e155c5ba2f75aaa2c4f0b6c914279809ea782dd Mon Sep 17 00:00:00 2001 From: Nicholas Bell Date: Thu, 24 Jul 2025 13:15:49 +0200 Subject: [PATCH 4/5] update documentation --- src/sage/matrix/matrix0.pyx | 20 +++++++-- src/sage/matrix/matrix_complex_ball_dense.pyx | 40 ++++++++++++++++-- src/sage/matrix/matrix_cyclo_dense.pyx | 41 +++++++++++++++++-- src/sage/matrix/matrix_gap.pyx | 36 ++++++++++++++++ src/sage/matrix/matrix_generic_dense.pyx | 37 +++++++++++++++++ src/sage/matrix/matrix_generic_sparse.pyx | 37 +++++++++++++++++ src/sage/matrix/matrix_gf2e_dense.pyx | 40 ++++++++++++++---- src/sage/matrix/matrix_gfpn_dense.pyx | 38 ++++++++++++++++- src/sage/matrix/matrix_integer_dense.pyx | 35 +++++++++++++--- src/sage/matrix/matrix_integer_sparse.pyx | 37 +++++++++++++++++ src/sage/matrix/matrix_mod2_dense.pyx | 37 ++++++++++++++++- src/sage/matrix/matrix_modn_dense_double.pyx | 36 +++++++++++++++- src/sage/matrix/matrix_modn_dense_float.pyx | 37 +++++++++++++++-- src/sage/matrix/matrix_modn_sparse.pyx | 36 ++++++++++++++++ src/sage/matrix/matrix_numpy_dense.pyx | 40 +++++++++++++++--- src/sage/matrix/matrix_rational_dense.pyx | 36 ++++++++++++++++ src/sage/matrix/matrix_rational_sparse.pyx | 36 ++++++++++++++++ 17 files changed, 585 insertions(+), 34 deletions(-) diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index 8cdc65918a5..9aee0007f1f 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -558,11 +558,25 @@ cdef class Matrix(sage.structure.element.Matrix): cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): """ - Copy from one matrix to another. It is assumed ``src`` is the same type of matrix as ``self``, with the same base ring. + 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 is fast because it avoids the type conversion that often is necessary in ``get_unsafe`` and ``set_unsafe``. + 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``. """ - raise NotImplementedError("this must be defined in the derived type.") + cdef Matrix _src = 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: """ diff --git a/src/sage/matrix/matrix_complex_ball_dense.pyx b/src/sage/matrix/matrix_complex_ball_dense.pyx index 6131c69cd71..300cb7c0721 100644 --- a/src/sage/matrix/matrix_complex_ball_dense.pyx +++ b/src/sage/matrix/matrix_complex_ball_dense.pyx @@ -309,13 +309,47 @@ cdef class Matrix_complex_ball_dense(Matrix_dense): 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 this matrix. + 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 + 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 = src acb_set(acb_mat_entry(self.value, iDst, jDst), acb_mat_entry(_src.value, iSrc, jSrc)) diff --git a/src/sage/matrix/matrix_cyclo_dense.pyx b/src/sage/matrix/matrix_cyclo_dense.pyx index 98766f2b140..b393055c3ef 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pyx +++ b/src/sage/matrix/matrix_cyclo_dense.pyx @@ -409,10 +409,45 @@ cdef class Matrix_cyclo_dense(Matrix_dense): 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``. + 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``. + 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. = 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 diff --git a/src/sage/matrix/matrix_gap.pyx b/src/sage/matrix/matrix_gap.pyx index 2920b76f61b..f3bc0aeb41b 100644 --- a/src/sage/matrix/matrix_gap.pyx +++ b/src/sage/matrix/matrix_gap.pyx @@ -205,6 +205,42 @@ 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 = src self._libgap[iDst,jDst] = _src._libgap[iSrc,jSrc] diff --git a/src/sage/matrix/matrix_generic_dense.pyx b/src/sage/matrix/matrix_generic_dense.pyx index 2980605037a..7356dc1bcc7 100644 --- a/src/sage/matrix/matrix_generic_dense.pyx +++ b/src/sage/matrix/matrix_generic_dense.pyx @@ -100,6 +100,43 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): 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. = 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 = src self._entries[iDst*self._ncols + jDst] = _src._entries[iSrc*_src._ncols + jSrc] diff --git a/src/sage/matrix/matrix_generic_sparse.pyx b/src/sage/matrix/matrix_generic_sparse.pyx index 969e9155cb2..74cfc64b2c8 100644 --- a/src/sage/matrix/matrix_generic_sparse.pyx +++ b/src/sage/matrix/matrix_generic_sparse.pyx @@ -201,6 +201,43 @@ cdef class Matrix_generic_sparse(matrix_sparse.Matrix_sparse): 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. = 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 = src if (iSrc,jSrc) in _src._entries: self._entries[(iDst,jDst)] = _src._entries.get((iSrc, jSrc), _src._zero) diff --git a/src/sage/matrix/matrix_gf2e_dense.pyx b/src/sage/matrix/matrix_gf2e_dense.pyx index 3bed85adde5..6713dcfe71c 100644 --- a/src/sage/matrix/matrix_gf2e_dense.pyx +++ b/src/sage/matrix/matrix_gf2e_dense.pyx @@ -286,16 +286,42 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): 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): - """ - A[iDst,jDst] = B[iSrc,jSrc] without bound checks. + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. INPUT: - - ``iDst`` -- row index - - ``jDst`` -- column index - - ``src`` -- source matrix, assumed to be a Matrix_gf2e_dense, with same base ring - - ``iSrc`` -- row index - - ``jSrc`` -- column index + - ``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. = 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 = src mzed_write_elem(self._entries, iDst, jDst, mzed_read_elem(_src._entries, iSrc, jSrc)) diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index f3ec2fdf157..42aa71a6bda 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -674,8 +674,42 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sig_off() cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): - """ - Copies values without bound or type checking. + 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_gfpn_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. = GF(59) + sage: M = MatrixSpace(K, 3, 4, implementation=Matrix_gfpn_dense)(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_gfpn_dense _src = src FfInsert(FfGetPtr(self.Data.Data, iDst), jDst, FfExtract(MatGetPtr(_src.Data,iSrc), jSrc)) diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index f139b0e773a..8b8fb890cb5 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -477,17 +477,42 @@ cdef class Matrix_integer_dense(Matrix_dense): return fmpz_is_zero(fmpz_mat_entry(self._matrix, i,j)) cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): - """Copy position iSrc,jSrc of ``src`` to position iDst,jDst of this matrix. + """Copy position iSrc,jSrc of ``src`` to position iDst,jDst of ``self``. - The object ``src`` must be of type ``Matrix_integer_dense`` and have the same base ring as ``self``. + The object ``src`` must be of type ``Matrix_integer_dense`` and have + the same base ring as ``self``. INPUT: - - ``iDst`` -- row + - ``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_integer_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``. - - ``jDst`` -- column + TESTS:: - - ``src`` -- must be Matrix_integer_dense! The value to set ``self[i,j]`` to. + sage: m = matrix(ZZ,3,4,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_integer_dense _src = src fmpz_set(fmpz_mat_entry(self._matrix, iDst, jDst), fmpz_mat_entry(_src._matrix, iSrc, jSrc)) diff --git a/src/sage/matrix/matrix_integer_sparse.pyx b/src/sage/matrix/matrix_integer_sparse.pyx index a242750a78f..8cbce29f122 100644 --- a/src/sage/matrix/matrix_integer_sparse.pyx +++ b/src/sage/matrix/matrix_integer_sparse.pyx @@ -119,6 +119,43 @@ cdef class Matrix_integer_sparse(Matrix_sparse): 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 position iSrc,jSrc of ``src`` to position iDst,jDst of ``self``. + + The object ``src`` must be of type ``Matrix_integer_sparse`` and have + 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_integer_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: m = matrix(ZZ,3,4,[i if is_prime(i) else 0 for i in range(12)],sparse=True) + sage: m + [ 0 0 2 3] + [ 0 5 0 7] + [ 0 0 0 11] + sage: m.transpose() + [ 0 0 0] + [ 0 5 0] + [ 2 0 0] + [ 3 7 11] + sage: m.matrix_from_rows([0,2]) + [ 0 0 2 3] + [ 0 0 0 11] + sage: m.matrix_from_columns([1,3]) + [ 0 3] + [ 5 7] + [ 0 11] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [ 0 7] + [ 0 11] + """ cdef Integer x x = Integer() cdef Matrix_integer_sparse _src = src diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 7ae6cd23dd2..709201492ab 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -106,7 +106,6 @@ TESTS:: from cysignals.memory cimport check_malloc, sig_free from cysignals.signals cimport sig_on, sig_str, sig_off -from cpython.sequence cimport PySequence_Fast cimport sage.matrix.matrix_dense as matrix_dense from sage.matrix.args cimport SparseEntry, MatrixArgs_init, MA_ENTRIES_NDARRAY @@ -362,6 +361,42 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse return 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_mod2_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 = matrix(GF(2),3,4,[is_prime(i) for i in range(12)]) + sage: m + [0 0 1 1] + [0 1 0 1] + [0 0 0 1] + sage: m.transpose() + [0 0 0] + [0 1 0] + [1 0 0] + [1 1 1] + sage: m.matrix_from_rows([0,2]) + [0 0 1 1] + [0 0 0 1] + sage: m.matrix_from_columns([1,3]) + [0 1] + [1 1] + [0 1] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [0 1] + [0 1] + """ cdef Matrix_mod2_dense _src = src mzd_write_bit(self._entries, iDst, jDst, mzd_read_bit(_src._entries, iSrc, jSrc)) diff --git a/src/sage/matrix/matrix_modn_dense_double.pyx b/src/sage/matrix/matrix_modn_dense_double.pyx index 50d02c21759..1e8e8c193a2 100644 --- a/src/sage/matrix/matrix_modn_dense_double.pyx +++ b/src/sage/matrix/matrix_modn_dense_double.pyx @@ -178,9 +178,41 @@ cdef class Matrix_modn_dense_double(Matrix_modn_dense_template): cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): r""" - Copies the (iSrc,jSrc) entry of ``src`` to the (iDst,jDst) entry of ``self`` with no bounds-checking, or any other checks. + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. - Assumes that ``src`` is a Matrix_modn_dense_double 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_modn_dense_double 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 = matrix(GF(257),3,4,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_modn_dense_double _src = src self._matrix[iDst][jDst] = _src._matrix[iSrc][jSrc] diff --git a/src/sage/matrix/matrix_modn_dense_float.pyx b/src/sage/matrix/matrix_modn_dense_float.pyx index 537f350e84b..e04250ee99a 100644 --- a/src/sage/matrix/matrix_modn_dense_float.pyx +++ b/src/sage/matrix/matrix_modn_dense_float.pyx @@ -153,10 +153,41 @@ cdef class Matrix_modn_dense_float(Matrix_modn_dense_template): return (self)._get_template._new_c(result) cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): - """ - Copies the (iSrc,jSrc) entry of ``src`` to the (iDst,jDst) entry of ``self`` with no bounds-checking, or any other checks. + 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_modn_dense_float + 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:: - Assumes that ``src`` is a Matrix_modn_dense_float with the same base ring as ``self``. + sage: m = matrix(GF(131),3,4,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_modn_dense_float _src = src self._matrix[iDst][jDst] = _src._matrix[iSrc][jSrc] diff --git a/src/sage/matrix/matrix_modn_sparse.pyx b/src/sage/matrix/matrix_modn_sparse.pyx index ad63ab6faf3..8155f95f9ca 100644 --- a/src/sage/matrix/matrix_modn_sparse.pyx +++ b/src/sage/matrix/matrix_modn_sparse.pyx @@ -183,6 +183,42 @@ cdef class Matrix_modn_sparse(Matrix_sparse): return n 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_modn_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: m = matrix(GF(257),3,4,[i if is_prime(i) else 0 for i in range(12)],sparse=True) + sage: m + [ 0 0 2 3] + [ 0 5 0 7] + [ 0 0 0 11] + sage: m.transpose() + [ 0 0 0] + [ 0 5 0] + [ 2 0 0] + [ 3 7 11] + sage: m.matrix_from_rows([0,2]) + [ 0 0 2 3] + [ 0 0 0 11] + sage: m.matrix_from_columns([1,3]) + [ 0 3] + [ 5 7] + [ 0 11] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [ 0 7] + [ 0 11] + """ cdef Matrix_modn_sparse _src = src set_entry(&self.rows[iDst], jDst, get_entry(&_src.rows[iSrc], jSrc)) diff --git a/src/sage/matrix/matrix_numpy_dense.pyx b/src/sage/matrix/matrix_numpy_dense.pyx index 64034d5dd0c..52b64d826c9 100644 --- a/src/sage/matrix/matrix_numpy_dense.pyx +++ b/src/sage/matrix/matrix_numpy_dense.pyx @@ -178,11 +178,41 @@ cdef class Matrix_numpy_dense(Matrix_dense): cnumpy.PyArray_GETPTR2(self._matrix_numpy, i, j))) cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): - """ - Copy the (iDst,jDst) entry of ``src`` to the ``(iSrc,jSrc)`` entry of ``self`` without any bounds checking, - mutability checking, etc. - - ``src`` is assumed to be a Matrix_numpy_dense + 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_numpy_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(RDF, 3, 4)(range(12)) + sage: M + [ 0.0 1.0 2.0 3.0] + [ 4.0 5.0 6.0 7.0] + [ 8.0 9.0 10.0 11.0] + sage: M.transpose() + [ 0.0 4.0 8.0] + [ 1.0 5.0 9.0] + [ 2.0 6.0 10.0] + [ 3.0 7.0 11.0] + sage: M.matrix_from_rows([0,2]) + [ 0.0 1.0 2.0 3.0] + [ 8.0 9.0 10.0 11.0] + sage: M.matrix_from_columns([1,3]) + [ 1.0 3.0] + [ 5.0 7.0] + [ 9.0 11.0] + sage: M.matrix_from_rows_and_columns([1,2],[0,3]) + [ 4.0 7.0] + [ 8.0 11.0] """ cdef Matrix_numpy_dense _src = src cnumpy.PyArray_SETITEM(self._matrix_numpy, cnumpy.PyArray_GETPTR2(self._matrix_numpy, iDst, jDst), cnumpy.PyArray_GETITEM(_src._matrix_numpy, cnumpy.PyArray_GETPTR2(_src._matrix_numpy, iSrc, jSrc))) diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index aae528d1985..786809efaf4 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -265,6 +265,42 @@ cdef class Matrix_rational_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): + 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_rational_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 = matrix(QQ,3,4,[i + 1/(i+1) for i in range(12)]) + sage: M + [ 1 3/2 7/3 13/4] + [ 21/5 31/6 43/7 57/8] + [ 73/9 91/10 111/11 133/12] + sage: M.transpose() + [ 1 21/5 73/9] + [ 3/2 31/6 91/10] + [ 7/3 43/7 111/11] + [ 13/4 57/8 133/12] + sage: M.matrix_from_rows([0,2]) + [ 1 3/2 7/3 13/4] + [ 73/9 91/10 111/11 133/12] + sage: M.matrix_from_columns([1,3]) + [ 3/2 13/4] + [ 31/6 57/8] + [ 91/10 133/12] + sage: M.matrix_from_rows_and_columns([1,2],[0,3]) + [ 21/5 57/8] + [ 73/9 133/12] + """ cdef Matrix_rational_dense _src = src fmpq_set(fmpq_mat_entry(self._matrix, iDst, jDst), fmpq_mat_entry(_src._matrix, iSrc, jSrc)) diff --git a/src/sage/matrix/matrix_rational_sparse.pyx b/src/sage/matrix/matrix_rational_sparse.pyx index 73b01004034..0ea992e12dc 100644 --- a/src/sage/matrix/matrix_rational_sparse.pyx +++ b/src/sage/matrix/matrix_rational_sparse.pyx @@ -103,6 +103,42 @@ cdef class Matrix_rational_sparse(Matrix_sparse): return 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_rational_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: M = matrix(QQ,3,4,[i + 1/(i+1) if is_prime(i) else 0 for i in range(12)],sparse=True) + sage: M + [ 0 0 7/3 13/4] + [ 0 31/6 0 57/8] + [ 0 0 0 133/12] + sage: M.transpose() + [ 0 0 0] + [ 0 31/6 0] + [ 7/3 0 0] + [ 13/4 57/8 133/12] + sage: M.matrix_from_rows([0,2]) + [ 0 0 7/3 13/4] + [ 0 0 0 133/12] + sage: M.matrix_from_columns([1,3]) + [ 0 13/4] + [ 31/6 57/8] + [ 0 133/12] + sage: M.matrix_from_rows_and_columns([1,2],[0,3]) + [ 0 57/8] + [ 0 133/12] + """ cdef Rational x x = Rational() cdef Matrix_rational_sparse _src = src From 839f37d5a535eead3cbcc5cb69cd6469a034da93 Mon Sep 17 00:00:00 2001 From: Nicholas Bell Date: Fri, 25 Jul 2025 10:06:19 +0200 Subject: [PATCH 5/5] add line breaks, remove unused import --- src/sage/matrix/matrix_gf2e_dense.pyx | 1 - src/sage/matrix/matrix_integer_dense.pyx | 3 ++- src/sage/matrix/matrix_integer_sparse.pyx | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix_gf2e_dense.pyx b/src/sage/matrix/matrix_gf2e_dense.pyx index 6713dcfe71c..4a36cbb7ece 100644 --- a/src/sage/matrix/matrix_gf2e_dense.pyx +++ b/src/sage/matrix/matrix_gf2e_dense.pyx @@ -82,7 +82,6 @@ REFERENCES: #***************************************************************************** from cysignals.signals cimport sig_on, sig_off -from cpython.sequence cimport PySequence_Fast cimport sage.matrix.matrix_dense as matrix_dense from sage.structure.element cimport Matrix diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index 8b8fb890cb5..f15380ad1db 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -477,7 +477,8 @@ cdef class Matrix_integer_dense(Matrix_dense): return fmpz_is_zero(fmpz_mat_entry(self._matrix, i,j)) cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): - """Copy position iSrc,jSrc of ``src`` to position iDst,jDst of ``self``. + """ + Copy position iSrc,jSrc of ``src`` to position iDst,jDst of ``self``. The object ``src`` must be of type ``Matrix_integer_dense`` and have the same base ring as ``self``. diff --git a/src/sage/matrix/matrix_integer_sparse.pyx b/src/sage/matrix/matrix_integer_sparse.pyx index 8cbce29f122..45f92acf0b6 100644 --- a/src/sage/matrix/matrix_integer_sparse.pyx +++ b/src/sage/matrix/matrix_integer_sparse.pyx @@ -119,7 +119,8 @@ cdef class Matrix_integer_sparse(Matrix_sparse): 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 position iSrc,jSrc of ``src`` to position iDst,jDst of ``self``. + """ + Copy position iSrc,jSrc of ``src`` to position iDst,jDst of ``self``. The object ``src`` must be of type ``Matrix_integer_sparse`` and have the same base ring as ``self``.