]> 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 d4ee9b022d8524752d3e15edf37284c2381ce509..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)),
@@ -64,10 +75,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         # long run to have the multiplication table be in terms of
         # algebra elements. We do this after calling the superclass
         # constructor so that from_vector() knows what to do.
-        self._multiplication_table = matrix(
-            [ map(lambda x: self.from_vector(x), ls)
-              for ls in mult_table ] )
-        self._multiplication_table.set_immutable()
+        self._multiplication_table = [ map(lambda x: self.from_vector(x), ls)
+                                       for ls in mult_table ]
 
 
     def _element_constructor_(self, elt):
@@ -119,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")
@@ -155,7 +169,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         return fmt.format(self.dimension(), self.base_ring())
 
     def product_on_basis(self, i, j):
-        return self._multiplication_table[i,j]
+        return self._multiplication_table[i][j]
 
     def _a_regular_element(self):
         """
@@ -251,9 +265,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         R = PolynomialRing(self.base_ring(), names)
         # Hack around the fact that our multiplication table is in terms of
         # algebra elements but the constructor wants it in terms of vectors.
-        vmt = [ tuple([ self._multiplication_table[i,j].to_vector()
-                        for j in range(self._multiplication_table.nrows()) ])
-                for i in range(self._multiplication_table.ncols()) ]
+        vmt = [ tuple(map(lambda x: x.to_vector(), ls))
+                for ls in self._multiplication_table ]
         J = FiniteDimensionalEuclideanJordanAlgebra(R, tuple(vmt), r)
 
         idmat = matrix.identity(J.base_ring(), n)
@@ -384,37 +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.
-
-        This is not extraordinarily useful, but it overrides a superclass
-        method that would otherwise just crash and complain about the
-        algebra being infinite.
+        Return a visual representation of this algebra's multiplication
+        table (on basis elements).
 
         SETUP::
 
-            sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
-            ....:                                  RealCartesianProductEJA)
+            sage: from mjo.eja.eja_algebra import JordanSpinEJA
 
         EXAMPLES::
 
-            sage: J = RealCartesianProductEJA(3)
-            sage: J.multiplication_table()
-            [e0  0  0]
-            [ 0 e1  0]
-            [ 0  0 e2]
-
-        ::
-
-            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 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):