]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/matrix_algebra.py
668a1c44d839e6b5704aa72acb90970136eca571
[sage.d.git] / mjo / matrix_algebra.py
1 from sage.misc.table import table
2 from sage.categories.magmatic_algebras import MagmaticAlgebras
3 from sage.misc.cachefunc import cached_method
4 from sage.combinat.free_module import CombinatorialFreeModule
5 from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement
6
7 class MatrixAlgebraElement(IndexedFreeModuleElement):
8 def nrows(self):
9 return self.parent().nrows()
10 ncols = nrows
11
12 @cached_method
13 def rows(self):
14 r"""
15 SETUP::
16
17 sage: from mjo.matrix_algebra import MatrixAlgebra
18
19 EXAMPLES::
20
21 sage: M = MatrixAlgebra(QQbar,RDF,2)
22 sage: A = M.monomial((0,0,1)) + 4*M.monomial((0,1,1))
23 sage: A
24 +-----+-----+
25 | 1.0 | 4.0 |
26 +-----+-----+
27 | 0 | 0 |
28 +-----+-----+
29 sage: A.rows()
30 [[1.0, 4.0], [0, 0]]
31
32 """
33 zero = self.parent().entry_algebra().zero()
34 l = [[zero for j in range(self.ncols())] for i in range(self.nrows())]
35 for (k,v) in self.monomial_coefficients().items():
36 (i,j,e) = k
37 l[i][j] += v*e
38 return l
39
40 def __repr__(self):
41 r"""
42 Display this matrix as a table.
43
44 The SageMath Matrix class representation is not easily reusable,
45 but using a table fakes it.
46
47 SETUP::
48
49 sage: from mjo.matrix_algebra import MatrixAlgebra
50
51 EXAMPLES::
52
53 sage: MatrixAlgebra(ZZ,ZZ,2).one()
54 +---+---+
55 | 1 | 0 |
56 +---+---+
57 | 0 | 1 |
58 +---+---+
59
60 """
61 return table(self.rows(), frame=True)._repr_()
62
63
64 def list(self):
65 r"""
66 Return one long list of this matrix's entries.
67
68 SETUP::
69
70 sage: from mjo.matrix_algebra import MatrixAlgebra
71
72 EXAMPLES::
73
74 sage: MatrixAlgebra(ZZ,ZZ,2).one().list()
75 [1, 0, 0, 1]
76
77 """
78 return sum( self.rows(), [] )
79
80
81 def __getitem__(self, indices):
82 r"""
83
84 SETUP::
85
86 sage: from mjo.matrix_algebra import MatrixAlgebra
87
88 EXAMPLES::
89
90 sage: M = MatrixAlgebra(ZZ,ZZ,2).one()
91 sage: M[0,0]
92 1
93 sage: M[0,1]
94 0
95 sage: M[1,0]
96 0
97 sage: M[1,1]
98 1
99
100 """
101 i,j = indices
102 return self.rows()[i][j]
103
104 def trace(self):
105 r"""
106 Return the sum of this matrix's diagonal entries.
107
108 SETUP::
109
110 sage: from mjo.matrix_algebra import MatrixAlgebra
111
112 EXAMPLES:
113
114 The trace (being a sum of entries) belongs to the same algebra
115 as those entries, and NOT the scalar ring::
116
117 sage: entries = MatrixSpace(ZZ,2)
118 sage: scalars = ZZ
119 sage: M = MatrixAlgebra(entries, scalars, 2)
120 sage: M.one().trace()
121 [2 0]
122 [0 2]
123
124 """
125 zero = self.parent().entry_algebra().zero()
126 return sum( (self[i,i] for i in range(self.nrows())), zero )
127
128 def matrix_space(self):
129 r"""
130
131 SETUP::
132
133 sage: from mjo.matrix_algebra import MatrixAlgebra
134
135 TESTS::
136
137 sage: set_random_seed()
138 sage: entries = QuaternionAlgebra(QQ,-1,-1)
139 sage: M = MatrixAlgebra(entries, QQ, 3)
140 sage: M.random_element().matrix_space() == M
141 True
142
143 """
144 return self.parent()
145
146 # onlt valid in HurwitzMatrixAlgebra subclass
147 # def is_hermitian(self):
148 # r"""
149
150 # SETUP::
151
152 # sage: from mjo.octonions import OctonionMatrixAlgebra
153
154 # EXAMPLES::
155
156 # sage: MS = OctonionMatrixAlgebra(3)
157 # sage: MS.one().is_hermitian()
158 # True
159
160 # """
161 # return all( self[i,j] == self[j,i].conjugate()
162 # for i in range(self.nrows())
163 # for j in range(self.ncols()) )
164
165
166 class MatrixAlgebra(CombinatorialFreeModule):
167 r"""
168 An algebra of ``n``-by-``n`` matrices over an arbitrary scalar
169 ring whose entries come from a magmatic algebra that need not
170 be the same as the scalars.
171
172 The usual matrix spaces in SageMath don't support separate spaces
173 for the entries and the scalars; in particular they assume that
174 the entries come from a commutative and associative ring. This
175 is problematic in several interesting matrix algebras, like those
176 where the entries are quaternions or octonions.
177 """
178 Element = MatrixAlgebraElement
179
180 def __init__(self, entry_algebra, scalars, n, prefix="A", **kwargs):
181
182 category = MagmaticAlgebras(scalars).FiniteDimensional()
183 category = category.WithBasis()
184
185 if "Unital" in entry_algebra.category().axioms():
186 category = category.Unital()
187 if "Associative" in entry_algebra.category().axioms():
188 category = category.Associative()
189
190 self._nrows = n
191
192 # Since the scalar ring is real but the entries are not,
193 # sticking a "1" in each position doesn't give us a basis for
194 # the space. We actually need to stick each of e0, e1, ... (a
195 # basis for the entry algebra itself) into each position.
196 I = range(n)
197 J = range(n)
198 self._entry_algebra = entry_algebra
199 entry_basis = entry_algebra.gens()
200
201 basis_indices = [(i,j,e) for i in range(n)
202 for j in range(n)
203 for e in entry_algebra.gens()]
204
205 super().__init__(scalars,
206 basis_indices,
207 category=category,
208 prefix=prefix,
209 bracket='(')
210
211 def _repr_(self):
212 return ("Module of %d by %d matrices with entries in %s"
213 " over the scalar ring %s" %
214 (self.nrows(),
215 self.ncols(),
216 self.entry_algebra(),
217 self.base_ring()) )
218
219 def entry_algebra(self):
220 r"""
221 Return the algebra that our elements' entries come from.
222 """
223 return self._entry_algebra
224
225 def nrows(self):
226 return self._nrows
227 ncols = nrows
228
229 def product_on_basis(self, mon1, mon2):
230 (i,j,e1) = mon1
231 (k,l,e2) = mon2
232 if j == k:
233 return self.monomial((i,l,e1*e2))
234 else:
235 return self.zero()
236
237 # TODO: only makes sense if I'm unital.
238 def one(self):
239 r"""
240 SETUP::
241
242 sage: from mjo.matrix_algebra import MatrixAlgebra
243
244 """
245 return sum( (self.monomial((i,i,self.entry_algebra().one()))
246 for i in range(self.nrows()) ),
247 self.zero() )
248
249 def from_list(self, entries):
250 r"""
251 Construct an element of this algebra from a list of lists of
252 entries.
253
254 SETUP::
255
256 sage: from mjo.matrix_algebra import MatrixAlgebra
257
258 """
259 nrows = len(entries)
260 ncols = 0
261 if nrows > 0:
262 ncols = len(entries[0])
263
264 if (not all( len(r) == ncols for r in entries )) or (ncols != nrows):
265 raise ValueError("list must be square")
266
267 def convert(e_ij):
268 # We have to pass through vectors to convert from the
269 # given entry algebra to ours. Otherwise we can fail
270 # to convert an element of (for example) Octonions(QQ)
271 # to Octonions(AA).
272 return self.entry_algebra().from_vector(e_ij.to_vector())
273
274 return sum( (self.monomial( (i,j, convert(entries[i][j])) )
275 for i in range(nrows)
276 for j in range(ncols) ),
277 self.zero() )