From e28bd3518185e3a87866c61d973876f84fdeea66 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 8 Mar 2021 14:51:45 -0500 Subject: [PATCH] Reorganize the Hurwitz (matrix) algebra stuff. --- mjo/eja/TODO | 3 +- mjo/eja/eja_algebra.py | 2 +- mjo/{octonions.py => hurwitz.py} | 124 ++++++++++++++++++++++++++++--- mjo/matrix_algebra.py | 28 +------ 4 files changed, 115 insertions(+), 42 deletions(-) rename mjo/{octonions.py => hurwitz.py} (78%) diff --git a/mjo/eja/TODO b/mjo/eja/TODO index 1742285..310e307 100644 --- a/mjo/eja/TODO +++ b/mjo/eja/TODO @@ -27,8 +27,7 @@ sage: a0 = (1/4)*X[4]**2*X[6]**2 - (1/2)*X[2]*X[5]*X[6]**2 - (1/2)*X[3]*X[4]*X[6 6. Can we convert the complex/quaternion algebras to avoid real- (un)embeddings? Quaternions would need their own QuaternionMatrixAlgebra, since Sage matrices have to have entries - in a commutative ring. Those and the octonion stuff could be moved - to hurwitz.py along with the HurwitzMatrixAlgebra. + in a commutative ring. 7. Every once in a long while, the test diff --git a/mjo/eja/eja_algebra.py b/mjo/eja/eja_algebra.py index c86cdff..2ecf8cd 100644 --- a/mjo/eja/eja_algebra.py +++ b/mjo/eja/eja_algebra.py @@ -2732,7 +2732,7 @@ class OctonionHermitianEJA(RationalBasisEJA, ConcreteEJA, MatrixEJA): 27 """ - from mjo.octonions import OctonionMatrixAlgebra + from mjo.hurwitz import OctonionMatrixAlgebra MS = OctonionMatrixAlgebra(n, scalars=field) es = MS.entry_algebra().gens() diff --git a/mjo/octonions.py b/mjo/hurwitz.py similarity index 78% rename from mjo/octonions.py rename to mjo/hurwitz.py index 78365e2..ff1792b 100644 --- a/mjo/octonions.py +++ b/mjo/hurwitz.py @@ -7,14 +7,14 @@ 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 +from mjo.matrix_algebra import MatrixAlgebra, MatrixAlgebraElement class Octonion(IndexedFreeModuleElement): def conjugate(self): r""" SETUP:: - sage: from mjo.octonions import Octonions + sage: from mjo.hurwitz import Octonions EXAMPLES:: @@ -47,7 +47,7 @@ class Octonion(IndexedFreeModuleElement): SETUP:: - sage: from mjo.octonions import Octonions + sage: from mjo.hurwitz import Octonions EXAMPLES:: @@ -80,7 +80,7 @@ class Octonion(IndexedFreeModuleElement): SETUP:: - sage: from mjo.octonions import Octonions + sage: from mjo.hurwitz import Octonions EXAMPLES:: @@ -111,7 +111,7 @@ class Octonion(IndexedFreeModuleElement): SETUP:: - sage: from mjo.octonions import Octonions + sage: from mjo.hurwitz import Octonions EXAMPLES:: @@ -152,7 +152,7 @@ class Octonion(IndexedFreeModuleElement): SETUP:: - sage: from mjo.octonions import Octonions + sage: from mjo.hurwitz import Octonions EXAMPLES:: @@ -198,7 +198,7 @@ class Octonion(IndexedFreeModuleElement): SETUP:: - sage: from mjo.octonions import Octonions + sage: from mjo.hurwitz import Octonions EXAMPLES:: @@ -230,7 +230,7 @@ class Octonions(CombinatorialFreeModule): r""" SETUP:: - sage: from mjo.octonions import Octonions + sage: from mjo.hurwitz import Octonions EXAMPLES:: @@ -280,7 +280,7 @@ class Octonions(CombinatorialFreeModule): SETUP:: - sage: from mjo.octonions import Octonions + sage: from mjo.hurwitz import Octonions TESTS: @@ -305,7 +305,7 @@ class Octonions(CombinatorialFreeModule): SETUP:: - sage: from mjo.octonions import Octonions + sage: from mjo.hurwitz import Octonions EXAMPLES: @@ -347,6 +347,106 @@ class Octonions(CombinatorialFreeModule): + + +class HurwitzMatrixAlgebraElement(MatrixAlgebraElement): + def is_hermitian(self): + r""" + + SETUP:: + + sage: from mjo.hurwitz import HurwitzMatrixAlgebra + + EXAMPLES:: + + sage: A = HurwitzMatrixAlgebra(QQbar, ZZ, 2) + sage: M = A([ [ 0,I], + ....: [-I,0] ]) + sage: M.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 HurwitzMatrixAlgebra(MatrixAlgebra): + r""" + A class of matrix algebras whose entries come from a Hurwitz + algebra. + + For our purposes, we consider "a Hurwitz" algebra to be the real + or complex numbers, the quaternions, or the octonions. These are + typically also referred to as the Euclidean Hurwitz algebras, or + the normed division algebras. + + By the Cayley-Dickson construction, each Hurwitz algebra is an + algebra over the real numbers, so we restrict the scalar field in + this case to be real. This also allows us to more accurately + produce the generators of the matrix algebra. + """ + Element = HurwitzMatrixAlgebraElement + + def __init__(self, entry_algebra, scalars, n, **kwargs): + from sage.rings.all import RR + if not scalars.is_subring(RR): + # Not perfect, but it's what we're using. + raise ValueError("scalar field is not real") + + super().__init__(entry_algebra, scalars, n, **kwargs) + + def entry_algebra_gens(self): + r""" + Return the generators of (that is, a basis for) the entries of + this matrix algebra. + + This works around the inconsistency in the ``gens()`` methods + of the real/complex numbers, quaternions, and octonions. + + SETUP:: + + sage: from mjo.hurwitz import Octonions, HurwitzMatrixAlgebra + + EXAMPLES: + + The inclusion of the unit element is inconsistent across + (subalgebras of) Hurwitz algebras:: + + sage: AA.gens() + (1,) + sage: QQbar.gens() + (I,) + sage: QuaternionAlgebra(AA,1,-1).gens() + [i, j, k] + sage: Octonions().gens() + (e0, e1, e2, e3, e4, e5, e6, e7) + + The unit element is always returned by this method, so the + sets of generators have cartinality 1,2,4, and 8 as you'd + expect:: + + sage: HurwitzMatrixAlgebra(AA, AA, 2).entry_algebra_gens() + (1,) + sage: HurwitzMatrixAlgebra(QQbar, AA, 2).entry_algebra_gens() + (1, I) + sage: Q = QuaternionAlgebra(AA,-1,-1) + sage: HurwitzMatrixAlgebra(Q, AA, 2).entry_algebra_gens() + (1, i, j, k) + sage: O = Octonions() + sage: HurwitzMatrixAlgebra(O, AA, 2).entry_algebra_gens() + (e0, e1, e2, e3, e4, e5, e6, e7) + + """ + gs = self.entry_algebra().gens() + one = self.entry_algebra().one() + if one in gs: + return gs + else: + return (one,) + tuple(gs) + + + class OctonionMatrixAlgebra(HurwitzMatrixAlgebra): r""" The algebra of ``n``-by-``n`` matrices with octonion entries over @@ -358,7 +458,7 @@ class OctonionMatrixAlgebra(HurwitzMatrixAlgebra): SETUP:: - sage: from mjo.octonions import OctonionMatrixAlgebra + sage: from mjo.hurwitz import OctonionMatrixAlgebra EXAMPLES:: @@ -418,7 +518,7 @@ class QuaternionMatrixAlgebra(HurwitzMatrixAlgebra): SETUP:: - sage: from mjo.octonions import QuaternionMatrixAlgebra + sage: from mjo.hurwitz import QuaternionMatrixAlgebra EXAMPLES:: diff --git a/mjo/matrix_algebra.py b/mjo/matrix_algebra.py index a67a9b4..94a8410 100644 --- a/mjo/matrix_algebra.py +++ b/mjo/matrix_algebra.py @@ -236,7 +236,7 @@ class MatrixAlgebra(CombinatorialFreeModule): SETUP:: - sage: from mjo.octonions import Octonions + sage: from mjo.hurwitz import Octonions sage: from mjo.matrix_algebra import MatrixAlgebra TESTS:: @@ -322,29 +322,3 @@ class MatrixAlgebra(CombinatorialFreeModule): return self else: return self.from_list(elt) - - -class HurwitzMatrixAlgebraElement(MatrixAlgebraElement): - def is_hermitian(self): - r""" - - SETUP:: - - sage: from mjo.matrix_algebra import HurwitzMatrixAlgebra - - EXAMPLES:: - - sage: A = HurwitzMatrixAlgebra(QQbar, ZZ, 2) - sage: M = A([ [ 0,I], - ....: [-I,0] ]) - sage: M.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 HurwitzMatrixAlgebra(MatrixAlgebra): - Element = HurwitzMatrixAlgebraElement -- 2.43.2