+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
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"""
"""
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.
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::
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([ [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)