Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/matrix/action.pyx
8815 views
1
"""
2
These are the actions used by the coercion model for matrix and vector
3
multiplications.
4
5
.. WARNING::
6
7
The class :class:`MatrixMulAction` and its descendants extends the class
8
:class:`Action`. As a cosnequence objects from these classes only keep weak
9
references to the underlying sets which are acted upon. This decision was
10
made in :trac:`715` in order to allow garbage collection within the coercion
11
framework, where actions are mainly used, and avoid memory leaks.
12
13
To ensure that the underlying set of such an object does not get garbage
14
collected, it is sufficient to explicitely create a strong reference to it
15
before creating the action.
16
17
::
18
19
sage: MSQ = MatrixSpace(QQ, 2)
20
sage: MSZ = MatrixSpace(ZZ['x'], 2)
21
sage: A = MSQ.get_action(MSZ)
22
sage: A
23
Left action by Full MatrixSpace of 2 by 2 dense matrices over Rational Field on Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring
24
sage: import gc
25
sage: _ = gc.collect()
26
sage: A
27
Left action by Full MatrixSpace of 2 by 2 dense matrices over Rational Field on Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring
28
29
.. NOTE::
30
31
The :func:`MatrixSpace` function caches the objects it creates. Therefore,
32
the underlying set ``MSZ`` in the above example will not be garbage
33
collected, even if it is not strongly ref'ed. Nonetheless, there is no
34
guarantee that the set that is acted upon will always be cached in such a
35
way, so that following the above example is good practice.
36
37
AUTHOR:
38
39
- Robert Bradshaw (2007-09): Initial version.
40
"""
41
42
#*****************************************************************************
43
# Copyright (C) 2007 Robert Bradshaw <[email protected]>
44
#
45
# Distributed under the terms of the GNU General Public License (GPL)
46
#
47
# http://www.gnu.org/licenses/
48
#*****************************************************************************
49
50
51
import operator
52
53
from matrix_space import MatrixSpace, is_MatrixSpace
54
from sage.modules.free_module import FreeModule, is_FreeModule
55
56
57
cdef class MatrixMulAction(Action):
58
def __init__(self, G, S, is_left):
59
if not is_MatrixSpace(G):
60
raise TypeError, "Not a matrix space: %s" % G
61
if G.base_ring() is not S.base_ring():
62
from sage.categories.pushout import pushout
63
base = pushout(G.base_ring(), S.base_ring())
64
else:
65
base = G.base_ring()
66
Action.__init__(self, G, S, is_left, operator.mul)
67
self._codomain = self._create_codomain(base)
68
self.fix_sparseness = G.is_sparse() != S.is_sparse()
69
70
def codomain(self):
71
return self._codomain
72
73
def domain(self):
74
"""
75
EXAMPLES:
76
77
By :trac:`715`, there only is a weak reference on the underlying set,
78
so that it can be garbage collected if only the action itself is
79
explicitly referred to. Hence, we first assign the involved matrix
80
spaces to a variable::
81
82
sage: MSQ = MatrixSpace(QQ, 2)
83
sage: MSZ = MatrixSpace(ZZ['x'], 2)
84
sage: A = MSQ.get_action(MSZ); A
85
Left action by Full MatrixSpace of 2 by 2 dense matrices over Rational Field on Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring
86
sage: A.actor()
87
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
88
sage: A.domain()
89
Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring
90
sage: A.codomain()
91
Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field
92
93
.. NOTE::
94
95
The :func:`MatrixSpace` function caches the object it creates.
96
Therefore, the underlying set ``MSZ`` in the above example will not
97
be garbage collected, even if it is not strongly ref'ed.
98
Nonetheless, there is no guarantee that the set that is acted upon
99
will always be cached in such a way, so that following the above
100
example is good practice.
101
102
"""
103
return self.underlying_set()
104
105
106
cdef class MatrixMatrixAction(MatrixMulAction):
107
def __init__(self, G, S):
108
"""
109
EXAMPLES:
110
111
By :trac:`715`, there only is a weak reference on the underlying set,
112
so that it can be garbage collected if only the action itself is
113
explicitly referred to. Hence, we first assign the involved matrix
114
spaces to a variable::
115
116
sage: R.<x> = ZZ[]
117
sage: MSR = MatrixSpace(R, 3, 3)
118
sage: MSQ = MatrixSpace(QQ, 3, 2)
119
sage: from sage.matrix.action import MatrixMatrixAction
120
sage: A = MatrixMatrixAction(MSR, MSQ); A
121
Left action by Full MatrixSpace of 3 by 3 dense matrices over Univariate Polynomial Ring in x over Integer Ring on Full MatrixSpace of 3 by 2 dense matrices over Rational Field
122
sage: A.codomain()
123
Full MatrixSpace of 3 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field
124
sage: A(matrix(R, 3, 3, x), matrix(QQ, 3, 2, range(6)))
125
[ 0 x]
126
[2*x 3*x]
127
[4*x 5*x]
128
129
.. NOTE::
130
131
The :func:`MatrixSpace` function caches the object it creates.
132
Therefore, the underlying set ``MSZ`` in the above example will not
133
be garbage collected, even if it is not strongly ref'ed.
134
Nonetheless, there is no guarantee that the set that is acted upon
135
will always be cached in such a way, so that following the above
136
example is good practice.
137
138
"""
139
if not is_MatrixSpace(S):
140
raise TypeError, "Not a matrix space: %s" % S
141
MatrixMulAction.__init__(self, G, S, True)
142
143
def _create_codomain(self, base):
144
"""
145
EXAMPLES:
146
147
By :trac:`715`, there only is a weak reference on the underlying set,
148
so that it can be garbage collected if only the action itself is
149
explicitly referred to. Hence, we first assign the involved matrix
150
spaces to a variable::
151
152
sage: from sage.matrix.action import MatrixMatrixAction
153
sage: R.<x> = ZZ[]
154
sage: MSR = MatrixSpace(R, 3, 3)
155
sage: MSQ = MatrixSpace(QQ, 3, 2)
156
sage: A = MatrixMatrixAction(MSR, MSQ); A
157
Left action by Full MatrixSpace of 3 by 3 dense matrices over Univariate Polynomial Ring in x over Integer Ring on Full MatrixSpace of 3 by 2 dense matrices over Rational Field
158
sage: A.codomain()
159
Full MatrixSpace of 3 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field
160
161
.. NOTE::
162
163
The :func:`MatrixSpace` function caches the object it creates.
164
Therefore, the underlying set ``MSZ`` in the above example will not
165
be garbage collected, even if it is not strongly ref'ed.
166
Nonetheless, there is no guarantee that the set that is acted upon
167
will always be cached in such a way, so that following the above
168
example is good practice.
169
170
"""
171
if self.G.ncols() != self.underlying_set().nrows():
172
raise TypeError, "incompatible dimensions %s, %s" % (self.G.ncols(), self.underlying_set().nrows())
173
return MatrixSpace(base, self.G.nrows(), self.underlying_set().ncols(),
174
sparse = self.G.is_sparse() and self.underlying_set().is_sparse())
175
176
cpdef _call_(self, g, s):
177
"""
178
EXAMPLES:
179
180
Respects compatible subdivisions::
181
182
sage: M = matrix(5, 5, prime_range(100))
183
sage: M.subdivide(2,3); M
184
[ 2 3 5| 7 11]
185
[13 17 19|23 29]
186
[--------+-----]
187
[31 37 41|43 47]
188
[53 59 61|67 71]
189
[73 79 83|89 97]
190
sage: N = matrix(5,2,[n^2 for n in range(10)])
191
sage: N.subdivide(3,1); N
192
[ 0| 1]
193
[ 4| 9]
194
[16|25]
195
[--+--]
196
[36|49]
197
[64|81]
198
sage: M*N
199
[ 1048| 1388]
200
[ 3056| 4117]
201
[-----+-----]
202
[ 5360| 7303]
203
[ 8168|11143]
204
[11056|15077]
205
206
Note that this is just like block matrix multiplication::
207
208
sage: M.subdivision(0,0) * N.subdivision(0,0) + M.subdivision(0,1) * N.subdivision(1,0)
209
[1048]
210
[3056]
211
212
If the subdivisions aren't compatible, ignore them.
213
::
214
215
sage: N.subdivide(1,1); N
216
[ 0| 1]
217
[--+--]
218
[ 4| 9]
219
[16|25]
220
[36|49]
221
[64|81]
222
sage: M*N
223
[ 1048 1388]
224
[ 3056 4117]
225
[ 5360 7303]
226
[ 8168 11143]
227
[11056 15077]
228
229
"""
230
cdef Matrix A = g #<Matrix>g
231
cdef Matrix B = s #<Matrix>s
232
if A._parent._base is not self._codomain._base:
233
A = A.change_ring(self._codomain._base)
234
if B._parent._base is not self._codomain._base:
235
B = B.change_ring(self._codomain._base)
236
if self.fix_sparseness:
237
if B.is_sparse_c():
238
B = B.dense_matrix()
239
else:
240
A = A.dense_matrix()
241
prod = A._matrix_times_matrix_(B)
242
if A._subdivisions is not None or B._subdivisions is not None:
243
Asubs = A.subdivisions()
244
Bsubs = B.subdivisions()
245
if Asubs[1] == Bsubs[0]:
246
prod.subdivide(Asubs[0], Bsubs[1])
247
return prod
248
249
250
cdef class MatrixVectorAction(MatrixMulAction):
251
def __init__(self, G, S):
252
"""
253
EXAMPLES::
254
255
sage: from sage.matrix.action import MatrixVectorAction
256
sage: A = MatrixVectorAction(MatrixSpace(QQ, 3, 3), VectorSpace(CDF, 4)); A
257
Traceback (most recent call last):
258
...
259
TypeError: incompatible dimensions 3, 4
260
"""
261
if not is_FreeModule(S):
262
raise TypeError, "Not a free module: %s" % S
263
MatrixMulAction.__init__(self, G, S, True)
264
265
def _create_codomain(self, base):
266
"""
267
EXAMPLES::
268
269
sage: from sage.matrix.action import MatrixVectorAction
270
sage: A = MatrixVectorAction(MatrixSpace(QQ, 5, 3), VectorSpace(CDF, 3)); A
271
Left action by Full MatrixSpace of 5 by 3 dense matrices over Rational Field on Vector space of dimension 3 over Complex Double Field
272
sage: A.codomain()
273
Vector space of dimension 5 over Complex Double Field
274
"""
275
if self.G.ncols() != self.underlying_set().degree():
276
raise TypeError, "incompatible dimensions %s, %s" % (self.G.ncols(),
277
self.underlying_set().degree())
278
return FreeModule(base, self.G.nrows(), sparse = self.G.is_sparse())
279
280
cpdef _call_(self, g, s):
281
cdef Matrix A = g #<Matrix>g
282
cdef Vector v = s #<Vector>s
283
if A._parent._base is not self._codomain._base:
284
A = A.change_ring(self._codomain._base)
285
if v._parent._base is not self._codomain._base:
286
v = v.change_ring(self._codomain._base)
287
if self.fix_sparseness:
288
if A.is_sparse_c():
289
v = v.sparse_vector()
290
else:
291
v = v.dense_vector()
292
return A._matrix_times_vector_(v)
293
294
295
cdef class VectorMatrixAction(MatrixMulAction):
296
def __init__(self, G, S):
297
"""
298
EXAMPLES::
299
300
sage: from sage.matrix.action import VectorMatrixAction
301
sage: A = VectorMatrixAction(MatrixSpace(QQ, 5, 3), VectorSpace(CDF, 3)); A
302
Traceback (most recent call last):
303
...
304
TypeError: incompatible dimensions 5, 3
305
"""
306
if not is_FreeModule(S):
307
raise TypeError, "Not a free module: %s" % S
308
MatrixMulAction.__init__(self, G, S, False)
309
310
def _create_codomain(self, base):
311
"""
312
EXAMPLES::
313
314
sage: from sage.matrix.action import VectorMatrixAction
315
sage: A = VectorMatrixAction(MatrixSpace(QQ, 3, 5), VectorSpace(CDF, 3)); A
316
Right action by Full MatrixSpace of 3 by 5 dense matrices over Rational Field on Vector space of dimension 3 over Complex Double Field
317
sage: A.codomain()
318
Vector space of dimension 5 over Complex Double Field
319
"""
320
if self.G.nrows() != self.underlying_set().degree():
321
raise TypeError, "incompatible dimensions %s, %s" % (self.G.nrows(),
322
self.underlying_set().degree())
323
return FreeModule(base, self.G.ncols(), sparse = self.G.is_sparse())
324
325
cpdef _call_(self, s, g):
326
cdef Matrix A = g #<Matrix>g
327
cdef Vector v = s #<Vector>s
328
if A._parent._base is not self._codomain._base:
329
A = A.change_ring(self._codomain._base)
330
if v._parent._base is not self._codomain._base:
331
v = v.change_ring(self._codomain._base)
332
if self.fix_sparseness:
333
if A.is_sparse_c():
334
v = v.sparse_vector()
335
else:
336
v = v.dense_vector()
337
return (<Matrix>A)._vector_times_matrix_(v) # v * A
338
339
340