From 8b70663d4c5e51aa5bd0a567c289f67e5ff8c000 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 29 Jul 2019 23:26:49 -0400 Subject: [PATCH] eja: implement subalgebra_generated_by() in terms of the new class. --- mjo/eja/eja_element.py | 95 ++++++--------------------------------- mjo/eja/eja_subalgebra.py | 67 ++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 91 deletions(-) diff --git a/mjo/eja/eja_element.py b/mjo/eja/eja_element.py index a8594ca..00a15a1 100644 --- a/mjo/eja/eja_element.py +++ b/mjo/eja/eja_element.py @@ -5,6 +5,8 @@ from sage.modules.free_module import VectorSpace # TODO: make this unnecessary somehow. from sage.misc.lazy_import import lazy_import lazy_import('mjo.eja.eja_algebra', 'FiniteDimensionalEuclideanJordanAlgebra') +lazy_import('mjo.eja.eja_subalgebra', + 'FiniteDimensionalEuclideanJordanElementSubalgebra') from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator from mjo.eja.eja_utils import _mat2vec @@ -702,7 +704,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle True """ - return self.span_of_powers().dimension() + return self.subalgebra_generated_by().dimension() def left_matrix(self): @@ -780,13 +782,8 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle 0 """ - V = self.span_of_powers() - assoc_subalg = self.subalgebra_generated_by() - # Mis-design warning: the basis used for span_of_powers() - # and subalgebra_generated_by() must be the same, and in - # the same order! - elt = assoc_subalg(V.coordinates(self.vector())) - return elt.operator().minimal_polynomial() + A = self.subalgebra_generated_by() + return A(self).operator().minimal_polynomial() @@ -992,19 +989,6 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle return ( L*M + M*L - (self*other).operator() ) - def span_of_powers(self): - """ - Return the vector space spanned by successive powers of - this element. - """ - # The dimension of the subalgebra can't be greater than - # the big algebra, so just put everything into a list - # and let span() get rid of the excess. - # - # We do the extra ambient_vector_space() in case we're messing - # with polynomials and the direct parent is a module. - V = self.parent().vector_space() - return V.span( (self**d).vector() for d in xrange(V.dimension()) ) def subalgebra_generated_by(self): @@ -1028,54 +1012,12 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle sage: set_random_seed() sage: x = random_eja().random_element() - sage: u = x.subalgebra_generated_by().random_element() - sage: u.operator()(u) == u^2 + sage: A = x.subalgebra_generated_by() + sage: A(x^2) == A(x)*A(x) True """ - # First get the subspace spanned by the powers of myself... - V = self.span_of_powers() - F = self.base_ring() - - # Now figure out the entries of the right-multiplication - # matrix for the successive basis elements b0, b1,... of - # that subspace. - mats = [] - for b_right in V.basis(): - eja_b_right = self.parent()(b_right) - b_right_rows = [] - # The first row of the right-multiplication matrix by - # b1 is what we get if we apply that matrix to b1. The - # second row of the right multiplication matrix by b1 - # is what we get when we apply that matrix to b2... - # - # IMPORTANT: this assumes that all vectors are COLUMN - # vectors, unlike our superclass (which uses row vectors). - for b_left in V.basis(): - eja_b_left = self.parent()(b_left) - # Multiply in the original EJA, but then get the - # coordinates from the subalgebra in terms of its - # basis. - this_row = V.coordinates((eja_b_left*eja_b_right).vector()) - b_right_rows.append(this_row) - b_right_matrix = matrix(F, b_right_rows) - mats.append(b_right_matrix) - - # It's an algebra of polynomials in one element, and EJAs - # are power-associative. - # - # TODO: choose generator names intelligently. - # - # The rank is the highest possible degree of a minimal polynomial, - # and is bounded above by the dimension. We know in this case that - # there's an element whose minimal polynomial has the same degree - # as the space's dimension, so that must be its rank too. - return FiniteDimensionalEuclideanJordanAlgebra( - F, - mats, - V.dimension(), - assume_associative=True, - names='f') + return FiniteDimensionalEuclideanJordanElementSubalgebra(self) def subalgebra_idempotent(self): @@ -1102,18 +1044,14 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle if self.is_nilpotent(): raise ValueError("this only works with non-nilpotent elements!") - V = self.span_of_powers() J = self.subalgebra_generated_by() - # Mis-design warning: the basis used for span_of_powers() - # and subalgebra_generated_by() must be the same, and in - # the same order! - u = J(V.coordinates(self.vector())) + u = J(self) # The image of the matrix of left-u^m-multiplication # will be minimal for some natural number s... s = 0 - minimal_dim = V.dimension() - for i in xrange(1, V.dimension()): + minimal_dim = J.dimension() + for i in xrange(1, minimal_dim): this_dim = (u**i).operator().matrix().image().dimension() if this_dim < minimal_dim: minimal_dim = this_dim @@ -1132,15 +1070,10 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle # Our FiniteDimensionalAlgebraElement superclass uses rows. u_next = u**(s+1) A = u_next.operator().matrix() - c_coordinates = A.solve_right(u_next.vector()) + c = J(A.solve_right(u_next.vector())) - # Now c_coordinates is the idempotent we want, but it's in - # the coordinate system of the subalgebra. - # - # We need the basis for J, but as elements of the parent algebra. - # - basis = [self.parent(v) for v in V.basis()] - return self.parent().linear_combination(zip(c_coordinates, basis)) + # Now c is the idempotent we want, but it still lives in the subalgebra. + return c.superalgebra_element() def trace(self): diff --git a/mjo/eja/eja_subalgebra.py b/mjo/eja/eja_subalgebra.py index 7c883d9..0ff3519 100644 --- a/mjo/eja/eja_subalgebra.py +++ b/mjo/eja/eja_subalgebra.py @@ -16,7 +16,7 @@ class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclide # First compute the vector subspace spanned by the powers of # the given element. V = superalgebra.vector_space() - eja_basis = [superalgebra.one()] + superalgebra_basis = [superalgebra.one()] basis_vectors = [superalgebra.one().vector()] W = V.span_of_basis(basis_vectors) for exponent in range(1, V.dimension()): @@ -24,21 +24,21 @@ class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclide basis_vectors.append( new_power.vector() ) try: W = V.span_of_basis(basis_vectors) - eja_basis.append( new_power ) + superalgebra_basis.append( new_power ) except ValueError: # Vectors weren't independent; bail and keep the # last subspace that worked. break # Make the basis hashable for UniqueRepresentation. - eja_basis = tuple(eja_basis) + superalgebra_basis = tuple(superalgebra_basis) # Now figure out the entries of the right-multiplication # matrix for the successive basis elements b0, b1,... of # that subspace. F = superalgebra.base_ring() mult_table = [] - for b_right in eja_basis: + for b_right in superalgebra_basis: b_right_rows = [] # The first row of the right-multiplication matrix by # b1 is what we get if we apply that matrix to b1. The @@ -47,7 +47,7 @@ class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclide # # IMPORTANT: this assumes that all vectors are COLUMN # vectors, unlike our superclass (which uses row vectors). - for b_left in eja_basis: + for b_left in superalgebra_basis: # Multiply in the original EJA, but then get the # coordinates from the subalgebra in terms of its # basis. @@ -87,7 +87,7 @@ class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclide F, mult_table, rank, - eja_basis, + superalgebra_basis, W, assume_associative=assume_associative, names=names, @@ -98,16 +98,16 @@ class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclide field, mult_table, rank, - eja_basis, + superalgebra_basis, vector_space, assume_associative=True, names='f', category=None, natural_basis=None): - self._superalgebra = eja_basis[0].parent() + self._superalgebra = superalgebra_basis[0].parent() self._vector_space = vector_space - self._eja_basis = eja_basis + self._superalgebra_basis = superalgebra_basis fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, self) fdeja.__init__(field, @@ -119,6 +119,13 @@ class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclide natural_basis=natural_basis) + def superalgebra(self): + """ + Return the superalgebra that this algebra was generated from. + """ + return self._superalgebra + + def vector_space(self): """ SETUP:: @@ -167,7 +174,7 @@ class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclide :: """ - if elt in A._superalgebra: + if elt in A.superalgebra(): # Try to convert a parent algebra element into a # subalgebra element... try: @@ -180,3 +187,43 @@ class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclide FiniteDimensionalEuclideanJordanAlgebraElement.__init__(self, A, elt) + + 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.vector(), self.parent()._superalgebra_basis) ) -- 2.43.2