X-Git-Url: http://gitweb.michael.orlitzky.com/?p=sage.d.git;a=blobdiff_plain;f=mjo%2Foctonions.py;h=bd014c22eb4c180117cf70291e4f2357c091bd20;hp=f6e222eebf7734a968dfa46a478d64ea7631d6cf;hb=a339e89c225bb46379332ecb8b0c50b918d34ac6;hpb=bccb4975e8bc21ddb5f726a68f2497477df97df9 diff --git a/mjo/octonions.py b/mjo/octonions.py index f6e222e..bd014c2 100644 --- a/mjo/octonions.py +++ b/mjo/octonions.py @@ -1,3 +1,5 @@ +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 from sage.categories.magmatic_algebras import MagmaticAlgebras @@ -5,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 MatrixAlgebra + class Octonion(IndexedFreeModuleElement): def conjugate(self): r""" @@ -137,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. @@ -171,6 +180,52 @@ class Octonion(IndexedFreeModuleElement): raise ValueError("zero is not invertible") return self.conjugate()/self._norm_squared() + + def cayley_dickson(self, Q=None): + r""" + Return the Cayley-Dickson representation of this element in terms + of the quaternion algebra ``Q``. + + The Cayley-Dickson representation is an identification of + octionions `x` and `y` with pairs of quaternions `(a,b)` and + `(c,d)` respectively such that: + + * `x + y = (a+b, c+d)` + * `xy` = (ac - \bar{d}*b, da + b\bar{c})` + * `\bar{x} = (a,-b)` + + where `\bar{x}` denotes the conjugate of `x`. + + SETUP:: + + sage: from mjo.octonions import Octonions + + EXAMPLES:: + + sage: O = Octonions() + sage: x = sum(O.gens()) + sage: x.cayley_dickson() + (1 + i + j + k, 1 + i + j + k) + + """ + if Q is None: + Q = QuaternionAlgebra(self.base_ring(), -1, -1) + + i,j,k = Q.gens() + a = (self.coefficient(0)*Q.one() + + self.coefficient(1)*i + + self.coefficient(2)*j + + self.coefficient(3)*k ) + b = (self.coefficient(4)*Q.one() + + self.coefficient(5)*i + + self.coefficient(6)*j + + self.coefficient(7)*k ) + + from sage.categories.sets_cat import cartesian_product + P = cartesian_product([Q,Q]) + return P((a,b)) + + class Octonions(CombinatorialFreeModule): r""" SETUP:: @@ -289,3 +344,56 @@ class Octonions(CombinatorialFreeModule): for i in range(n) ] return table(M, header_row=True, header_column=True, frame=True) + + + +class OctonionMatrixAlgebra(MatrixAlgebra): + 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). + + SETUP:: + + sage: from mjo.octonions import Octonions, OctonionMatrixAlgebra + + EXAMPLES:: + + 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.from_list([ [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 + + """ + def __init__(self, n, scalars=AA, prefix="E", **kwargs): + super().__init__(Octonions(field=scalars), + scalars, + n, + prefix=prefix, + **kwargs)