| 1 | ############################################# |
|---|
| 2 | ## Generic *DENSE* matrices over any commutative ring |
|---|
| 3 | ############################################# |
|---|
| 4 | |
|---|
| 5 | def _convert_dense_entries_to_list(entries): |
|---|
| 6 | # Create matrix from a list of vectors |
|---|
| 7 | e = [] |
|---|
| 8 | for v in entries: |
|---|
| 9 | e = e+ v.list() |
|---|
| 10 | copy = False |
|---|
| 11 | return e |
|---|
| 12 | |
|---|
| 13 | include "../ext/interrupt.pxi" |
|---|
| 14 | |
|---|
| 15 | cimport matrix_generic |
|---|
| 16 | import matrix_generic |
|---|
| 17 | |
|---|
| 18 | cdef class Matrix_dense(matrix_generic.Matrix): |
|---|
| 19 | """ |
|---|
| 20 | The \\class{Matrix_dense} class derives from |
|---|
| 21 | \\class{Matrix}, and defines functionality for dense matrices over |
|---|
| 22 | any base ring. Matrices are represented by a list of elements in |
|---|
| 23 | the base ring, and element access operations are implemented in |
|---|
| 24 | this class. |
|---|
| 25 | """ |
|---|
| 26 | def __init__(self, parent, |
|---|
| 27 | entries = None, |
|---|
| 28 | copy = True, |
|---|
| 29 | coerce = True): |
|---|
| 30 | matrix_generic.Matrix.__init__(self, parent) |
|---|
| 31 | self._nrows = parent.nrows() |
|---|
| 32 | self._ncols = parent.ncols() |
|---|
| 33 | cdef int i, n |
|---|
| 34 | if entries: |
|---|
| 35 | if not isinstance(entries, list): |
|---|
| 36 | raise TypeError, 'entries must be a list' |
|---|
| 37 | if not (coerce or copy): |
|---|
| 38 | self.__entries = entries |
|---|
| 39 | else: |
|---|
| 40 | self.__entries = [None]*(self._nrows*self._ncols) |
|---|
| 41 | n = len(entries) |
|---|
| 42 | if coerce: |
|---|
| 43 | R = parent.base_ring() |
|---|
| 44 | for i from 0 <= i < n: |
|---|
| 45 | self.__entries[i] = R(entries[i]) |
|---|
| 46 | else: |
|---|
| 47 | for i from 0 <= i < n: |
|---|
| 48 | self.__entries[i] = entries[i] |
|---|
| 49 | else: |
|---|
| 50 | self.__entries = [None]*(self._nrows*self._ncols) |
|---|
| 51 | |
|---|
| 52 | self._init_row_indices() |
|---|
| 53 | |
|---|
| 54 | def _init_row_indices(self): |
|---|
| 55 | self._row_indices = <int*> PyMem_Malloc(sizeof(int*) * self._nrows) |
|---|
| 56 | n = 0 |
|---|
| 57 | for i from 0 <= i < self._nrows: |
|---|
| 58 | self._row_indices[i] = n |
|---|
| 59 | n = n + self._ncols |
|---|
| 60 | |
|---|
| 61 | def __dealloc__(self): |
|---|
| 62 | PyMem_Free(self._row_indices) |
|---|
| 63 | |
|---|
| 64 | def __getitem__(self, ij): |
|---|
| 65 | """ |
|---|
| 66 | INPUT: |
|---|
| 67 | A[i, j] -- the i,j of A, and |
|---|
| 68 | A[i] -- the i-th row of A. |
|---|
| 69 | """ |
|---|
| 70 | #self._require_mutable() # todo |
|---|
| 71 | cdef int i, j |
|---|
| 72 | i, j = ij |
|---|
| 73 | if i < 0 or i >= self._nrows: |
|---|
| 74 | raise IndexError |
|---|
| 75 | return self.__entries[self._row_indices[i] + j] |
|---|
| 76 | |
|---|
| 77 | def __setitem__(self, ij, value): |
|---|
| 78 | """ |
|---|
| 79 | INPUT: |
|---|
| 80 | A[i, j] = value -- set the (i,j) entry of A |
|---|
| 81 | A[i] = value -- set the ith row of A |
|---|
| 82 | """ |
|---|
| 83 | #self._require_mutable() # todo |
|---|
| 84 | cdef int i, j |
|---|
| 85 | i, j = ij |
|---|
| 86 | if i < 0 or i >= self._nrows: |
|---|
| 87 | raise IndexError |
|---|
| 88 | self.__entries[self._row_indices[i] + j] = value |
|---|
| 89 | |
|---|
| 90 | def matrix_window(self, int row=0, int col=0, int nrows=-1, int ncols=-1): |
|---|
| 91 | if nrows == -1: |
|---|
| 92 | nrows = self._nrows |
|---|
| 93 | ncols = self._ncols |
|---|
| 94 | return MatrixWindow(self, row, col, nrows, ncols) |
|---|
| 95 | |
|---|
| 96 | cdef classical_multiply_cdef(self, matrix_generic.Matrix right): |
|---|
| 97 | """ |
|---|
| 98 | Multiply the matrices self and right using the classical $O(n^3)$ |
|---|
| 99 | algorithm. |
|---|
| 100 | |
|---|
| 101 | EXAMPLES |
|---|
| 102 | |
|---|
| 103 | sage: include the 0 rows and 0 columns cases -- do dense examples |
|---|
| 104 | """ |
|---|
| 105 | cdef int i, j, k, m, n, r, nr, nc, snc |
|---|
| 106 | cdef object v |
|---|
| 107 | |
|---|
| 108 | if self._ncols != right._nrows: |
|---|
| 109 | raise IndexError, "Number of columns of self must equal number of rows of other." |
|---|
| 110 | |
|---|
| 111 | cdef Matrix_dense A |
|---|
| 112 | nr = self._nrows |
|---|
| 113 | nc = right._ncols |
|---|
| 114 | snc = self._ncols |
|---|
| 115 | |
|---|
| 116 | R = self.base_ring() |
|---|
| 117 | P = self.matrix_space(nr, nc) |
|---|
| 118 | A = Matrix_dense(P) |
|---|
| 119 | v = A.__entries |
|---|
| 120 | zero = R(0) |
|---|
| 121 | r = 0 |
|---|
| 122 | for i from 0 <= i < nr: |
|---|
| 123 | m = self._row_indices[i] |
|---|
| 124 | for j from 0 <= j < nc: |
|---|
| 125 | z = zero |
|---|
| 126 | for k from 0 <= k < snc: |
|---|
| 127 | z = z + self.__entries[m + k] * right.__entries[right._row_indices[k]+j] |
|---|
| 128 | v[r] = z |
|---|
| 129 | r = r + 1 |
|---|
| 130 | return A |
|---|
| 131 | |
|---|
| 132 | def _entries(self): |
|---|
| 133 | return self.__entries |
|---|
| 134 | |
|---|
| 135 | def list(self): |
|---|
| 136 | return self.__entries |
|---|
| 137 | |
|---|
| 138 | def antitranspose(self): |
|---|
| 139 | f = [] |
|---|
| 140 | e = self.list() |
|---|
| 141 | (nc, nr) = (self.ncols(), self.nrows()) |
|---|
| 142 | for j in reversed(xrange(nc)): |
|---|
| 143 | for i in reversed(xrange(nr)): |
|---|
| 144 | f.append(e[i*nc + j]) |
|---|
| 145 | return self.new_matrix(nrows = nc, ncols = nr, |
|---|
| 146 | entries = f, copy=False, coerce=False) |
|---|
| 147 | |
|---|
| 148 | def transpose(self): |
|---|
| 149 | """ |
|---|
| 150 | Returns the transpose of self, without changing self. |
|---|
| 151 | |
|---|
| 152 | EXAMPLES: |
|---|
| 153 | We create a matrix, compute its transpose, and note that the |
|---|
| 154 | original matrix is not changed. |
|---|
| 155 | sage: M = MatrixSpace(QQ, 2) |
|---|
| 156 | sage: A = M([1,2,3,4]) |
|---|
| 157 | sage: B = A.transpose() |
|---|
| 158 | sage: print B |
|---|
| 159 | [1 3] |
|---|
| 160 | [2 4] |
|---|
| 161 | sage: print A |
|---|
| 162 | [1 2] |
|---|
| 163 | [3 4] |
|---|
| 164 | """ |
|---|
| 165 | f = [] |
|---|
| 166 | e = self.list() |
|---|
| 167 | (nc, nr) = (self.ncols(), self.nrows()) |
|---|
| 168 | for j in xrange(nc): |
|---|
| 169 | for i in xrange(nr): |
|---|
| 170 | f.append(e[i*nc + j]) |
|---|
| 171 | return self.new_matrix(nrows = nc, ncols = nr, |
|---|
| 172 | entries = f, copy=False, |
|---|
| 173 | coerce=False) |
|---|
| 174 | |
|---|
| 175 | |
|---|
| 176 | |
|---|
| 177 | cdef class MatrixWindow: |
|---|
| 178 | |
|---|
| 179 | def __init__(MatrixWindow self, matrix, int row, int col, int nrows, int ncols): |
|---|
| 180 | self._matrix = matrix |
|---|
| 181 | self._row = row |
|---|
| 182 | self._col = col |
|---|
| 183 | self._nrows = nrows |
|---|
| 184 | self._ncols = ncols |
|---|
| 185 | |
|---|
| 186 | def __repr__(self): |
|---|
| 187 | return "Matrix window of size %s x %s at (%s,%s):\n%s"%( |
|---|
| 188 | self._nrows, self._ncols, self._row, self._col, self._matrix) |
|---|
| 189 | |
|---|
| 190 | def matrix(MatrixWindow self): |
|---|
| 191 | """ |
|---|
| 192 | Returns the underlying matrix that this window is a view of. |
|---|
| 193 | |
|---|
| 194 | EXAMPLES: |
|---|
| 195 | |
|---|
| 196 | """ |
|---|
| 197 | return self._matrix |
|---|
| 198 | |
|---|
| 199 | |
|---|
| 200 | def to_matrix(MatrixWindow self): |
|---|
| 201 | """ |
|---|
| 202 | Returns an actual matrix object representing this view. (Copy) |
|---|
| 203 | """ |
|---|
| 204 | entries = self.list() |
|---|
| 205 | return self._matrix.new_matrix(self._nrows, self._ncols, entries=entries, |
|---|
| 206 | coerce=False, copy=False) |
|---|
| 207 | |
|---|
| 208 | def list(MatrixWindow self): |
|---|
| 209 | v = self._matrix.__entries |
|---|
| 210 | w = [None]*(self._nrows*self._ncols) |
|---|
| 211 | cdef int i, j, k, l |
|---|
| 212 | k = 0 |
|---|
| 213 | for i from 0 <= i < self._nrows: |
|---|
| 214 | l = self._matrix._row_indices[i] |
|---|
| 215 | for j from 0 <= j < self._ncols: |
|---|
| 216 | w[k] = v[l + j] |
|---|
| 217 | k = k + 1 |
|---|
| 218 | return w |
|---|
| 219 | |
|---|
| 220 | def matrix_window(MatrixWindow self, int row, int col, int n_rows, int n_cols): |
|---|
| 221 | """ |
|---|
| 222 | Returns a matrix window relative to this window of the underlying matrix. |
|---|
| 223 | """ |
|---|
| 224 | return self._matrix.matrix_window(self._matrix, _row + row, _col + col, n_rows, n_cols) |
|---|
| 225 | |
|---|
| 226 | def nrows(MatrixWindow self): |
|---|
| 227 | return self._nrows |
|---|
| 228 | |
|---|
| 229 | def ncols(MatrixWindow self): |
|---|
| 230 | return self._ncols |
|---|
| 231 | |
|---|
| 232 | |
|---|
| 233 | def set_to(MatrixWindow self, MatrixWindow A): |
|---|
| 234 | cdef int i, j |
|---|
| 235 | cdef int start, self_ix |
|---|
| 236 | cdef int A_ix |
|---|
| 237 | for i from 0 <= i < self._nrows: |
|---|
| 238 | A_ix = self._matrix._row_indices[i+A._row] + a._col |
|---|
| 239 | for self_ix from self._row_indices[i+self._row] + self._col <= self_ix < self_start + self._ncols: |
|---|
| 240 | self._matrix.__entries[self_ix] = A._matrix.__entries[A_ix] |
|---|
| 241 | A_ix = A_ix + 1 |
|---|
| 242 | |
|---|
| 243 | |
|---|
| 244 | def set_to_zero(MatrixWindow self): |
|---|
| 245 | cdef int i, j |
|---|
| 246 | cdef int start, self_ix |
|---|
| 247 | zero = self._matrix.base_ring(0) |
|---|
| 248 | for i from 0 <= i < self._nrows: |
|---|
| 249 | for self_ix from self._row_indices[i+self._row] + self._col <= self_ix < self_start + self._ncols: |
|---|
| 250 | self._matrix.__entries[self_ix] = zero |
|---|
| 251 | |
|---|
| 252 | |
|---|
| 253 | def add(MatrixWindow self, MatrixWindow A): |
|---|
| 254 | cdef int i, j |
|---|
| 255 | cdef int start, self_ix |
|---|
| 256 | cdef int A_ix |
|---|
| 257 | for i from 0 <= i < self._nrows: |
|---|
| 258 | A_ix = A._matrix._row_indices[i+A._row] + A._col |
|---|
| 259 | for self_ix from self._row_indices[i+self._row] + self._col <= self_ix < self_start + self._ncols: |
|---|
| 260 | self._matrix.__entries[self_ix] = slef._matrix.__entries[self_ix] + A._matrix.__entries[A_ix] |
|---|
| 261 | A_ix = A_ix + 1 |
|---|
| 262 | |
|---|
| 263 | |
|---|
| 264 | def subtract(MatrixWindow self, MatrixWindow A): |
|---|
| 265 | cdef int i, j |
|---|
| 266 | cdef int start, self_ix |
|---|
| 267 | cdef int A_ix |
|---|
| 268 | for i from 0 <= i < self._nrows: |
|---|
| 269 | A_ix = A._matrix._row_indices[i+A._row] + a._col |
|---|
| 270 | for self_ix from self._row_indices[i+self._row] + self._col <= self_ix < self_start + self._ncols: |
|---|
| 271 | self._matrix.__entries[self_ix] = self._matrix.__entries[self_ix] - A._matrix.__entries[A_ix] |
|---|
| 272 | A_ix = A_ix + 1 |
|---|
| 273 | |
|---|
| 274 | |
|---|
| 275 | def set_to_sum(MatrixWindow self, MatrixWindow A, MatrixWindow B): |
|---|
| 276 | cdef int i, j |
|---|
| 277 | cdef int start, self_ix |
|---|
| 278 | cdef int A_ix |
|---|
| 279 | for i from 0 <= i < self._nrows: |
|---|
| 280 | A_ix = A._matrix._row_indices[i+A._row] + A._col |
|---|
| 281 | B_ix = B._matrix._row_indices[i+B._row] + B._col |
|---|
| 282 | for self_ix from self._row_indices[i+self._row] + self._col <= self_ix < self_start + self._ncols: |
|---|
| 283 | self._matrix.__entries[self_ix] = A._matrix.__entries[A_ix] + B._matrix.__entries[B_ix] |
|---|
| 284 | A_ix = A_ix + 1 |
|---|
| 285 | B_ix = B_ix + 1 |
|---|
| 286 | |
|---|
| 287 | |
|---|
| 288 | def set_to_diff(MatrixWindow self, MatrixWindow A, MatrixWindow B): |
|---|
| 289 | cdef int i, j |
|---|
| 290 | cdef int start, self_ix |
|---|
| 291 | cdef int A_ix |
|---|
| 292 | for i from 0 <= i < self._nrows: |
|---|
| 293 | A_ix = A._matrix._row_indices[i+A._row] + A._col |
|---|
| 294 | B_ix = B._matrix._row_indices[i+B._row] + B._col |
|---|
| 295 | for self_ix from self._row_indices[i+self._row] + self._col <= self_ix < self_start + self._ncols: |
|---|
| 296 | self._matrix.__entries[self_ix] = A._matrix.__entries[A_ix] - B._matrix.__entries[B_ix] |
|---|
| 297 | A_ix = A_ix + 1 |
|---|
| 298 | B_ix = B_ix + 1 |
|---|
| 299 | |
|---|
| 300 | |
|---|
| 301 | def set_to_prod(MatrixWindow self, MatrixWindow A, MatrixWindow B): |
|---|
| 302 | cdef int i, j, k |
|---|
| 303 | cdef int start, self_ix |
|---|
| 304 | for i from 0 <= i < A._nrows: |
|---|
| 305 | for j from 0 <= j < B._ncols: |
|---|
| 306 | sum = A._matrix.__entries[ A._row_indices[A._row+i]+A._col ] *B._matrix.__entries[ B._row_indices[B._row]+B._col+j ] |
|---|
| 307 | for k from 1 <= k < A._ncols: |
|---|
| 308 | sum = sum + A._matrix.__entries[ A._row_indices[A._row+i]+A._col + k ] * B._matrix.__entries[ B._row_indices[B._row+k]+B._col+j ] |
|---|
| 309 | self._matrix.__entries[ self._row_indices[self_.row+i]+self._col+j ] = sum |
|---|
| 310 | |
|---|
| 311 | |
|---|
| 312 | def add_prod(MatrixWindow self, MatrixWindow A, MatrixWindow B): |
|---|
| 313 | cdef int i, j, k |
|---|
| 314 | cdef int start, self_ix |
|---|
| 315 | for i from 0 <= i < A._nrows: |
|---|
| 316 | for j from 0 <= j < B._ncols: |
|---|
| 317 | sum = A._matrix.__entries[ A._row_indices[A._row+i]+A._col ] *B._matrix.__entries[ B._row_indices[B._row]+B._col+j ] |
|---|
| 318 | for k from 1 <= k < A._ncols: |
|---|
| 319 | sum = sum + A._matrix.__entries[ A._row_indices[A._row+i]+A._col + k ] * B._matrix.__entries[ B._row_indices[B._row+k]+B._col+j ] |
|---|
| 320 | self._matrix.__entries[ self._row_indices[self_.row+i]+self._col+j ] = self._matrix.__entries[ self._row_indices[self_.row+i]+self._col+j ] + sum |
|---|
| 321 | |
|---|
| 322 | |
|---|
| 323 | def new_empty_window(MatrixWindow self, int nrows, int ncols, zero=True): |
|---|
| 324 | return self._matrix.new_matrix(nrows,ncols, zero=zero).matrix_window() |
|---|