]> gitweb.michael.orlitzky.com - sage.d.git/commitdiff
eja: ensure that Sage doesn't think EJAs are associative.
authorMichael Orlitzky <michael@orlitzky.com>
Mon, 5 Aug 2019 18:06:24 +0000 (14:06 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Mon, 5 Aug 2019 18:06:24 +0000 (14:06 -0400)
It turns out that the FiniteDimensionalAlgebrasWithBasis category
somehow has both the legacy Algebras() category and the newer
MagmaticAlgebras() category as super-categories. Problem is, the
legacy one is associative! To fix that, we now use MagmaticAlgebras
directly.

Of course, we have to reimplement some of the stuff that was done for
us before... and we have to add a bunch of hacks for parts of Sage
that break when you don't have a ring.... and we can't use a matrix
for our multiplication table any more. But it was all doable.

mjo/eja/eja_algebra.py
mjo/eja/eja_element.py
mjo/eja/eja_subalgebra.py

index 28e86c25e3a3d315cf8fefb325fc05ef4b03b427..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,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 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):
index e38012eb3bf9cda640c8cc4c4ef8d822e194ce43..287a217e785ff3e44109d3fc8d8fd85ed1ca4771 100644 (file)
@@ -490,7 +490,9 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             False
 
         """
-        zero = self.parent().zero()
+        # In fact, we only need to know if the constant term is non-zero,
+        # so we can pass in the field's zero element instead.
+        zero = self.base_ring().zero()
         p = self.minimal_polynomial()
         return not (p(zero) == zero)
 
@@ -801,10 +803,12 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
         """
         P = self.parent()
+        left_mult_by_self = lambda y: self*y
+        L = P.module_morphism(function=left_mult_by_self, codomain=P)
         return FiniteDimensionalEuclideanJordanAlgebraOperator(
                  P,
                  P,
-                 self.to_matrix() )
+                 L.matrix() )
 
 
     def quadratic_representation(self, other=None):
index 7451e47bdbbbf2d58ce598aa3bb4e17ec42d5dae..a3ad92a4f9f5acedc7a12c6c11971f0d9351c3a3 100644 (file)
@@ -157,6 +157,12 @@ class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclide
         ::
 
         """
+        if elt == 0:
+            # Just as in the superalgebra class, we need to hack
+            # this special case to ensure that random_element() can
+            # coerce a ring zero into the algebra.
+            return self.zero()
+
         if elt in self.superalgebra():
             coords = self.vector_space().coordinate_vector(elt.to_vector())
             return self.from_vector(coords)