From 4d2f874e306baa8d99fd938e978b8c968ca3a82e Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 13 Mar 2021 08:14:33 -0500 Subject: [PATCH] eja: skip FDEJA constructor in CartesianProductEJA. --- mjo/eja/eja_algebra.py | 107 +++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 46 deletions(-) diff --git a/mjo/eja/eja_algebra.py b/mjo/eja/eja_algebra.py index 7918759..79efd38 100644 --- a/mjo/eja/eja_algebra.py +++ b/mjo/eja/eja_algebra.py @@ -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) -- 2.43.2