]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_algebra.py
eja: disentangle RationalBasisEJA from ConcreteEJA.
[sage.d.git] / mjo / eja / eja_algebra.py
index d7010bcfd63ff838c0219dc7208a9b8e1988c889..aef11acd1dbb6dc60b4765be1790f2fb71c5a1be 100644 (file)
@@ -1656,7 +1656,7 @@ class RationalBasisEJA(FiniteDimensionalEJA):
         subs_dict = { X[i]: BX[i] for i in range(len(X)) }
         return tuple( a_i.subs(subs_dict) for a_i in a )
 
-class ConcreteEJA(RationalBasisEJA):
+class ConcreteEJA(FiniteDimensionalEJA):
     r"""
     A class for the Euclidean Jordan algebras that we know by name.
 
@@ -1733,11 +1733,9 @@ class MatrixEJA:
     def trace_inner_product(X,Y):
         r"""
         A trace inner-product for matrices that aren't embedded in the
-        reals.
+        reals. It takes MATRICES as arguments, not EJA elements.
         """
-        # We take the norm (absolute value) because Octonions() isn't
-        # smart enough yet to coerce its one() into the base field.
-        return (X*Y).trace().abs()
+        return (X*Y).trace().real()
 
 class RealEmbeddedMatrixEJA(MatrixEJA):
     @staticmethod
@@ -1833,7 +1831,7 @@ class RealEmbeddedMatrixEJA(MatrixEJA):
         # as a REAL matrix will be 2*a = 2*Re(z_1). And so forth.
         return (X*Y).trace()/cls.dimension_over_reals()
 
-class RealSymmetricEJA(ConcreteEJA, MatrixEJA):
+class RealSymmetricEJA(ConcreteEJA, RationalBasisEJA, MatrixEJA):
     """
     The rank-n simple EJA consisting of real symmetric n-by-n
     matrices, the usual symmetric Jordan product, and the trace inner
@@ -2115,7 +2113,7 @@ class ComplexMatrixEJA(RealEmbeddedMatrixEJA):
         return matrix(F, n/d, elements)
 
 
-class ComplexHermitianEJA(ConcreteEJA, ComplexMatrixEJA):
+class ComplexHermitianEJA(ConcreteEJA, RationalBasisEJA, ComplexMatrixEJA):
     """
     The rank-n simple EJA consisting of complex Hermitian n-by-n
     matrices over the real numbers, the usual symmetric Jordan product,
@@ -2417,7 +2415,9 @@ class QuaternionMatrixEJA(RealEmbeddedMatrixEJA):
         return matrix(Q, n/d, elements)
 
 
-class QuaternionHermitianEJA(ConcreteEJA, QuaternionMatrixEJA):
+class QuaternionHermitianEJA(ConcreteEJA,
+                             RationalBasisEJA,
+                             QuaternionMatrixEJA):
     r"""
     The rank-n simple EJA consisting of self-adjoint n-by-n quaternion
     matrices, the usual symmetric Jordan product, and the
@@ -2586,7 +2586,89 @@ class QuaternionHermitianEJA(ConcreteEJA, QuaternionMatrixEJA):
         return cls(n, **kwargs)
 
 class OctonionHermitianEJA(FiniteDimensionalEJA, MatrixEJA):
