]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_algebra.py
eja: begin dropping CFM_CartesianProduct, tests all broken.
[sage.d.git] / mjo / eja / eja_algebra.py
index 00de418a36cca4ecdf7bd6c6e70daf7cc8531344..1040d37071d9000cbbd69111306284e7a9745edc 100644 (file)
@@ -3018,8 +3018,7 @@ class TrivialEJA(ConcreteEJA):
         return cls(**kwargs)
 
 
-class CartesianProductEJA(CombinatorialFreeModule_CartesianProduct,
-                          FiniteDimensionalEJA):
+class CartesianProductEJA(FiniteDimensionalEJA):
     r"""
     The external (orthogonal) direct sum of two or more Euclidean
     Jordan algebras. Every Euclidean Jordan algebra decomposes into an
@@ -3115,6 +3114,33 @@ class CartesianProductEJA(CombinatorialFreeModule_CartesianProduct,
         sage: CP2.is_associative()
         False
 
+    Cartesian products of Cartesian products work::
+
+        sage: J1 = JordanSpinEJA(1)
+        sage: J2 = JordanSpinEJA(1)
+        sage: J3 = JordanSpinEJA(1)
+        sage: J = cartesian_product([J1,cartesian_product([J2,J3])])
+        sage: J.multiplication_table()
+        +--------------++---------+--------------+--------------+
+        | *            || e(0, 0) | e(1, (0, 0)) | e(1, (1, 0)) |
+        +==============++=========+==============+==============+
+        | e(0, 0)      || e(0, 0) | 0            | 0            |
+        +--------------++---------+--------------+--------------+
+        | e(1, (0, 0)) || 0       | e(1, (0, 0)) | 0            |
+        +--------------++---------+--------------+--------------+
+        | e(1, (1, 0)) || 0       | 0            | e(1, (1, 0)) |
+        +--------------++---------+--------------+--------------+
+        sage: HadamardEJA(3).multiplication_table()
+        +----++----+----+----+
+        | *  || e0 | e1 | e2 |
+        +====++====+====+====+
+        | e0 || e0 | 0  | 0  |
+        +----++----+----+----+
+        | e1 || 0  | e1 | 0  |
+        +----++----+----+----+
+        | e2 || 0  | 0  | e2 |
+        +----++----+----+----+
+
     TESTS:
 
     All factors must share the same base field::
@@ -3142,37 +3168,39 @@ class CartesianProductEJA(CombinatorialFreeModule_CartesianProduct,
     Element = FiniteDimensionalEJAElement
 
 
-    def __init__(self, algebras, **kwargs):
-        CombinatorialFreeModule_CartesianProduct.__init__(self,
-                                                          algebras,
-                                                          **kwargs)
-        field = algebras[0].base_ring()
-        if not all( J.base_ring() == field for J in algebras ):
+    def __init__(self, factors, **kwargs):
+        m = len(factors)
+        if m == 0:
+            return TrivialEJA()
+
+        self._sets = factors
+
+        field = factors[0].base_ring()
+        if not all( J.base_ring() == field for J in factors ):
             raise ValueError("all factors must share the same base field")
 
-        associative = all( m.is_associative() for m in algebras )
+        associative = all( f.is_associative() for f in factors )
 
-        # The definition of matrix_space() and self.basis() relies
-        # only on the stuff in the CFM_CartesianProduct class, which
-        # we've already initialized.
-        Js = self.cartesian_factors()
-        m = len(Js)
         MS = self.matrix_space()
-        basis = tuple(
-            MS(tuple( self.cartesian_projection(i)(b).to_matrix()
-                      for i in range(m) ))
-            for b in self.basis()
-        )
+        basis = []
+        zero = MS.zero()
+        for i in range(m):
+            for b in factors[i].matrix_basis():
+                z = list(zero)
+                z[i] = b
+                basis.append(z)
+
+        basis = tuple( MS(b) for b in basis )
 
         # Define jordan/inner products that operate on that matrix_basis.
         def jordan_product(x,y):
             return MS(tuple(
-                (Js[i](x[i])*Js[i](y[i])).to_matrix() for i in range(m)
+                (factors[i](x[i])*factors[i](y[i])).to_matrix() for i in range(m)
             ))
 
         def inner_product(x, y):
             return sum(
-                Js[i](x[i]).inner_product(Js[i](y[i])) for i in range(m)
+                factors[i](x[i]).inner_product(factors[i](y[i])) for i in range(m)
             )
 
         # There's no need to check the field since it already came
@@ -3192,50 +3220,12 @@ class CartesianProductEJA(CombinatorialFreeModule_CartesianProduct,
                                       check_field=False,
                                       check_axioms=False)
 
-        ones = tuple(J.one() for J in algebras)
-        self.one.set_cache(self._cartesian_product_of_elements(ones))
-        self.rank.set_cache(sum(J.rank() for J in algebras))
-
-    def product_on_basis(self, i, j):
-        r"""
-        Return the product of the monomials indexed by ``i`` and ``j``.
-
-        This overrides the superclass method because here, both ``i``
-        and ``j`` will be ordered pairs.
-
-        SETUP::
-
-            sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
-            ....:                                  JordanSpinEJA,
-            ....:                                  RealSymmetricEJA)
+        ones = tuple(J.one().to_matrix() for J in factors)
+        self.one.set_cache(self(ones))
+        self.rank.set_cache(sum(J.rank() for J in factors))
 
