Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/matrix/matrix_dense.pyx
4072 views
1
r"""
2
Base class for dense matrices
3
4
TESTS::
5
6
sage: R.<a,b> = QQ[]
7
sage: m = matrix(R,2,[0,a,b,b^2])
8
sage: TestSuite(m).run()
9
"""
10
11
cimport matrix
12
13
from sage.structure.element cimport Element
14
import sage.matrix.matrix_space
15
import sage.structure.sequence
16
17
include '../ext/cdefs.pxi'
18
include '../ext/stdsage.pxi'
19
20
cdef class Matrix_dense(matrix.Matrix):
21
cdef bint is_sparse_c(self):
22
return 0
23
24
cdef bint is_dense_c(self):
25
return 1
26
27
def __copy__(self):
28
"""
29
Return a copy of this matrix. Changing the entries of the copy will
30
not change the entries of this matrix.
31
"""
32
A = self.new_matrix(entries=self.list(), coerce=False, copy=False)
33
if self._subdivisions is not None:
34
A.subdivide(*self.subdivisions())
35
return A
36
37
def __hash__(self):
38
"""
39
Return the hash of this matrix.
40
41
Equal matrices should have equal hashes, even if one is sparse and
42
the other is dense.
43
44
EXAMPLES::
45
46
sage: m = matrix(2, range(24), sparse=True)
47
sage: m.set_immutable()
48
sage: hash(m)
49
976
50
51
::
52
53
sage: d = m.dense_matrix()
54
sage: d.set_immutable()
55
sage: hash(d)
56
976
57
58
::
59
60
sage: hash(m) == hash(d)
61
True
62
"""
63
return self._hash()
64
65
cdef long _hash(self) except -1:
66
x = self.fetch('hash')
67
if not x is None: return x
68
69
if not self._mutability._is_immutable:
70
raise TypeError, "mutable matrices are unhashable"
71
72
v = self._list()
73
cdef Py_ssize_t i
74
cdef long h = 0
75
76
for i from 0 <= i < len(v):
77
h = h ^ (i * hash(v[i]))
78
79
if h == -1:
80
h = -2
81
82
self.cache('hash', h)
83
return h
84
85
cdef set_unsafe_int(self, Py_ssize_t i, Py_ssize_t j, int value):
86
self[i][j] = value
87
88
def _pickle(self):
89
version = -1
90
data = self._list() # linear list of all elements
91
return data, version
92
93
def _unpickle_generic(self, data, int version):
94
cdef Py_ssize_t i, j, k
95
if version == -1:
96
# data is a *list* of the entries of the matrix.
97
# TODO: Change the data[k] below to use the fast list access macros from the Python/C API
98
k = 0
99
for i from 0 <= i < self._nrows:
100
for j from 0 <= j < self._ncols:
101
self.set_unsafe(i, j, data[k])
102
k = k + 1
103
else:
104
raise RuntimeError, "unknown matrix version (=%s)"%version
105
106
cdef int _cmp_c_impl(self, Element right) except -2:
107
"""
108
EXAMPLES::
109
110
sage: P.<x> = QQ[]
111
sage: m = matrix([[x,x+1],[1,x]])
112
sage: n = matrix([[x+1,x],[1,x]])
113
sage: o = matrix([[x,x],[1,x]])
114
sage: m.__cmp__(n)
115
-1
116
sage: m.__cmp__(m)
117
0
118
sage: n.__cmp__(m)
119
1
120
sage: m.__cmp__(o)
121
1
122
"""
123
cdef Py_ssize_t i, j
124
for i from 0 <= i < self._nrows:
125
for j from 0 <= j < self._ncols:
126
res = cmp( self[i,j], right[i,j] )
127
if res != 0:
128
return res
129
return 0
130
131
def transpose(self):
132
"""
133
Returns the transpose of self, without changing self.
134
135
EXAMPLES: We create a matrix, compute its transpose, and note that
136
the original matrix is not changed.
137
138
::
139
140
sage: M = MatrixSpace(QQ, 2)
141
sage: A = M([1,2,3,4])
142
sage: B = A.transpose()
143
sage: print B
144
[1 3]
145
[2 4]
146
sage: print A
147
[1 2]
148
[3 4]
149
150
``.T`` is a convenient shortcut for the transpose::
151
152
sage: A.T
153
[1 3]
154
[2 4]
155
156
::
157
158
sage: A.subdivide(None, 1); A
159
[1|2]
160
[3|4]
161
sage: A.transpose()
162
[1 3]
163
[---]
164
[2 4]
165
"""
166
(nc, nr) = (self.ncols(), self.nrows())
167
cdef Matrix_dense trans
168
trans = self.new_matrix(nrows = nc, ncols = nr,
169
copy=False, coerce=False)
170
171
cdef Py_ssize_t i, j
172
for j from 0<= j < nc:
173
for i from 0<= i < nr:
174
trans.set_unsafe(j,i,self.get_unsafe(i,j))
175
176
if self._subdivisions is not None:
177
row_divs, col_divs = self.subdivisions()
178
trans.subdivide(col_divs, row_divs)
179
return trans
180
181
def antitranspose(self):
182
"""
183
Returns the antitranspose of self, without changing self.
184
185
EXAMPLES::
186
187
sage: A = matrix(2,3,range(6)); A
188
[0 1 2]
189
[3 4 5]
190
sage: A.antitranspose()
191
[5 2]
192
[4 1]
193
[3 0]
194
195
::
196
197
sage: A.subdivide(1,2); A
198
[0 1|2]
199
[---+-]
200
[3 4|5]
201
sage: A.antitranspose()
202
[5|2]
203
[-+-]
204
[4|1]
205
[3|0]
206
"""
207
(nc, nr) = (self.ncols(), self.nrows())
208
cdef Matrix_dense atrans
209
atrans = self.new_matrix(nrows = nc, ncols = nr,
210
copy=False, coerce=False)
211
cdef Py_ssize_t i,j
212
cdef Py_ssize_t ri,rj # reversed i and j
213
rj = nc
214
for j from 0 <= j < nc:
215
ri = nr
216
rj = rj-1
217
for i from 0 <= i < nr:
218
ri = ri-1
219
atrans.set_unsafe(j , i, self.get_unsafe(ri,rj))
220
221
if self._subdivisions is not None:
222
row_divs, col_divs = self.subdivisions()
223
atrans.subdivide([nc - t for t in reversed(col_divs)],
224
[nr - t for t in reversed(row_divs)])
225
return atrans
226
227
def _elementwise_product(self, right):
228
r"""
229
Returns the elementwise product of two dense
230
matrices with identical base rings.
231
232
This routine assumes that ``self`` and ``right``
233
are both matrices, both dense, with identical
234
sizes and with identical base rings. It is
235
"unsafe" in the sense that these conditions
236
are not checked and no sensible errors are
237
raised.
238
239
This routine is meant to be called from the
240
meth:`~sage.matrix.matrix2.Matrix.elementwise_product`
241
method, which will ensure that this routine receives
242
proper input. More thorough documentation is provided
243
there.
244
245
EXAMPLE::
246
247
sage: A = matrix(ZZ, 2, range(6), sparse=False)
248
sage: B = matrix(ZZ, 2, [1,0,2,0,3,0], sparse=False)
249
sage: A._elementwise_product(B)
250
[ 0 0 4]
251
[ 0 12 0]
252
253
AUTHOR:
254
255
- Rob Beezer (2009-07-14)
256
"""
257
cdef Py_ssize_t r, c
258
cdef Matrix_dense other, prod
259
260
nc, nr = self.ncols(), self.nrows()
261
other = right
262
prod = self.new_matrix(nr, nc, copy=False, coerce=False)
263
for r in range(nr):
264
for c in range(nc):
265
entry = self.get_unsafe(r,c)*other.get_unsafe(r,c)
266
prod.set_unsafe(r,c,entry)
267
return prod
268
269
def apply_morphism(self, phi):
270
"""
271
Apply the morphism phi to the coefficients of this dense matrix.
272
273
The resulting matrix is over the codomain of phi.
274
275
INPUT:
276
277
278
- ``phi`` - a morphism, so phi is callable and
279
phi.domain() and phi.codomain() are defined. The codomain must be a
280
ring.
281
282
283
OUTPUT: a matrix over the codomain of phi
284
285
EXAMPLES::
286
287
sage: m = matrix(ZZ, 3, range(9))
288
sage: phi = ZZ.hom(GF(5))
289
sage: m.apply_morphism(phi)
290
[0 1 2]
291
[3 4 0]
292
[1 2 3]
293
sage: parent(m.apply_morphism(phi))
294
Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 5
295
296
We apply a morphism to a matrix over a polynomial ring::
297
298
sage: R.<x,y> = QQ[]
299
sage: m = matrix(2, [x,x^2 + y, 2/3*y^2-x, x]); m
300
[ x x^2 + y]
301
[2/3*y^2 - x x]
302
sage: phi = R.hom([y,x])
303
sage: m.apply_morphism(phi)
304
[ y y^2 + x]
305
[2/3*x^2 - y y]
306
"""
307
R = phi.codomain()
308
M = sage.matrix.matrix_space.MatrixSpace(R, self._nrows,
309
self._ncols, sparse=False)
310
image = M([phi(z) for z in self.list()])
311
if self._subdivisions is not None:
312
image.subdivide(*self.subdivisions())
313
return image
314
315
def apply_map(self, phi, R=None, sparse=False):
316
"""
317
Apply the given map phi (an arbitrary Python function or callable
318
object) to this dense matrix. If R is not given, automatically
319
determine the base ring of the resulting matrix.
320
321
INPUT:
322
sparse -- True to make the output a sparse matrix; default False
323
324
325
- ``phi`` - arbitrary Python function or callable
326
object
327
328
- ``R`` - (optional) ring
329
330
331
OUTPUT: a matrix over R
332
333
EXAMPLES::
334
335
sage: m = matrix(ZZ, 3, range(9))
336
sage: k.<a> = GF(9)
337
sage: f = lambda x: k(x)
338
sage: n = m.apply_map(f); n
339
[0 1 2]
340
[0 1 2]
341
[0 1 2]
342
sage: n.parent()
343
Full MatrixSpace of 3 by 3 dense matrices over Finite Field in a of size 3^2
344
345
In this example, we explicitly specify the codomain.
346
347
::
348
349
sage: s = GF(3)
350
sage: f = lambda x: s(x)
351
sage: n = m.apply_map(f, k); n
352
[0 1 2]
353
[0 1 2]
354
[0 1 2]
355
sage: n.parent()
356
Full MatrixSpace of 3 by 3 dense matrices over Finite Field in a of size 3^2
357
358
If self is subdivided, the result will be as well::
359
360
sage: m = matrix(2, 2, srange(4))
361
sage: m.subdivide(None, 1); m
362
[0|1]
363
[2|3]
364
sage: m.apply_map(lambda x: x*x)
365
[0|1]
366
[4|9]
367
368
If the map sends most of the matrix to zero, then it may be useful
369
to get the result as a sparse matrix.
370
371
::
372
373
sage: m = matrix(ZZ, 3, 3, range(1, 10))
374
sage: n = m.apply_map(lambda x: 1//x, sparse=True); n
375
[1 0 0]
376
[0 0 0]
377
[0 0 0]
378
sage: n.parent()
379
Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring
380
381
TESTS::
382
383
sage: m = matrix([])
384
sage: m.apply_map(lambda x: x*x) == m
385
True
386
387
sage: m.apply_map(lambda x: x*x, sparse=True).parent()
388
Full MatrixSpace of 0 by 0 sparse matrices over Integer Ring
389
"""
390
if self._nrows==0 or self._ncols==0:
391
if sparse:
392
return self.sparse_matrix()
393
else:
394
return self.__copy__()
395
v = [phi(z) for z in self.list()]
396
if R is None:
397
v = sage.structure.sequence.Sequence(v)
398
R = v.universe()
399
M = sage.matrix.matrix_space.MatrixSpace(R, self._nrows,
400
self._ncols, sparse=sparse)
401
image = M(v)
402
if self._subdivisions is not None:
403
image.subdivide(*self.subdivisions())
404
return image
405
406
def _derivative(self, var=None, R=None):
407
"""
408
Differentiate with respect to var by differentiating each element
409
with respect to var.
410
411
.. seealso::
412
413
:meth:`derivative`
414
415
EXAMPLES::
416
417
sage: m = matrix(2, [x^i for i in range(4)])
418
sage: m._derivative(x)
419
[ 0 1]
420
[ 2*x 3*x^2]
421
"""
422
# We would just use apply_map, except that Cython doesn't
423
# allow lambda functions
424
425
if self._nrows==0 or self._ncols==0:
426
return self.__copy__()
427
v = [z.derivative(var) for z in self.list()]
428
if R is None:
429
v = sage.structure.sequence.Sequence(v)
430
R = v.universe()
431
M = sage.matrix.matrix_space.MatrixSpace(R, self._nrows,
432
self._ncols, sparse=False)
433
image = M(v)
434
if self._subdivisions is not None:
435
image.subdivide(*self.subdivisions())
436
return image
437
438
439