X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Foctonions.py;h=c2b829f98b9b49dbe078172a3669f0cb8b6406e4;hb=ff8c9b19da5ed821366a491a95b4f6c946f315ae;hp=cd25f18a6500b45ce621fa9ae94b6d7c28760750;hpb=61037c13a8d4988428aeb79b383f3b45dbad8778;p=sage.d.git diff --git a/mjo/octonions.py b/mjo/octonions.py index cd25f18..c2b829f 100644 --- a/mjo/octonions.py +++ b/mjo/octonions.py @@ -1,3 +1,4 @@ +from sage.misc.cachefunc import cached_method from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra from sage.combinat.free_module import CombinatorialFreeModule from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement @@ -336,3 +337,290 @@ class Octonions(CombinatorialFreeModule): for i in range(n) ] return table(M, header_row=True, header_column=True, frame=True) + + +class OctonionMatrix(IndexedFreeModuleElement): + def nrows(self): + return self.parent().nrows() + ncols = nrows + + @cached_method + def to_nested_list(self): + r""" + SETUP:: + + sage: from mjo.octonions import OctonionMatrixAlgebra + + EXAMPLES:: + + sage: MS = OctonionMatrixAlgebra(3) + sage: E00e0 = MS.gens()[0] + sage: E00e0 + +----+---+---+ + | e0 | 0 | 0 | + +----+---+---+ + | 0 | 0 | 0 | + +----+---+---+ + | 0 | 0 | 0 | + +----+---+---+ + sage: E00e3 = MS.gens()[3] + sage: E00e3 + +----+---+---+ + | e3 | 0 | 0 | + +----+---+---+ + | 0 | 0 | 0 | + +----+---+---+ + | 0 | 0 | 0 | + +----+---+---+ + sage: (E00e0 + 2*E00e3).to_nested_list() + [[e0 + 2*e3, 0, 0], [0, 0, 0], [0, 0, 0]] + + """ + zero = self.parent().octonions().zero() + l = [[zero for j in range(self.ncols())] for i in range(self.nrows())] + for (k,v) in self.monomial_coefficients().items(): + (i,j,e) = k + l[i][j] += v*e + return l + + def __repr__(self): + r""" + SETUP:: + + sage: from mjo.octonions import OctonionMatrixAlgebra + + EXAMPLES:: + + sage: OctonionMatrixAlgebra(3).one() + +----+----+----+ + | e0 | 0 | 0 | + +----+----+----+ + | 0 | e0 | 0 | + +----+----+----+ + | 0 | 0 | e0 | + +----+----+----+ + + """ + return table(self.to_nested_list(), frame=True)._repr_() + + + def list(self): + r""" + Return one long list of this matrix's entries. + + SETUP:: + + sage: from mjo.octonions import OctonionMatrixAlgebra + + EXAMPLES:: + + sage: MS = OctonionMatrixAlgebra(3) + sage: E00e0 = MS.gens()[0] + sage: E00e3 = MS.gens()[3] + sage: (E00e0 + 2*E00e3).to_nested_list() + [[e0 + 2*e3, 0, 0], [0, 0, 0], [0, 0, 0]] + sage: (E00e0 + 2*E00e3).list() + [e0 + 2*e3, 0, 0, 0, 0, 0, 0, 0, 0] + + """ + return sum( self.to_nested_list(), [] ) + + + def __getitem__(self, indices): + r""" + + SETUP:: + + sage: from mjo.octonions import OctonionMatrixAlgebra + + EXAMPLES:: + + sage: MS = OctonionMatrixAlgebra(2) + sage: I = MS.one() + sage: I[0,0] + e0 + sage: I[0,1] + 0 + sage: I[1,0] + 0 + sage: I[1,1] + e0 + + """ + i,j = indices + return self.to_nested_list()[i][j] + + def trace(self): + r""" + + SETUP:: + + sage: from mjo.octonions import OctonionMatrixAlgebra + + EXAMPLES:: + + sage: MS = OctonionMatrixAlgebra(3) + sage: MS.one().trace() + 3*e0 + + """ + zero = self.parent().octonions().zero() + return sum( (self[i,i] for i in range(self.nrows())), zero ) + + def matrix_space(self): + r""" + + SETUP:: + + sage: from mjo.octonions import OctonionMatrixAlgebra + + TESTS:: + + sage: set_random_seed() + sage: MS = OctonionMatrixAlgebra(2) + sage: MS.random_element().matrix_space() + Module of 2 by 2 matrices with octonion entries over the + scalar ring Algebraic Real Field + + """ + return self.parent() + + def is_hermitian(self): + r""" + + SETUP:: + + sage: from mjo.octonions import OctonionMatrixAlgebra + + EXAMPLES:: + + sage: MS = OctonionMatrixAlgebra(3) + sage: MS.one().is_hermitian() + True + + """ + return all( self[i,j] == self[j,i].conjugate() + for i in range(self.nrows()) + for j in range(self.ncols()) ) + +class OctonionMatrixAlgebra(CombinatorialFreeModule): + r""" + The algebra of ``n``-by-``n`` matrices with octonion entries over + (a subfield of) the real numbers. + + The usual matrix spaces in SageMath don't support octonion entries + because they assume that the entries of the matrix come from a + commutative and associative ring (i.e. very NOT the octonions). + """ + Element = OctonionMatrix + + def __init__(self, n, field=AA, prefix="E", **kwargs): + # Not associative, not commutative + category = MagmaticAlgebras(field).FiniteDimensional() + category = category.WithBasis().Unital() + + self._nrows = n + + # Since the scalar field is real but the entries are octonion, + # sticking a "1" in each position doesn't give us a basis for + # the space. We actually need to stick each of e0, e1, ..., e7 + # (a basis for the Octonions themselves) into each position. + from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + from sage.categories.sets_cat import cartesian_product + + I = FiniteEnumeratedSet(range(n)) + J = FiniteEnumeratedSet(range(n)) + self._octonions = Octonions(field=field) + entry_basis = self._octonions.gens() + + basis_indices = cartesian_product([I,J,entry_basis]) + super().__init__(field, + basis_indices, + category=category, + prefix=prefix, + bracket='(') + + def _repr_(self): + return ("Module of %d by %d matrices with octonion entries" + " over the scalar ring %s" % + (self.nrows(), self.ncols(), self.base_ring()) ) + + def octonions(self): + r""" + Return the Octonion algebra that our elements' entries come from. + """ + return self._octonions + + def nrows(self): + return self._nrows + ncols = nrows + + def product_on_basis(self, mon1, mon2): + (i,j,oct1) = mon1 + (k,l,oct2) = mon2 + if j == k: + return self.monomial((i,l,oct1*oct2)) + else: + return self.zero() + + def one(self): + r""" + SETUP:: + + sage: from mjo.octonions import OctonionMatrixAlgebra + + TESTS:: + + sage: set_random_seed() + sage: MS = OctonionMatrixAlgebra(ZZ.random_element(10)) + sage: x = MS.random_element() + sage: x*MS.one() == x and MS.one()*x == x + True + + """ + return sum( (self.monomial((i,i,self._octonions.one())) + for i in range(self.nrows()) ), + self.zero() ) + + def from_list(self, entries): + r""" + Construct an element of this algebra from a list of lists of + octonions. + + SETUP:: + + sage: from mjo.octonions import Octonions, OctonionMatrixAlgebra + + EXAMPLES:: + + sage: O = Octonions(QQ) + sage: e0,e1,e2,e3,e4,e5,e6,e7 = O.gens() + sage: MS = OctonionMatrixAlgebra(2) + sage: MS.from_list([ [e0+e4, e1+e5], + ....: [e2-e6, e3-e7] ]) + +---------+---------+ + | e0 + e4 | e1 + e5 | + +---------+---------+ + | e2 - e6 | e3 - e7 | + +---------+---------+ + + """ + nrows = len(entries) + ncols = 0 + if nrows > 0: + ncols = len(entries[0]) + + if (not all( len(r) == ncols for r in entries )) or (ncols != nrows): + raise ValueError("list must be square") + + def convert(e_ij): + # We have to pass through vectors to convert from the + # given octonion algebra to ours. Otherwise we can fail + # to convert an element of (for example) Octonions(QQ) + # to Octonions(AA). + return self.octonions().from_vector(e_ij.to_vector()) + + return sum( (self.monomial( (i,j, convert(entries[i][j])) ) + for i in range(nrows) + for j in range(ncols) ), + self.zero() )