-        TESTS::
-
-            sage: J1 = RealSymmetricEJA(2,field=QQ,orthonormalize=False)
-            sage: J2 = ComplexHermitianEJA(0,field=QQ,orthonormalize=False)
-            sage: J3 = JordanSpinEJA(2,field=QQ,orthonormalize=False)
-            sage: J = cartesian_product([J1,J2,J3])
-            sage: x = sum(J.gens())
-            sage: x*J.one()
-            e(0, 0) + e(0, 1) + e(0, 2) + e(2, 0) + e(2, 1)
-            sage: x*x
-            2*e(0, 0) + 2*e(0, 1) + 2*e(0, 2) + 2*e(2, 0) + 2*e(2, 1)
-
-        """
-        factor = i[0]
-        assert(j[0] == i[0])
-        n = self.cartesian_factors()[factor].dimension()
-
-        # The superclass method indexes into a matrix, so we have to
-        # turn the tuples i and j into integers. This is easy enough
-        # given that the first coordinate of i and j corresponds to
-        # the factor, and the second coordinate corresponds to the
-        # index of the generator within that factor. And of course
-        # we should never be multiplying two elements from different
-        # factors.
-        l = n*factor + i[1]
-        m = n*factor + j[1]
-        super().product_on_basis(l, m)
+    def cartesian_factors(self):
+        return self._sets
 
     def matrix_space(self):
         r"""
@@ -3333,8 +3323,11 @@ class CartesianProductEJA(CombinatorialFreeModule_CartesianProduct,
 
         """
         Ji = self.cartesian_factors()[i]
-        # Requires the fix on Trac 31421/31422 to work!
-        Pi = super().cartesian_projection(i)
+
+        Pi = self._module_morphism(lambda j_t: Ji.monomial(j_t[1])
+                                   if i == j_t[0] else Ji.zero(),
+                                   codomain=Ji)
+
         return FiniteDimensionalEJAOperator(self,Ji,Pi.matrix())
 
     @cached_method
@@ -3441,8 +3434,8 @@ class CartesianProductEJA(CombinatorialFreeModule_CartesianProduct,
 
         """
         Ji = self.cartesian_factors()[i]
-        # Requires the fix on Trac 31421/31422 to work!
-        Ei = super().cartesian_embedding(i)
+        Ei = Ji._module_morphism(lambda t: self.monomial((i, t)),
+                                 codomain=self)
         return FiniteDimensionalEJAOperator(Ji,self,Ei.matrix())
 
 
@@ -3488,3 +3481,16 @@ class RationalBasisCartesianProductEJA(CartesianProductEJA,
 RationalBasisEJA.CartesianProduct = RationalBasisCartesianProductEJA
 
 random_eja = ConcreteEJA.random_instance
+
+# def random_eja(*args, **kwargs):
+#     J1 = ConcreteEJA.random_instance(*args, **kwargs)
+
+#     # This might make Cartesian products appear roughly as often as
+#     # any other ConcreteEJA.
+#     if ZZ.random_element(len(ConcreteEJA.__subclasses__()) + 1) == 0:
+#         # Use random_eja() again so we can get more than two factors.
+#         J2 = random_eja(*args, **kwargs)
+#         J = cartesian_product([J1,J2])
+#         return J
+#     else:
+#         return J1