]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/matrix_algebra.py
matrix_algebra: fix conditional categories.
[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 from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
197 from sage.categories.sets_cat import cartesian_product
198
199 I = FiniteEnumeratedSet(range(n))
200 J = FiniteEnumeratedSet(range(n))
201 self._entry_algebra = entry_algebra
202 entry_basis = entry_algebra.gens()
203
204 basis_indices = cartesian_product([I,J,entry_basis])
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,oct1) = mon1
231 (k,l,oct2) = mon2
232 if j == k:
233 return self.monomial((i,l,oct1*oct2))
234 else:
235 return self.zero()
236
237 def one(self):
238 r"""
239 SETUP::
240
241 sage: from mjo.matrix_algebra import MatrixAlgebra
242
243 """
244 return sum( (self.monomial((i,i,self.entry_algebra().one()))
245 for i in range(self.nrows()) ),
246 self.zero() )
247
248 def from_list(self, entries):
249 r"""
250 Construct an element of this algebra from a list of lists of
251 entries.
252
253 SETUP::
254
255 sage: from mjo.matrix_algebra import MatrixAlgebra
256
257 """
258 nrows = len(entries)
259 ncols = 0
260 if nrows > 0:
261 ncols = len(entries[0])
262
263 if (not all( len(r) == ncols for r in entries )) or (ncols != nrows):
264 raise ValueError("list must be square")
265
266 def convert(e_ij):
267 # We have to pass through vectors to convert from the
268 # given entry algebra to ours. Otherwise we can fail
269 # to convert an element of (for example) Octonions(QQ)
270 # to Octonions(AA).
271 return self.entry_algebra().from_vector(e_ij.to_vector())
272
273 return sum( (self.monomial( (i,j, convert(entries[i][j])) )
274 for i in range(nrows)
275 for j in range(ncols) ),
276 self.zero() )