X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feja_algebra.py;h=1040d37071d9000cbbd69111306284e7a9745edc;hb=516438a5d7d7578d93c9780f62ceca41ae2e2f12;hp=40b4bcac6583e75f6877260f633d752b6693d8d7;hpb=86ec96a9ff510b4b3d178998d63b0ce9a374c444;p=sage.d.git diff --git a/mjo/eja/eja_algebra.py b/mjo/eja/eja_algebra.py index 40b4bca..1040d37 100644 --- a/mjo/eja/eja_algebra.py +++ b/mjo/eja/eja_algebra.py @@ -460,9 +460,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule): this algebra was constructed with ``check_axioms=False`` and passed an invalid multiplication table. """ - return all( self.product_on_basis(i,j) == self.product_on_basis(i,j) - for i in range(self.dimension()) - for j in range(self.dimension()) ) + return all( x*y == y*x for x in self.gens() for y in self.gens() ) def _is_jordanian(self): r""" @@ -931,7 +929,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule): # And to each subsequent row, prepend an entry that belongs to # the left-side "header column." - M += [ [self.gens()[i]] + [ self.product_on_basis(i,j) + M += [ [self.gens()[i]] + [ self.gens()[i]*self.gens()[j] for j in range(n) ] for i in range(n) ] @@ -1994,11 +1992,11 @@ class RealSymmetricEJA(ConcreteEJA, RealMatrixEJA): if n <= 1: associative = True - super(RealSymmetricEJA, self).__init__(self._denormalized_basis(n), - self.jordan_product, - self.trace_inner_product, - associative=associative, - **kwargs) + super().__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 @@ -2088,7 +2086,7 @@ class ComplexMatrixEJA(MatrixEJA): True """ - super(ComplexMatrixEJA,cls).real_embed(M) + super().real_embed(M) n = M.nrows() # We don't need any adjoined elements... @@ -2135,7 +2133,7 @@ class ComplexMatrixEJA(MatrixEJA): True """ - super(ComplexMatrixEJA,cls).real_unembed(M) + super().real_unembed(M) n = ZZ(M.nrows()) d = cls.dimension_over_reals() F = cls.complex_extension(M.base_ring()) @@ -2287,11 +2285,11 @@ class ComplexHermitianEJA(ConcreteEJA, ComplexMatrixEJA): if n <= 1: associative = True - super(ComplexHermitianEJA, self).__init__(self._denormalized_basis(n), - self.jordan_product, - self.trace_inner_product, - associative=associative, - **kwargs) + super().__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(). @@ -2374,7 +2372,7 @@ class QuaternionMatrixEJA(MatrixEJA): True """ - super(QuaternionMatrixEJA,cls).real_embed(M) + super().real_embed(M) quaternions = M.base_ring() n = M.nrows() @@ -2429,7 +2427,7 @@ class QuaternionMatrixEJA(MatrixEJA): True """ - super(QuaternionMatrixEJA,cls).real_unembed(M) + super().real_unembed(M) n = ZZ(M.nrows()) d = cls.dimension_over_reals() @@ -2598,11 +2596,11 @@ class QuaternionHermitianEJA(ConcreteEJA, QuaternionMatrixEJA): if n <= 1: associative = True - super(QuaternionHermitianEJA, self).__init__(self._denormalized_basis(n), - self.jordan_product, - self.trace_inner_product, - associative=associative, - **kwargs) + super().__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 @@ -2835,11 +2833,11 @@ class BilinearFormEJA(ConcreteEJA): if n <= 2: associative = True - super(BilinearFormEJA, self).__init__(column_basis, - jordan_product, - inner_product, - associative=associative, - **kwargs) + super().__init__(column_basis, + jordan_product, + inner_product, + associative=associative, + **kwargs) # The rank of this algebra is two, unless we're in a # one-dimensional ambient space (because the rank is bounded @@ -2944,7 +2942,7 @@ class JordanSpinEJA(BilinearFormEJA): # But also don't pass check_field=False here, because the user # can pass in a field! - super(JordanSpinEJA, self).__init__(B, **kwargs) + super().__init__(B, **kwargs) @staticmethod def _max_random_instance_size(): @@ -3002,11 +3000,11 @@ class TrivialEJA(ConcreteEJA): if "orthonormalize" not in kwargs: kwargs["orthonormalize"] = False if "check_axioms" not in kwargs: kwargs["check_axioms"] = False - super(TrivialEJA, self).__init__(basis, - jordan_product, - inner_product, - associative=True, - **kwargs) + super().__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. @@ -3020,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 @@ -3117,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:: @@ -3144,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 @@ -3194,9 +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)) + 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)) + + def cartesian_factors(self): + return self._sets def matrix_space(self): r""" @@ -3294,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 @@ -3402,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()) @@ -3449,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