]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_algebra.py
eja: ensure that Sage doesn't think EJAs are associative.
[sage.d.git] / mjo / eja / eja_algebra.py
index 76a8ce624d526b8c3bd67de6d3b169b4b866d73b..8c66de69ee4a451ce59b0319d1680b8474e7439d 100644 (file)
@@ -6,11 +6,12 @@ what can be supported in a general Jordan Algebra.
 """
 
 from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra
-from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis
+from sage.categories.magmatic_algebras import MagmaticAlgebras
 from sage.combinat.free_module import CombinatorialFreeModule
 from sage.matrix.constructor import matrix
 from sage.misc.cachefunc import cached_method
 from sage.misc.prandom import choice
+from sage.misc.table import table
 from sage.modules.free_module import VectorSpace
 from sage.rings.integer_ring import ZZ
 from sage.rings.number_field.number_field import QuadraticField
@@ -22,6 +23,14 @@ from mjo.eja.eja_element import FiniteDimensionalEuclideanJordanAlgebraElement
 from mjo.eja.eja_utils import _mat2vec
 
 class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
+    # This is an ugly hack needed to prevent the category framework
+    # from implementing a coercion from our base ring (e.g. the
+    # rationals) into the algebra. First of all -- such a coercion is
+    # nonsense to begin with. But more importantly, it tries to do so
+    # in the category of rings, and since our algebras aren't
+    # associative they generally won't be rings.
+    _no_generic_basering_coercion = True
+
     def __init__(self,
                  field,
                  mult_table,
@@ -50,7 +59,9 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         self._natural_basis = natural_basis
 
         if category is None:
-            category = FiniteDimensionalAlgebrasWithBasis(field).Unital()
+            category = MagmaticAlgebras(field).FiniteDimensional()
+            category = category.WithBasis().Unital()
+
         fda = super(FiniteDimensionalEuclideanJordanAlgebra, self)
         fda.__init__(field,
                      range(len(mult_table)),
@@ -117,6 +128,11 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             True
 
         """
+        if elt == 0:
+            # The superclass implementation of random_element()
+            # needs to be able to coerce "0" into the algebra.
+            return self.zero()
+
         natural_basis = self.natural_basis()
         if elt not in natural_basis[0].matrix_space():
             raise ValueError("not a naturally-represented algebra element")
@@ -381,32 +397,36 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
 
     def multiplication_table(self):
         """
-        Return a readable matrix representation of this algebra's
-        multiplication table. The (i,j)th entry in the matrix contains
-        the product of the ith basis element with the jth.
+        Return a visual representation of this algebra's multiplication
+        table (on basis elements).
 
-        This is not extraordinarily useful, but it overrides a superclass
-        method that would otherwise just crash and complain about the
-        algebra being infinite.
-
-        EXAMPLES::
+        SETUP::
 
-            sage: J = RealCartesianProductEJA(3)
-            sage: J.multiplication_table()
-            [e0  0  0]
-            [ 0 e1  0]
-            [ 0  0 e2]
+            sage: from mjo.eja.eja_algebra import JordanSpinEJA
 
-        ::
+        EXAMPLES::
 
-            sage: J = JordanSpinEJA(3)
+            sage: J = JordanSpinEJA(4)
             sage: J.multiplication_table()
-            [e0 e1 e2]
-            [e1 e0  0]
-            [e2  0 e0]
+            +----++----+----+----+----+
+            | *  || e0 | e1 | e2 | e3 |
+            +====++====+====+====+====+
+            | e0 || e0 | e1 | e2 | e3 |
+            +----++----+----+----+----+
+            | e1 || e1 | e0 | 0  | 0  |
+            +----++----+----+----+----+
+            | e2 || e2 | 0  | e0 | 0  |
+            +----++----+----+----+----+
+            | e3 || e3 | 0  | 0  | e0 |
+            +----++----+----+----+----+
 
         """
-        return matrix(self._multiplication_table)
+        M = list(self._multiplication_table) # copy
+        for i in range(len(M)):
+            # M had better be "square"
+            M[i] = [self.monomial(i)] + M[i]
+        M = [["*"] + list(self.gens())] + M
+        return table(M, header_row=True, header_column=True, frame=True)
 
 
     def natural_basis(self):
@@ -472,7 +492,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             sage: J.one()
             e0 + e1 + e2 + e3 + e4
 
-        TESTS::
+        TESTS:
 
         The identity element acts like the identity::
 
@@ -633,8 +653,8 @@ class RealCartesianProductEJA(FiniteDimensionalEuclideanJordanAlgebra):
     """
     def __init__(self, n, field=QQ):
         V = VectorSpace(field, n)
-        mult_table = [ [ V.basis()[i]*(i == j) for i in range(n) ]
-                       for j in range(n) ]
+        mult_table = [ [ V.gen(i)*(i == j) for j in range(n) ]
+                       for i in range(n) ]
 
         fdeja = super(RealCartesianProductEJA, self)
         return fdeja.__init__(field, mult_table, rank=n)
@@ -821,7 +841,7 @@ def _multiplication_table_from_matrix_basis(basis):
     V = VectorSpace(field, dimension**2)
     W = V.span_of_basis( _mat2vec(s) for s in basis )
     n = len(basis)
-    mult_table = [[W.zero() for i in range(n)] for j in range(n)]
+    mult_table = [[W.zero() for j in range(n)] for i in range(n)]
     for i in range(n):
         for j in range(n):
             mat_entry = (basis[i]*basis[j] + basis[j]*basis[i])/2
@@ -1287,11 +1307,11 @@ class JordanSpinEJA(FiniteDimensionalEuclideanJordanAlgebra):
     """
     def __init__(self, n, field=QQ):
         V = VectorSpace(field, n)
-        mult_table = [[V.zero() for i in range(n)] for j in range(n)]
+        mult_table = [[V.zero() for j in range(n)] for i in range(n)]
         for i in range(n):
             for j in range(n):
-                x = V.basis()[i]
-                y = V.basis()[j]
+                x = V.gen(i)
+                y = V.gen(j)
                 x0 = x[0]
                 xbar = x[1:]
                 y0 = y[0]