+    r"""
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import (FiniteDimensionalEJA,
+        ....:                                  OctonionHermitianEJA)
+
+    EXAMPLES:
+
+    The 3-by-3 algebra satisfies the axioms of an EJA::
+
+        sage: OctonionHermitianEJA(3,                    # long time
+        ....:                      field=QQ,             # long time
+        ....:                      orthonormalize=False, # long time
+        ....:                      check_axioms=True)    # long time
+        Euclidean Jordan algebra of dimension 27 over Rational Field
+
+    After a change-of-basis, the 2-by-2 algebra has the same
+    multiplication table as the ten-dimensional Jordan spin algebra::
+
+        sage: b = OctonionHermitianEJA._denormalized_basis(2,QQ)
+        sage: basis = (b[0] + b[9],) + b[1:9] + (b[0] - b[9],)
+        sage: jp = OctonionHermitianEJA.jordan_product
+        sage: ip = OctonionHermitianEJA.trace_inner_product
+        sage: J = FiniteDimensionalEJA(basis,
+        ....:                          jp,
+        ....:                          ip,
+        ....:                          field=QQ,
+        ....:                          orthonormalize=False)
+        sage: J.multiplication_table()
+        +----++----+----+----+----+----+----+----+----+----+----+
+        | *  || b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 |
+        +====++====+====+====+====+====+====+====+====+====+====+
+        | b0 || b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 |
+        +----++----+----+----+----+----+----+----+----+----+----+
+        | b1 || b1 | b0 | 0  | 0  | 0  | 0  | 0  | 0  | 0  | 0  |
+        +----++----+----+----+----+----+----+----+----+----+----+
+        | b2 || b2 | 0  | b0 | 0  | 0  | 0  | 0  | 0  | 0  | 0  |
+        +----++----+----+----+----+----+----+----+----+----+----+
+        | b3 || b3 | 0  | 0  | b0 | 0  | 0  | 0  | 0  | 0  | 0  |
+        +----++----+----+----+----+----+----+----+----+----+----+
+        | b4 || b4 | 0  | 0  | 0  | b0 | 0  | 0  | 0  | 0  | 0  |
+        +----++----+----+----+----+----+----+----+----+----+----+
+        | b5 || b5 | 0  | 0  | 0  | 0  | b0 | 0  | 0  | 0  | 0  |
+        +----++----+----+----+----+----+----+----+----+----+----+
+        | b6 || b6 | 0  | 0  | 0  | 0  | 0  | b0 | 0  | 0  | 0  |
+        +----++----+----+----+----+----+----+----+----+----+----+
+        | b7 || b7 | 0  | 0  | 0  | 0  | 0  | 0  | b0 | 0  | 0  |
+        +----++----+----+----+----+----+----+----+----+----+----+
+        | b8 || b8 | 0  | 0  | 0  | 0  | 0  | 0  | 0  | b0 | 0  |
+        +----++----+----+----+----+----+----+----+----+----+----+
+        | b9 || b9 | 0  | 0  | 0  | 0  | 0  | 0  | 0  | 0  | b0 |
+        +----++----+----+----+----+----+----+----+----+----+----+
+
+    TESTS:
 
+    We can actually construct the 27-dimensional Albert algebra,
+    and we get the right unit element if we recompute it::
+
+        sage: J = OctonionHermitianEJA(3,                    # long time
+        ....:                          field=QQ,             # long time
+        ....:                          orthonormalize=False) # long time
+        sage: J.one.clear_cache()                            # long time
+        sage: J.one()                                        # long time
+        b0 + b9 + b26
+        sage: J.one().to_matrix()                            # long time
+        +----+----+----+
+        | e0 | 0  | 0  |
+        +----+----+----+
+        | 0  | e0 | 0  |
+        +----+----+----+
+        | 0  | 0  | e0 |
+        +----+----+----+
+
+    The 2-by-2 algebra is isomorphic to the ten-dimensional Jordan
+    spin algebra, but just to be sure, we recompute its rank::
+
+        sage: J = OctonionHermitianEJA(2,                    # long time
+        ....:                          field=QQ,             # long time
+        ....:                          orthonormalize=False) # long time
+        sage: J.rank.clear_cache()                           # long time
+        sage: J.rank()                                       # long time
+        2
+    """
     def __init__(self, n, field=AA, **kwargs):
         if n > 3:
             # Otherwise we don't get an EJA.
@@ -2599,6 +2681,7 @@ class OctonionHermitianEJA(FiniteDimensionalEJA, MatrixEJA):
         super().__init__(self._denormalized_basis(n,field),
                          self.jordan_product,
                          self.trace_inner_product,
+                         field=field,
                          **kwargs)
 
         # TODO: this could be factored out somehow, but is left here
@@ -2621,7 +2704,7 @@ class OctonionHermitianEJA(FiniteDimensionalEJA, MatrixEJA):
 
         EXAMPLES::
 
-            sage: B = OctonionHermitianEJA._denormalized_basis(3)
+            sage: B = OctonionHermitianEJA._denormalized_basis(3,QQ)
             sage: all( M.is_hermitian() for M in B )
             True
             sage: len(B)
@@ -2641,13 +2724,38 @@ class OctonionHermitianEJA(FiniteDimensionalEJA, MatrixEJA):
                 else:
                     for e in es:
                         E_ij  = MS.monomial( (i,j,e)             )
-                        E_ij += MS.monomial( (j,i,e.conjugate()) )
+                        ec = e.conjugate()
+                        # If the conjugate has a negative sign in front
+                        # of it, (j,i,ec) won't be a monomial!
+                        if (j,i,ec) in MS.indices():
+                            E_ij += MS.monomial( (j,i,ec) )
+                        else:
+                            E_ij -= MS.monomial( (j,i,-ec) )
                         basis.append(E_ij)
 
         return tuple( basis )
 
+    @staticmethod
+    def trace_inner_product(X,Y):
+        r"""
+        The octonions don't know that the reals are embedded in them,
+        so we have to take the e0 component ourselves.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import OctonionHermitianEJA
+
+        TESTS::
+
+            sage: J = OctonionHermitianEJA(2,field=QQ,orthonormalize=False)
+            sage: I = J.one().to_matrix()
+            sage: J.trace_inner_product(I, -I)
+            -2
+
+        """
+        return (X*Y).trace().real().coefficient(0)
 
-class HadamardEJA(ConcreteEJA):
+class HadamardEJA(ConcreteEJA, RationalBasisEJA):
     """
     Return the Euclidean Jordan Algebra corresponding to the set
     `R^n` under the Hadamard product.
@@ -2739,7 +2847,7 @@ class HadamardEJA(ConcreteEJA):
         return cls(n, **kwargs)
 
 
-class BilinearFormEJA(ConcreteEJA):
+class BilinearFormEJA(ConcreteEJA, RationalBasisEJA):
     r"""
     The rank-2 simple EJA consisting of real vectors ``x=(x0, x_bar)``
     with the half-trace inner product and jordan product ``x*y =
@@ -2987,7 +3095,7 @@ class JordanSpinEJA(BilinearFormEJA):
         return cls(n, **kwargs)
 
 
-class TrivialEJA(ConcreteEJA):
+class TrivialEJA(ConcreteEJA, RationalBasisEJA):
     """
     The trivial Euclidean Jordan algebra consisting of only a zero element.