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
7 class MatrixAlgebraElement(IndexedFreeModuleElement
):
9 return self
.parent().nrows()
17 sage: from mjo.matrix_algebra import MatrixAlgebra
21 sage: M = MatrixAlgebra(QQbar,RDF,2)
22 sage: A = M.monomial((0,0,1)) + 4*M.monomial((0,1,1))
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():
42 Display this matrix as a table.
44 The SageMath Matrix class representation is not easily reusable,
45 but using a table fakes it.
49 sage: from mjo.matrix_algebra import MatrixAlgebra
53 sage: MatrixAlgebra(ZZ,ZZ,2).zero()
61 return table(self
.rows(), frame
=True)._repr
_()
66 Return one long list of this matrix's entries.
70 sage: from mjo.matrix_algebra import MatrixAlgebra
74 sage: A = MatrixAlgebra(ZZ,ZZ,2)
75 sage: A([[1,2],[3,4]]).list()
79 return sum( self
.rows(), [] )
82 def __getitem__(self
, indices
):
87 sage: from mjo.matrix_algebra import MatrixAlgebra
91 sage: M = MatrixAlgebra(ZZ,ZZ,2)([[1,2],[3,4]])
103 return self
.rows()[i
][j
]
107 Return the sum of this matrix's diagonal entries.
111 sage: from mjo.matrix_algebra import MatrixAlgebra
115 The trace (being a sum of entries) belongs to the same algebra
116 as those entries, and NOT the scalar ring::
118 sage: entries = MatrixSpace(ZZ,2)
120 sage: M = MatrixAlgebra(entries, scalars, 2)
121 sage: I = entries.one()
122 sage: Z = entries.zero()
123 sage: M([[I,Z],[Z,I]]).trace()
128 zero
= self
.parent().entry_algebra().zero()
129 return sum( (self
[i
,i
] for i
in range(self
.nrows())), zero
)
131 def matrix_space(self
):
136 sage: from mjo.matrix_algebra import MatrixAlgebra
140 sage: set_random_seed()
141 sage: entries = QuaternionAlgebra(QQ,-1,-1)
142 sage: M = MatrixAlgebra(entries, QQ, 3)
143 sage: M.random_element().matrix_space() == M
150 class MatrixAlgebra(CombinatorialFreeModule
):
152 An algebra of ``n``-by-``n`` matrices over an arbitrary scalar
153 ring whose entries come from a magmatic algebra that need not
154 be the same as the scalars.
156 The usual matrix spaces in SageMath don't support separate spaces
157 for the entries and the scalars; in particular they assume that
158 the entries come from a commutative and associative ring. This
159 is problematic in several interesting matrix algebras, like those
160 where the entries are quaternions or octonions.
162 Element
= MatrixAlgebraElement
164 def __init__(self
, entry_algebra
, scalars
, n
, prefix
="A", **kwargs
):
166 category
= MagmaticAlgebras(scalars
).FiniteDimensional()
167 category
= category
.WithBasis()
169 if "Unital" in entry_algebra
.category().axioms():
170 category
= category
.Unital()
171 if "Associative" in entry_algebra
.category().axioms():
172 category
= category
.Associative()
176 # Since the scalar ring is real but the entries are not,
177 # sticking a "1" in each position doesn't give us a basis for
178 # the space. We actually need to stick each of e0, e1, ... (a
179 # basis for the entry algebra itself) into each position.
182 self
._entry
_algebra
= entry_algebra
183 entry_basis
= entry_algebra
.gens()
185 basis_indices
= [(i
,j
,e
) for i
in range(n
)
187 for e
in entry_algebra
.gens()]
189 super().__init
__(scalars
,
196 return ("Module of %d by %d matrices with entries in %s"
197 " over the scalar ring %s" %
200 self
.entry_algebra(),
203 def entry_algebra(self
):
205 Return the algebra that our elements' entries come from.
207 return self
._entry
_algebra
213 def product_on_basis(self
, mon1
, mon2
):
217 return self
.monomial((i
,l
,e1
*e2
))
221 def from_list(self
, entries
):
223 Construct an element of this algebra from a list of lists of
228 sage: from mjo.matrix_algebra import MatrixAlgebra
232 sage: A = MatrixAlgebra(QQbar, ZZ, 2)
233 sage: A.from_list([[0,I],[-I,0]])
244 ncols
= len(entries
[0])
246 if (not all( len(r
) == ncols
for r
in entries
)) or (ncols
!= nrows
):
247 raise ValueError("list must be square")
250 if e_ij
in self
.entry_algebra():
251 # Don't re-create an element if it already lives where
256 # This branch works with e.g. QQbar, where no
257 # to/from_vector() methods are available.
258 return self
.entry_algebra()(e_ij
)
260 # We have to pass through vectors to convert from the
261 # given entry algebra to ours. Otherwise we can fail to
262 # convert an element of (for example) Octonions(QQ) to
264 return self
.entry_algebra().from_vector(e_ij
.to_vector())
266 return sum( (self
.monomial( (i
,j
, convert(entries
[i
][j
])) )
267 for i
in range(nrows
)
268 for j
in range(ncols
) ),
271 def _element_constructor_(self
, elt
):
275 return self
.from_list(elt
)
278 class HurwitzMatrixAlgebraElement(MatrixAlgebraElement
):
279 def is_hermitian(self
):
284 sage: from mjo.matrix_algebra import HurwitzMatrixAlgebra
288 sage: A = HurwitzMatrixAlgebra(QQbar, ZZ, 2)
289 sage: M = A([ [ 0,I],
291 sage: M.is_hermitian()
295 return all( self
[i
,j
] == self
[j
,i
].conjugate()
296 for i
in range(self
.nrows())
297 for j
in range(self
.ncols()) )
300 class HurwitzMatrixAlgebra(MatrixAlgebra
):
301 Element
= HurwitzMatrixAlgebraElement
307 sage: from mjo.matrix_algebra import HurwitzMatrixAlgebra
310 return sum( (self
.monomial((i
,i
,self
.entry_algebra().one()))
311 for i
in range(self
.nrows()) ),