]> gitweb.michael.orlitzky.com - sage.d.git/commitdiff
eja: skip FDEJA constructor in CartesianProductEJA.
authorMichael Orlitzky <michael@orlitzky.com>
Sat, 13 Mar 2021 13:14:33 +0000 (08:14 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Sat, 13 Mar 2021 13:14:33 +0000 (08:14 -0500)
mjo/eja/eja_algebra.py

index 79187594472d82e24a0b700305b7ddfc7b192536..79efd3876b6fadd0d2a7494a45856bf46bf3a621 100644 (file)
@@ -267,7 +267,6 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
                  matrix_space=None,
                  orthonormalize=True,
                  associative=None,
-                 cartesian_product=False,
                  check_field=True,
                  check_axioms=True,
                  prefix="b"):
@@ -306,11 +305,6 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         if associative:
             # Element subalgebras can take advantage of this.
             category = category.Associative()
-        if cartesian_product:
-            # Use join() here because otherwise we only get the
-            # "Cartesian product of..." and not the things themselves.
-            category = category.join([category,
-                                      category.CartesianProducts()])
 
         # Call the superclass constructor so that we can use its from_vector()
         # method to build our multiplication table.
@@ -385,7 +379,8 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         # Now we actually compute the multiplication and inner-product
         # tables/matrices using the possibly-orthonormalized basis.
         self._inner_product_matrix = matrix.identity(field, n)
-        self._multiplication_table = [ [0 for j in range(i+1)]
+        zed = self.zero()
+        self._multiplication_table = [ [zed for j in range(i+1)]
                                        for i in range(n) ]
 
         # Note: the Jordan and inner-products are defined in terms
@@ -3089,9 +3084,6 @@ class CartesianProductEJA(FiniteDimensionalEJA):
         True
 
     """
-    Element = FiniteDimensionalEJAElement
-
-
     def __init__(self, factors, **kwargs):
         m = len(factors)
         if m == 0:
@@ -3103,7 +3095,11 @@ class CartesianProductEJA(FiniteDimensionalEJA):
         if not all( J.base_ring() == field for J in factors ):
             raise ValueError("all factors must share the same base field")
 
+        # Figure out the category to use.
         associative = all( f.is_associative() for f in factors )
+        category = EuclideanJordanAlgebras(field)
+        if associative: category = category.Associative()
+        category = category.join([category, category.CartesianProducts()])
 
         # Compute my matrix space. This category isn't perfect, but
         # is good enough for what we need to do.
@@ -3111,55 +3107,74 @@ class CartesianProductEJA(FiniteDimensionalEJA):
         MS_cat = MS_cat.Unital().CartesianProducts()
         MS_factors = tuple( J.matrix_space() for J in factors )
         from sage.sets.cartesian_product import CartesianProduct
-        MS = CartesianProduct(MS_factors, MS_cat)
+        self._matrix_space = CartesianProduct(MS_factors, MS_cat)
 
-        basis = []
-        zero = MS.zero()
+        self._matrix_basis = []
+        zero = self._matrix_space.zero()
         for i in range(m):
             for b in factors[i].matrix_basis():
                 z = list(zero)
                 z[i] = b
-                basis.append(z)
+                self._matrix_basis.append(z)
 
-        basis = tuple( MS(b) for b in basis )
+        self._matrix_basis = tuple( self._matrix_space(b)
+                                    for b in self._matrix_basis )
+        n = len(self._matrix_basis)
 
-        # Define jordan/inner products that operate on that matrix_basis.
-        def jordan_product(x,y):
-            return MS(tuple(
-                (factors[i](x[i])*factors[i](y[i])).to_matrix()
-                for i in range(m)
-            ))
-
-        def inner_product(x, y):
-            return sum(
-                factors[i](x[i]).inner_product(factors[i](y[i]))
-                for i in range(m)
-            )
+        # We already have what we need for the super-superclass constructor.
+        CombinatorialFreeModule.__init__(self,
+                                         field,
+                                         range(n),
+                                         prefix="b",
+                                         category=category,
+                                         bracket=False)
 
-        # There's no need to check the field since it already came
-        # from an EJA. Likewise the axioms are guaranteed to be
-        # satisfied, unless the guy writing this class sucks.
-        #
-        # If you want the basis to be orthonormalized, orthonormalize
-        # the factors.
-        FiniteDimensionalEJA.__init__(self,
-                                      basis,
-                                      jordan_product,
-                                      inner_product,
-                                      field=field,
-                                      matrix_space=MS,
-                                      orthonormalize=False,
-                                      associative=associative,
-                                      cartesian_product=True,
-                                      check_field=False,
-                                      check_axioms=False)
+        # Now create the vector space for the algebra, which will have
+        # its own set of non-ambient coordinates (in terms of the
+        # supplied basis).
+        degree = sum( f._matrix_span.ambient_vector_space().degree()
+                      for f in factors )
+        V = VectorSpace(field, degree)
+        vector_basis = tuple( V(_all2list(b)) for b in self._matrix_basis )
+
+        # Save the span of our matrix basis (when written out as long
+        # vectors) because otherwise we'll have to reconstruct it
+        # every time we want to coerce a matrix into the algebra.
+        self._matrix_span = V.span_of_basis( vector_basis, check=False)
 
         # Since we don't (re)orthonormalize the basis, the FDEJA
         # constructor is going to set self._deortho_matrix to the
         # identity matrix. Here we set it to the correct value using
         # the deortho matrices from our factors.
-        self._deortho_matrix = matrix.block_diagonal( [J._deortho_matrix
-                                                       for J in factors] )
+        self._deortho_matrix = matrix.block_diagonal(
+            [J._deortho_matrix for J in factors]
+        )
+
+        self._inner_product_matrix = matrix.block_diagonal(
+            [J._inner_product_matrix for J in factors]
+        )
+
+        # Building the multiplication table is a bit more tricky
+        # because we have to embed the entries of the factors'
+        # multiplication tables into the product EJA.
+        zed = self.zero()
+        self._multiplication_table = [ [zed for j in range(i+1)]
+                                       for i in range(n) ]
+
+        # Keep track of an offset that tallies the dimensions of all
+        # previous factors. If the second factor is dim=2 and if the
+        # first one is dim=3, then we want to skip the first 3x3 block
+        # when copying the multiplication table for the second factor.
+        offset = 0
+        for f in range(m):
+            phi_f = self.cartesian_embedding(f)
+            factor_dim = factors[f].dimension()
+            for i in range(factor_dim):
+                for j in range(i+1):
+                    f_ij = factors[f]._multiplication_table[i][j]
+                    e = phi_f(f_ij)
+                    self._multiplication_table[offset+i][offset+j] = e
+            offset += factor_dim
 
         self.rank.set_cache(sum(J.rank() for J in factors))
         ones = tuple(J.one().to_matrix() for J in factors)