]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_algebra.py
eja: add subclass for Cartesian product elements.
[sage.d.git] / mjo / eja / eja_algebra.py
index ccc5006f3d79397d81ad98bbf45a7262e36dd6e9..a8df29f6e94161016217a9e13f6c1cc73c30354e 100644 (file)
@@ -31,7 +31,8 @@ from sage.modules.free_module import FreeModule, VectorSpace
 from sage.rings.all import (ZZ, QQ, AA, QQbar, RR, RLF, CLF,
                             PolynomialRing,
                             QuadraticField)
-from mjo.eja.eja_element import FiniteDimensionalEJAElement
+from mjo.eja.eja_element import (CartesianProductEJAElement,
+                                 FiniteDimensionalEJAElement)
 from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
 from mjo.eja.eja_utils import _mat2vec
 
@@ -311,9 +312,9 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         return ``True``, unless this algebra was constructed with
         ``check_axioms=False`` and passed an invalid multiplication table.
         """
-        return all( (self.monomial(i)**2)*(self.monomial(i)*self.monomial(j))
+        return all( (self.gens()[i]**2)*(self.gens()[i]*self.gens()[j])
                     ==
-                    (self.monomial(i))*((self.monomial(i)**2)*self.monomial(j))
+                    (self.gens()[i])*((self.gens()[i]**2)*self.gens()[j])
                     for i in range(self.dimension())
                     for j in range(self.dimension()) )
 
@@ -335,9 +336,9 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         for i in range(self.dimension()):
             for j in range(self.dimension()):
                 for k in range(self.dimension()):
-                    x = self.monomial(i)
-                    y = self.monomial(j)
-                    z = self.monomial(k)
+                    x = self.gens()[i]
+                    y = self.gens()[j]
+                    z = self.gens()[k]
                     diff = (x*y).inner_product(z) - x.inner_product(y*z)
 
                     if self.base_ring().is_exact():
@@ -660,8 +661,8 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
 
         # And to each subsequent row, prepend an entry that belongs to
         # the left-side "header column."
-        M += [ [self.monomial(i)] + [ self.product_on_basis(i,j)
-                                      for j in range(n) ]
+        M += [ [self.gens()[i]] + [ self.product_on_basis(i,j)
+                                    for j in range(n) ]
                for i in range(n) ]
 
         return table(M, header_row=True, header_column=True, frame=True)
@@ -1129,7 +1130,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         def L_x_i_j(i,j):
             # From a result in my book, these are the entries of the
             # basis representation of L_x.
-            return sum( vars[k]*self.monomial(k).operator().matrix()[i,j]
+            return sum( vars[k]*self.gens()[k].operator().matrix()[i,j]
                         for k in range(n) )
 
         L_x = matrix(F, n, n, L_x_i_j)
@@ -2730,6 +2731,33 @@ class CartesianProductEJA(CombinatorialFreeModule_CartesianProduct,
         Real Field (+) Euclidean Jordan algebra of dimension 6 over
         Algebraic Real Field
 
+    Rank is additive on a Cartesian product::
+
+        sage: J1 = HadamardEJA(1)
+        sage: J2 = RealSymmetricEJA(2)
+        sage: J = cartesian_product([J1,J2])
+        sage: J1.rank.clear_cache()
+        sage: J2.rank.clear_cache()
+        sage: J.rank.clear_cache()
+        sage: J.rank()
+        3
+        sage: J.rank() == J1.rank() + J2.rank()
+        True
+
+    The same rank computation works over the rationals, with whatever
+    basis you like::
+
+        sage: J1 = HadamardEJA(1, field=QQ, orthonormalize=False)
+        sage: J2 = RealSymmetricEJA(2, field=QQ, orthonormalize=False)
+        sage: J = cartesian_product([J1,J2])
+        sage: J1.rank.clear_cache()
+        sage: J2.rank.clear_cache()
+        sage: J.rank.clear_cache()
+        sage: J.rank()
+        3
+        sage: J.rank() == J1.rank() + J2.rank()
+        True
+
     TESTS:
 
     All factors must share the same base field::
@@ -2754,6 +2782,18 @@ class CartesianProductEJA(CombinatorialFreeModule_CartesianProduct,
         sage: x.inner_product(y) == J.cartesian_inner_product(x,y)
         True
 
+    The cached unit element is the same one that would be computed::
+
+        sage: set_random_seed()              # long time
+        sage: J1 = random_eja()              # long time
+        sage: J2 = random_eja()              # long time
+        sage: J = cartesian_product([J1,J2]) # long time
+        sage: actual = J.one()               # long time
+        sage: J.one.clear_cache()            # long time
+        sage: expected = J.one()             # long time
+        sage: actual == expected             # long time
+        True
+
     """
     def __init__(self, modules, **kwargs):
         CombinatorialFreeModule_CartesianProduct.__init__(self,
@@ -2793,8 +2833,49 @@ class CartesianProductEJA(CombinatorialFreeModule_CartesianProduct,
                                       check_axioms=False,
                                       category=self.category())
 
+        ones = tuple(J.one() for J in modules)
+        self.one.set_cache(self._cartesian_product_of_elements(ones))
         self.rank.set_cache(sum(J.rank() for J in modules))
 
+        # Now that everything else is ready, we clobber our computed
+        # matrix basis with the "correct" one consisting of ordered
+        # tuples. Since we didn't orthonormalize our basis, we can
+        # create these from the basis that was handed to us; that is,
+        # we don't need to use the one that the earlier __init__()
+        # method came up with.
+        m = len(self.cartesian_factors())
+        MS = self.matrix_space()
+        self._matrix_basis = tuple(
+            MS(tuple( self.cartesian_projection(i)(b).to_matrix()
+                      for i in range(m) ))
+            for b in self.basis()
+        )
+
+    def matrix_space(self):
+        r"""
+        Return the space that our matrix basis lives in as a Cartesian
+        product.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import (HadamardEJA,
+            ....:                                  RealSymmetricEJA)
+
+        EXAMPLES::
+
+            sage: J1 = HadamardEJA(1)
+            sage: J2 = RealSymmetricEJA(2)
+            sage: J = cartesian_product([J1,J2])
+            sage: J.matrix_space()
+            The Cartesian product of (Full MatrixSpace of 1 by 1 dense
+            matrices over Algebraic Real Field, Full MatrixSpace of 2
+            by 2 dense matrices over Algebraic Real Field)
+
+        """
+        from sage.categories.cartesian_product import cartesian_product
+        return cartesian_product( [J.matrix_space()
+                                   for J in self.cartesian_factors()] )
+
     @cached_method
     def cartesian_projection(self, i):
         r"""
@@ -3055,7 +3136,35 @@ class CartesianProductEJA(CombinatorialFreeModule_CartesianProduct,
         return sum( P(x).inner_product(P(y)) for P in projections )
 
 
-    Element = FiniteDimensionalEJAElement
+    def _element_constructor_(self, elt):
+        r"""
+        Construct an element of this algebra from an ordered tuple.
+
+        We just apply the element constructor from each of our factors
+        to the corresponding component of the tuple, and package up
+        the result.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import (HadamardEJA,
+            ....:                                  RealSymmetricEJA)
+
+        EXAMPLES::
+
+            sage: J1 = HadamardEJA(3)
+            sage: J2 = RealSymmetricEJA(2)
+            sage: J = cartesian_product([J1,J2])
+            sage: J( (J1.matrix_basis()[1], J2.matrix_basis()[2]) )
+            e(0, 1) + e(1, 2)
+        """
+        m = len(self.cartesian_factors())
+        try:
+            z = tuple( self.cartesian_factors()[i](elt[i]) for i in range(m) )
+            return self._cartesian_product_of_elements(z)
+        except:
+            raise ValueError("not an element of this algebra")
+
+    Element = CartesianProductEJAElement
 
 
 FiniteDimensionalEJA.CartesianProduct = CartesianProductEJA