X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Foctonions.py;h=fb4b83396ea4d8bcac0bd058eae6406381b0eccc;hb=7f8c5e957f3449ad73be895a5f88e889168732f9;hp=3c3f47418b1186147ddcf3efc47f3b5dc5b969ee;hpb=04db87da2d505376f168cb14fa5eb9d0a73e4ca7;p=sage.d.git diff --git a/mjo/octonions.py b/mjo/octonions.py index 3c3f474..fb4b833 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 @@ -6,6 +7,8 @@ from sage.rings.all import AA, ZZ from sage.matrix.matrix_space import MatrixSpace from sage.misc.table import table +from mjo.matrix_algebra import HurwitzMatrixAlgebra + class Octonion(IndexedFreeModuleElement): def conjugate(self): r""" @@ -138,6 +141,11 @@ class Octonion(IndexedFreeModuleElement): """ return self._norm_squared().sqrt() + # The absolute value notation is typically used for complex numbers... + # and norm() isn't supported in AA, so this lets us use abs() in all + # of the division algebras we need. + abs = norm + def inverse(self): r""" Return the inverse of this element if it exists. @@ -338,202 +346,54 @@ class Octonions(CombinatorialFreeModule): return table(M, header_row=True, header_column=True, frame=True) -class OctonionMatrix: - r""" - A pseudo-matrix class that supports octonion entries. - - Matrices in SageMath can't have base rings that are - non-commutative, much less non-associative. The "matrix" scaling, - addition, and multiplication operations for this class are all - wholly inefficient, but are hand-written to guarantee that they - are performed in the correct order. Of course, it can't guarantee - that you won't write something visually ambiguous like - `A*B*C`... but you already have that problem with the - non-associative octonions themselves. - - This class is only as sophisticated as it need to be to implement - the Jordan and inner-products in the space of Hermitian matrices - with octonion entries, namely ``(X*Y+Y*X)/2`` and - ``(X*Y).trace().real()`` for two octonion matrices ``X`` and - ``Y``. - - .. WARNING: - - These are not matrices in the usual sense! Matrix - multiplication is associative. Multiplication of octonion - "matrices" cannot be, since the multiplication of the - underlying octonions is not (consider two 1-by-1 matrices each - containing a single octonion). - """ - def __init__(self, entries): - r""" - Initialize this matrix with a list of lists in (row,column) order, - just like in SageMath. - """ - self._nrows = len(entries) - - if self._nrows == 0: - self._ncols = 0 - else: - # We don't check that you haven't supplied two rows (or - # columns) of different lengths! - self._ncols = len(entries[0]) - - self._entries = entries - - def __getitem__(self, indices): - r""" - SETUP:: - - sage: from mjo.octonions import Octonions, OctonionMatrix - - EXAMPLES:: - - sage: O = Octonions(field=QQ) - sage: M = OctonionMatrix([ [O.one(), O.zero()], - ....: [O.zero(), O.one() ] ]) - sage: M[0,0] - e0 - sage: M[0,1] - 0 - sage: M[1,0] - 0 - sage: M[1,1] - e0 - """ - i,j = indices - return self._entries[i][j] - - def nrows(self): - r""" - SETUP:: - - sage: from mjo.octonions import Octonions, OctonionMatrix - - EXAMPLES:: - - sage: O = Octonions(field=QQ) - sage: M = OctonionMatrix([ [O.one(), O.zero()], - ....: [O.zero(), O.one() ], - ....: [O.zero(), O.zero()] ]) - sage: M.nrows() - 3 - - """ - return self._nrows - - def ncols(self): - r""" - - SETUP:: - - sage: from mjo.octonions import Octonions, OctonionMatrix - - EXAMPLES:: - sage: O = Octonions(field=QQ) - sage: M = OctonionMatrix([ [O.one(), O.zero()], - ....: [O.zero(), O.one() ], - ....: [O.zero(), O.zero()] ]) - sage: M.ncols() - 2 - - """ - return self._ncols - - def __repr__(self): - return table(self._entries, frame=True)._repr_() - - def __mul__(self,rhs): - r""" - - SETUP:: - - sage: from mjo.octonions import Octonions, OctonionMatrix - - EXAMPLES:: - - sage: O = Octonions(QQ) - sage: e1 = O.monomial(1) - sage: e2 = O.monomial(2) - sage: e1*e2 - e3 - sage: e2*e1 - -e3 - sage: E1 = OctonionMatrix([[e1]]) - sage: E2 = OctonionMatrix([[e2]]) - sage: E1*E2 - +----+ - | e3 | - +----+ - sage: E2*E1 - +-----+ - | -e3 | - +-----+ - - """ - if not self.ncols() == rhs.nrows(): - raise ValueError("dimension mismatch") - - m = self.nrows() - n = self.ncols() - p = rhs.ncols() - - C = lambda i,j: sum( self[i,k]*rhs[k,j] for k in range(n) ) - return OctonionMatrix([ [C(i,j) for j in range(m)] - for i in range(p) ] ) - - def __rmul__(self,scalar): - r""" - - SETUP:: - - sage: from mjo.octonions import Octonions, OctonionMatrix - - EXAMPLES:: - - sage: O = Octonions(QQ) - sage: M = OctonionMatrix([[O.one(), O.zero()], - ....: [O.zero(),O.one() ] ]) - sage: 2*M - +------+------+ - | 2*e0 | 0 | - +------+------+ - | 0 | 2*e0 | - +------+------+ +class OctonionMatrixAlgebra(HurwitzMatrixAlgebra): + r""" + The algebra of ``n``-by-``n`` matrices with octonion entries over + (a subfield of) the real numbers. - r""" - # SCALAR GOES ON THE LEFT HERE - return OctonionMatrix([ [scalar*self[i,j] - for j in range(self.ncols())] - for i in range(self.nrows()) ]) + 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). - def __add__(self,rhs): - r""" - SETUP:: + SETUP:: - sage: from mjo.octonions import Octonions, OctonionMatrix + sage: from mjo.octonions import Octonions, OctonionMatrixAlgebra - EXAMPLES:: + EXAMPLES:: - sage: O = Octonions(QQ) - sage: e0,e1,e2,e3,e4,e5,e6,e7 = O.gens() - sage: A = OctonionMatrix([ [e0,e1], - ....: [e2,e3] ]) - sage: B = OctonionMatrix([ [e4,e5], - ....: [e6,e7] ]) - sage: A+B - +---------+---------+ - | e0 + e4 | e1 + e5 | - +---------+---------+ - | e2 + e6 | e3 + e7 | - +---------+---------+ + sage: OctonionMatrixAlgebra(3) + Module of 3 by 3 matrices with entries in Octonion algebra with base + ring Algebraic Real Field over the scalar ring Algebraic Real Field + sage: OctonionMatrixAlgebra(3,QQ) + Module of 3 by 3 matrices with entries in Octonion algebra with base + ring Rational Field over the scalar ring Rational Field + + :: + + sage: O = Octonions(QQ) + sage: e0,e1,e2,e3,e4,e5,e6,e7 = O.gens() + sage: MS = OctonionMatrixAlgebra(2) + sage: MS([ [e0+e4, e1+e5], + ....: [e2-e6, e3-e7] ]) + +---------+---------+ + | e0 + e4 | e1 + e5 | + +---------+---------+ + | e2 - e6 | e3 - e7 | + +---------+---------+ + + 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 - """ - if not self.ncols() == rhs.ncols(): - raise ValueError("column dimension mismatch") - if not self.nrows() == rhs.nrows(): - raise ValueError("row dimension mismatch") - return OctonionMatrix([ [self[i,j] + rhs[i,j] - for j in range(self.ncols())] - for i in range(self.nrows()) ]) + """ + def __init__(self, n, scalars=AA, prefix="E", **kwargs): + super().__init__(Octonions(field=scalars), + scalars, + n, + prefix=prefix, + **kwargs)