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
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
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 _monomial_to_generator(self, mon):
- r"""
- Convert a monomial index into a generator index.
-
- This is needed in product algebras because the multiplication
- table is in terms of the generator indices.
-
- SETUP::
+ 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))
- sage: from mjo.eja.eja_algebra import random_eja
-
- TESTS::
-
- sage: J1 = random_eja(field=QQ, orthonormalize=False)
- sage: J2 = random_eja(field=QQ, orthonormalize=False)
- sage: J = cartesian_product([J1,J2])
- sage: all( J.monomial(m)
- ....: ==
- ....: J.gens()[J._monomial_to_generator(m)]
- ....: for m in J.basis().keys() )
- True
-
- """
- # This works recursively so that we can handle Cartesian
- # products of Cartesian products.
- try:
- # monomial is an ordered pair
- factor = mon[0]
- except TypeError: # 'int' object is not subscriptable
- # base case where the monomials are integers
- return mon
-
- idx_in_factor = self._monomial_to_generator(mon[1])
-
- offset = sum( f.dimension()
- for f in self.cartesian_factors()[:factor] )
- return offset + idx_in_factor
-
- 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 (HadamardEJA,
- ....: JordanSpinEJA,
- ....: QuaternionHermitianEJA,
- ....: RealSymmetricEJA,)
-
- EXAMPLES::
-
- sage: J1 = JordanSpinEJA(2, field=QQ)
- sage: J2 = RealSymmetricEJA(2, field=QQ, orthonormalize=False)
- sage: J3 = HadamardEJA(1, field=QQ)
- sage: K1 = cartesian_product([J1,J2])
- sage: K2 = cartesian_product([K1,J3])
- sage: list(K2.basis())
- [e(0, (0, 0)), e(0, (0, 1)), e(0, (1, 0)), e(0, (1, 1)),
- e(0, (1, 2)), e(1, 0)]
- sage: g = K2.gens()
- sage: (g[0] + 2*g[3]) * (g[1] - 4*g[2])
- e(0, (0, 1)) - 4*e(0, (1, 1))
-
- TESTS::
-
- sage: J1 = RealSymmetricEJA(1,field=QQ)
- sage: J2 = QuaternionHermitianEJA(1,field=QQ)
- sage: J = cartesian_product([J1,J2])
- sage: x = sum(J.gens())
- sage: x == J.one()
- True
- sage: x*x == x
- True
-
- """
- l = self._monomial_to_generator(i)
- m = self._monomial_to_generator(j)
- return FiniteDimensionalEJA.product_on_basis(self, l, m)
+ def cartesian_factors(self):
+ return self._sets
def matrix_space(self):
r"""
"""
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
"""
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())