from sage.matrix.constructor import matrix from mjo.eja.eja_algebra import FiniteDimensionalEuclideanJordanAlgebra from mjo.eja.eja_element import FiniteDimensionalEuclideanJordanAlgebraElement class FiniteDimensionalEuclideanJordanSubalgebraElement(FiniteDimensionalEuclideanJordanAlgebraElement): """ SETUP:: sage: from mjo.eja.eja_algebra import random_eja TESTS:: The natural representation of an element in the subalgebra is the same as its natural representation in the superalgebra:: sage: set_random_seed() sage: A = random_eja().random_element().subalgebra_generated_by() sage: y = A.random_element() sage: actual = y.natural_representation() sage: expected = y.superalgebra_element().natural_representation() sage: actual == expected True The left-multiplication-by operator for elements in the subalgebra works like it does in the superalgebra, even if we orthonormalize our basis:: sage: set_random_seed() sage: x = random_eja(AA).random_element() sage: A = x.subalgebra_generated_by(orthonormalize_basis=True) sage: y = A.random_element() sage: y.operator()(A.one()) == y True """ def superalgebra_element(self): """ Return the object in our algebra's superalgebra that corresponds to myself. SETUP:: sage: from mjo.eja.eja_algebra import (RealSymmetricEJA, ....: random_eja) EXAMPLES:: sage: J = RealSymmetricEJA(3) sage: x = sum(J.gens()) sage: x e0 + e1 + e2 + e3 + e4 + e5 sage: A = x.subalgebra_generated_by() sage: A(x) f1 sage: A(x).superalgebra_element() e0 + e1 + e2 + e3 + e4 + e5 TESTS: We can convert back and forth faithfully:: sage: set_random_seed() sage: J = random_eja() sage: x = J.random_element() sage: A = x.subalgebra_generated_by() sage: A(x).superalgebra_element() == x True sage: y = A.random_element() sage: A(y.superalgebra_element()) == y True """ return self.parent().superalgebra().linear_combination( zip(self.parent()._superalgebra_basis, self.to_vector()) ) class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJordanAlgebra): """ A subalgebra of an EJA with a given basis. SETUP:: sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA, ....: JordanSpinEJA) TESTS: Ensure that our generator names don't conflict with the superalgebra:: sage: J = JordanSpinEJA(3) sage: J.one().subalgebra_generated_by().gens() (f0,) sage: J = JordanSpinEJA(3, prefix='f') sage: J.one().subalgebra_generated_by().gens() (g0,) sage: J = JordanSpinEJA(3, prefix='b') sage: J.one().subalgebra_generated_by().gens() (c0,) Ensure that we can find subalgebras of subalgebras:: sage: A = ComplexHermitianEJA(3).one().subalgebra_generated_by() sage: B = A.one().subalgebra_generated_by() sage: B.dimension() 1 """ def __init__(self, superalgebra, basis, rank=None, category=None): self._superalgebra = superalgebra V = self._superalgebra.vector_space() field = self._superalgebra.base_ring() if category is None: category = self._superalgebra.category() # A half-assed attempt to ensure that we don't collide with # the superalgebra's prefix (ignoring the fact that there # could be super-superelgrbas in scope). If possible, we # try to "increment" the parent algebra's prefix, although # this idea goes out the window fast because some prefixen # are off-limits. prefixen = [ 'f', 'g', 'h', 'a', 'b', 'c', 'd' ] try: prefix = prefixen[prefixen.index(self._superalgebra.prefix()) + 1] except ValueError: prefix = prefixen[0] basis_vectors = [ b.to_vector() for b in basis ] superalgebra_basis = [ self._superalgebra.from_vector(b) for b in basis_vectors ] W = V.span_of_basis( V.from_vector(v) for v in basis_vectors ) n = len(superalgebra_basis) mult_table = [[W.zero() for i in range(n)] for j in range(n)] for i in range(n): for j in range(n): product = superalgebra_basis[i]*superalgebra_basis[j] # product.to_vector() might live in a vector subspace # if our parent algebra is already a subalgebra. We # use V.from_vector() to make it "the right size" in # that case. product_vector = V.from_vector(product.to_vector()) mult_table[i][j] = W.coordinate_vector(product_vector) natural_basis = tuple( b.natural_representation() for b in superalgebra_basis ) self._vector_space = W self._superalgebra_basis = superalgebra_basis fdeja = super(FiniteDimensionalEuclideanJordanSubalgebra, self) return fdeja.__init__(field, mult_table, rank, prefix=prefix, category=category, natural_basis=natural_basis) def _element_constructor_(self, elt): """ Construct an element of this subalgebra from the given one. The only valid arguments are elements of the parent algebra that happen to live in this subalgebra. SETUP:: sage: from mjo.eja.eja_algebra import RealSymmetricEJA sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra EXAMPLES:: sage: J = RealSymmetricEJA(3) sage: X = matrix(QQ, [ [0,0,1], ....: [0,1,0], ....: [1,0,0] ]) sage: x = J(X) sage: basis = ( x, x^2 ) # x^2 is the identity matrix sage: K = FiniteDimensionalEuclideanJordanSubalgebra(J, basis) sage: K(J.one()) f1 sage: K(J.one() + x) f0 + f1 :: """ if elt not in self.superalgebra(): raise ValueError("not an element of this subalgebra") coords = self.vector_space().coordinate_vector(elt.to_vector()) return self.from_vector(coords) def natural_basis_space(self): """ Return the natural basis space of this algebra, which is identical to that of its superalgebra. This is correct "by definition," and avoids a mismatch when the subalgebra is trivial (with no natural basis to infer anything from) and the parent is not. """ return self.superalgebra().natural_basis_space() def superalgebra(self): """ Return the superalgebra that this algebra was generated from. """ return self._superalgebra def vector_space(self): """ SETUP:: sage: from mjo.eja.eja_algebra import RealSymmetricEJA sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra EXAMPLES:: sage: J = RealSymmetricEJA(3) sage: E11 = matrix(QQ, [ [1,0,0], ....: [0,0,0], ....: [0,0,0] ]) sage: E22 = matrix(QQ, [ [0,0,0], ....: [0,1,0], ....: [0,0,0] ]) sage: b1 = J(E11) sage: b2 = J(E22) sage: basis = (b1, b2) sage: K = FiniteDimensionalEuclideanJordanSubalgebra(J,basis) sage: K.vector_space() Vector space of degree 6 and dimension 2 over... User basis matrix: [1 0 0 0 0 0] [0 0 1 0 0 0] sage: b1.to_vector() (1, 0, 0, 0, 0, 0) sage: b2.to_vector() (0, 0, 1, 0, 0, 0) """ return self._vector_space Element = FiniteDimensionalEuclideanJordanSubalgebraElement