]> gitweb.michael.orlitzky.com - sage.d.git/commitdiff
eja: add automatic associativity detection.
authorMichael Orlitzky <michael@orlitzky.com>
Fri, 26 Feb 2021 01:53:41 +0000 (20:53 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Fri, 26 Feb 2021 01:53:41 +0000 (20:53 -0500)
mjo/eja/TODO
mjo/eja/eja_algebra.py

index 0d6edf2500664bbbad54e08b18f9e304765a7b6f..c92cfc9a62c2424e7ae2ab3be37d7f17f3954630 100644 (file)
@@ -15,8 +15,6 @@ 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
    15-dimensional QuaternionHermitianAlgebra(3)) to find out why
    they're so slow.
 
-6. We should compute whether or not the algebra is associative if it
-   is unknown. I guess the "associative" argument should be ternary
-   (True, False, None)? We should also figure out the correct
-   True/False values for the example classes, and of course add an
-   _is_associative() method.
+6. The _rational_algebra for a cartesian product should be a cartesian product.
+
+7. Use super() where it works.
index ee34e532fa7f4efb3d5aa7d89001f0430f2df52d..40b4bcac6583e75f6877260f633d752b6693d8d7 100644 (file)
@@ -112,6 +112,23 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         generally rules out using the rationals as your ``field``, but
         is required for spectral decompositions.
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import random_eja
+
+    TESTS:
+
+    We should compute that an element subalgebra is associative even
+    if we circumvent the element method::
+
+        sage: set_random_seed()
+        sage: J = random_eja(field=QQ,orthonormalize=False)
+        sage: x = J.random_element()
+        sage: A = x.subalgebra_generated_by(orthonormalize=False)
+        sage: basis = tuple(b.superalgebra_element() for b in A.basis())
+        sage: J.subalgebra(basis, orthonormalize=False).is_associative()
+        True
+
     """
     Element = FiniteDimensionalEJAElement
 
@@ -121,7 +138,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
                  inner_product,
                  field=AA,
                  orthonormalize=True,
-                 associative=False,
+                 associative=None,
                  cartesian_product=False,
                  check_field=True,
                  check_axioms=True,
@@ -180,6 +197,18 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         category = MagmaticAlgebras(field).FiniteDimensional()
         category = category.WithBasis().Unital().Commutative()
 
+        if associative is None:
+            # We should figure it out. As with check_axioms, we have to do
+            # this without the help of the _jordan_product_is_associative()
+            # method because we need to know the category before we
+            # initialize the algebra.
+            associative = all( jordan_product(jordan_product(bi,bj),bk)
+                               ==
+                               jordan_product(bi,jordan_product(bj,bk))
+                               for bi in basis
+                               for bj in basis
+                               for bk in basis)
+
         if associative:
             # Element subalgebras can take advantage of this.
             category = category.Associative()
@@ -464,7 +493,8 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
 
         SETUP::
 
-            sage: from mjo.eja.eja_algebra import (RealSymmetricEJA,
+            sage: from mjo.eja.eja_algebra import (random_eja,
+            ....:                                  RealSymmetricEJA,
             ....:                                  ComplexHermitianEJA,
             ....:                                  QuaternionHermitianEJA)
 
@@ -498,6 +528,16 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
             sage: A._jordan_product_is_associative()
             True
 
+        TESTS:
+
+        The values we've presupplied to the constructors agree with
+        the computation::
+
+            sage: set_random_seed()
+            sage: J = random_eja()
+            sage: J.is_associative() == J._jordan_product_is_associative()
+            True
+
         """
         R = self.base_ring()
 
@@ -1562,6 +1602,13 @@ class RationalBasisEJA(FiniteDimensionalEJA):
             if not all( all(b_i in QQ for b_i in b.list()) for b in basis ):
                 raise TypeError("basis not rational")
 
+        super().__init__(basis,
+                         jordan_product,
+                         inner_product,
+                         field=field,
+                         check_field=check_field,
+                         **kwargs)
+
         self._rational_algebra = None
         if field is not QQ:
             # There's no point in constructing the extra algebra if this
@@ -1575,17 +1622,11 @@ class RationalBasisEJA(FiniteDimensionalEJA):
                                        jordan_product,
                                        inner_product,
                                        field=QQ,
+                                       associative=self.is_associative(),
                                        orthonormalize=False,
                                        check_field=False,
                                        check_axioms=False)
 
-        super().__init__(basis,
-                         jordan_product,
-                         inner_product,
-                         field=field,
-                         check_field=check_field,
-                         **kwargs)
-
     @cached_method
     def _charpoly_coefficients(self):
         r"""
@@ -1949,9 +1990,14 @@ class RealSymmetricEJA(ConcreteEJA, RealMatrixEJA):
         # if the user passes check_axioms=True.
         if "check_axioms" not in kwargs: kwargs["check_axioms"] = False
 
+        associative = False
+        if n <= 1:
+            associative = True
+
         super(RealSymmetricEJA, self).__init__(self._denormalized_basis(n),
                                                self.jordan_product,
                                                self.trace_inner_product,
+                                               associative=associative,
                                                **kwargs)
 
         # TODO: this could be factored out somehow, but is left here
@@ -2237,9 +2283,14 @@ class ComplexHermitianEJA(ConcreteEJA, ComplexMatrixEJA):
         # if the user passes check_axioms=True.
         if "check_axioms" not in kwargs: kwargs["check_axioms"] = False
 
+        associative = False
+        if n <= 1:
+            associative = True
+
         super(ComplexHermitianEJA, self).__init__(self._denormalized_basis(n),
                                                   self.jordan_product,
                                                   self.trace_inner_product,
+                                                  associative=associative,
                                                   **kwargs)
         # TODO: this could be factored out somehow, but is left here
         # because the MatrixEJA is not presently a subclass of the
@@ -2543,10 +2594,16 @@ class QuaternionHermitianEJA(ConcreteEJA, QuaternionMatrixEJA):
         # if the user passes check_axioms=True.
         if "check_axioms" not in kwargs: kwargs["check_axioms"] = False
 
+        associative = False
+        if n <= 1:
+            associative = True
+
         super(QuaternionHermitianEJA, self).__init__(self._denormalized_basis(n),
                                                      self.jordan_product,
                                                      self.trace_inner_product,
+                                                     associative=associative,
                                                      **kwargs)
+
         # TODO: this could be factored out somehow, but is left here
         # because the MatrixEJA is not presently a subclass of the
         # FDEJA class that defines rank() and one().
@@ -2772,9 +2829,16 @@ class BilinearFormEJA(ConcreteEJA):
 
         n = B.nrows()
         column_basis = tuple( b.column() for b in FreeModule(ZZ, n).basis() )
+
+        # TODO: I haven't actually checked this, but it seems legit.
+        associative = False
+        if n <= 2:
+            associative = True
+
         super(BilinearFormEJA, self).__init__(column_basis,
                                               jordan_product,
                                               inner_product,
+                                              associative=associative,
                                               **kwargs)
 
         # The rank of this algebra is two, unless we're in a
@@ -2941,7 +3005,9 @@ class TrivialEJA(ConcreteEJA):
         super(TrivialEJA, self).__init__(basis,
                                          jordan_product,
                                          inner_product,
+                                         associative=True,
                                          **kwargs)
+
         # The rank is zero using my definition, namely the dimension of the
         # largest subalgebra generated by any element.
         self.rank.set_cache(0)