# Element subalgebras can take advantage of this.
category = category.Associative()
if cartesian_product:
- category = category.CartesianProducts()
+ # 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.
sage: if n > 0:
....: i = ZZ.random_element(n)
....: j = ZZ.random_element(n)
- ....: ei = J.gens()[i]
- ....: ej = J.gens()[j]
+ ....: ei = J.monomial(i)
+ ....: ej = J.monomial(j)
....: ei_ej = J.product_on_basis(i,j)
sage: ei*ej == ei_ej
True
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"""
return ``True``, unless this algebra was constructed with
``check_axioms=False`` and passed an invalid multiplication table.
"""
- return all( (self.gens()[i]**2)*(self.gens()[i]*self.gens()[j])
+ return all( (self.monomial(i)**2)*(self.monomial(i)*self.monomial(j))
==
- (self.gens()[i])*((self.gens()[i]**2)*self.gens()[j])
+ (self.monomial(i))*((self.monomial(i)**2)*self.monomial(j))
for i in range(self.dimension())
for j in range(self.dimension()) )
for i in range(self.dimension()):
for j in range(self.dimension()):
for k in range(self.dimension()):
- x = self.gens()[i]
- y = self.gens()[j]
- z = self.gens()[k]
+ x = self.monomial(i)
+ y = self.monomial(j)
+ z = self.monomial(k)
diff = (x*y)*z - x*(y*z)
if diff.norm() > epsilon:
for i in range(self.dimension()):
for j in range(self.dimension()):
for k in range(self.dimension()):
- x = self.gens()[i]
- y = self.gens()[j]
- z = self.gens()[k]
+ x = self.monomial(i)
+ y = self.monomial(j)
+ z = self.monomial(k)
diff = (x*y).inner_product(z) - x.inner_product(y*z)
if diff.abs() > epsilon:
sage: J2 = RealSymmetricEJA(2)
sage: J = cartesian_product([J1,J2])
sage: J( (J1.matrix_basis()[1], J2.matrix_basis()[2]) )
- e(0, 1) + e(1, 2)
+ e1 + e5
TESTS:
# 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.monomial(i)] + [ self.monomial(i)*self.monomial(j)
for j in range(n) ]
for i in range(n) ]
def L_x_i_j(i,j):
# From a result in my book, these are the entries of the
# basis representation of L_x.
- return sum( vars[k]*self.gens()[k].operator().matrix()[i,j]
+ return sum( vars[k]*self.monomial(k).operator().matrix()[i,j]
for k in range(n) )
L_x = matrix(F, n, n, L_x_i_j)
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
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()
+ +----++----+----+----+
+ | * || e0 | e1 | e2 |
+ +====++====+====+====+
+ | e0 || e0 | 0 | 0 |
+ +----++----+----+----+
+ | e1 || 0 | e1 | 0 |
+ +----++----+----+----+
+ | e2 || 0 | 0 | e2 |
+ +----++----+----+----+
+ 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::
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))
+ 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):
+ # Copy/pasted from CombinatorialFreeModule_CartesianProduct.
+ return self._sets
+
+ def cartesian_factor(self, i):
+ r"""
+ Return the ``i``th factor of this algebra.
+ """
+ return self._sets[i]
+
+ def _repr_(self):
+ # Copy/pasted from CombinatorialFreeModule_CartesianProduct.
+ from sage.categories.cartesian_product import cartesian_product
+ return cartesian_product.symbol.join("%s" % factor
+ for factor in self._sets)
def matrix_space(self):
r"""
True
"""
- Ji = self.cartesian_factors()[i]
- # Requires the fix on Trac 31421/31422 to work!
- Pi = super().cartesian_projection(i)
+ offset = sum( self.cartesian_factor(k).dimension()
+ for k in range(i) )
+ Ji = self.cartesian_factor(i)
+ Pi = self._module_morphism(lambda j: Ji.monomial(j - offset),
+ codomain=Ji)
+
return FiniteDimensionalEJAOperator(self,Ji,Pi.matrix())
@cached_method
True
"""
- Ji = self.cartesian_factors()[i]
- # Requires the fix on Trac 31421/31422 to work!
- Ei = super().cartesian_embedding(i)
+ offset = sum( self.cartesian_factor(k).dimension()
+ for k in range(i) )
+ Ji = self.cartesian_factor(i)
+ Ei = Ji._module_morphism(lambda j: self.monomial(j + offset),
+ codomain=self)
return FiniteDimensionalEJAOperator(Ji,self,Ei.matrix())
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