X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feja_algebra.py;h=4b8d466c3456f9ec1daf6ca2d701f3078a3524d1;hb=ef4a0674cdc17613ce65103fc679506e7c7008de;hp=689a3db016437d1e6eda5c6372e52a3513896671;hpb=3a476bd1ea5aef3ecd375e71d50342f1441fd35d;p=sage.d.git diff --git a/mjo/eja/eja_algebra.py b/mjo/eja/eja_algebra.py index 689a3db..4b8d466 100644 --- a/mjo/eja/eja_algebra.py +++ b/mjo/eja/eja_algebra.py @@ -773,6 +773,65 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule): return (J0, J5, J1) + def orthogonal_idempotents(self): + r""" + Generate a set of `r` orthogonal idempotents for this algebra, + where `r` is its rank. + + This implementation is based on the so-called "central + orthogonal idempotents" implemented for (semisimple) centers + of SageMath ``FiniteDimensionalAlgebrasWithBasis``. Since all + Euclidean Jordan algebas are commutative (and thus equal to + their own centers) and semisimple, the method should work more + or less as implemented, if it ever worked in the first place. + (I don't know the justification for the original implementation. + yet). + + How it works: we loop through the algebras generators, looking + for their eigenspaces. If there's more than one eigenspace, + and if they result in more than one subalgebra, then we split + those subalgebras recursively until we get to subalgebras of + dimension one (whose idempotent is the unit element). Why does + some generator have to produce at least two subalgebras? I + dunno. But it seems to work. + + Beware that Koecher defines the "center" of a Jordan algebra to + be something else, because the usual definition is stupid in a + (necessarily commutative) Jordan algebra. + """ + if self.dimension() == 1: + return [self.one()] + + for g in self.gens(): + eigenpairs = g.operator().matrix().right_eigenspaces() + if len(eigenpairs) >= 2: + subalgebras = [] + for eigval, eigspace in eigenpairs: + # Make sub-EJAs from the matrix eigenspaces... + sb = tuple( self.from_vector(b) for b in eigspace.basis() ) + try: + # This will fail if e.g. the eigenspace basis + # contains two elements and their product + # isn't a linear combination of the two of + # them (i.e. the generated EJA isn't actually + # two dimensional). + s = FiniteDimensionalEuclideanJordanSubalgebra(self, sb) + subalgebras.append(s) + except: + pass + if len(subalgebras) >= 2: + # apply this method recursively. + return tuple( c.superalgebra_element() + for subalgebra in subalgebras + for c in subalgebra.orthogonal_idempotents() ) + + # If we got here, the algebra didn't decompose, at least not when we looked at + # the eigenspaces corresponding only to basis elements of the algebra. The + # implementation I stole says that this should work because of Schur's Lemma, + # so I personally blame Schur's Lemma if it does not. + raise Exception("Schur's Lemma didn't work!") + + def random_elements(self, count): """ Return ``count`` random elements as a tuple. @@ -1994,23 +2053,20 @@ class BilinearFormEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA): TESTS: - Ensure that this is one-half of the trace inner-product:: + Ensure that this is one-half of the trace inner-product when + the algebra isn't just the reals (when ``n`` isn't one). This + is in Faraut and Koranyi, and also my "On the symmetry..." + paper:: sage: set_random_seed() - sage: n = ZZ.random_element(5) - sage: M = matrix.random(QQ, n-1, algorithm='unimodular') + sage: n = ZZ.random_element(2,5) + sage: M = matrix.random(QQ, max(0,n-1), algorithm='unimodular') sage: B = M.transpose()*M sage: J = BilinearFormEJA(n, B=B) - sage: eis = VectorSpace(M.base_ring(), M.ncols()).basis() - sage: V = J.vector_space() - sage: sis = [ J.from_vector(V([0] + (M.inverse()*ei).list())) - ....: for ei in eis ] - sage: actual = [ sis[i]*sis[j] - ....: for i in range(n-1) - ....: for j in range(n-1) ] - sage: expected = [ J.one() if i == j else J.zero() - ....: for i in range(n-1) - ....: for j in range(n-1) ] + sage: x = J.random_element() + sage: y = J.random_element() + sage: x.inner_product(y) == (x*y).trace()/2 + True """ xvec = x.to_vector() @@ -2019,7 +2075,8 @@ class BilinearFormEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA): ybar = yvec[1:] return x[0]*y[0] + (self._B*xbar).inner_product(ybar) -class JordanSpinEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA): + +class JordanSpinEJA(BilinearFormEJA): """ The rank-2 simple EJA consisting of real vectors ``x=(x0, x_bar)`` with the usual inner product and jordan product ``x*y = @@ -2056,42 +2113,9 @@ class JordanSpinEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA): sage: JordanSpinEJA(2, prefix='B').gens() (B0, B1) - """ - def __init__(self, n, field=QQ, **kwargs): - V = VectorSpace(field, n) - mult_table = [[V.zero() for j in range(n)] for i in range(n)] - for i in range(n): - for j in range(n): - x = V.gen(i) - y = V.gen(j) - x0 = x[0] - xbar = x[1:] - y0 = y[0] - ybar = y[1:] - # z = x*y - z0 = x.inner_product(y) - zbar = y0*xbar + x0*ybar - z = V([z0] + zbar.list()) - mult_table[i][j] = z - - # The rank of the spin algebra is two, unless we're in a - # one-dimensional ambient space (because the rank is bounded by - # the ambient dimension). - fdeja = super(JordanSpinEJA, self) - return fdeja.__init__(field, mult_table, rank=min(n,2), **kwargs) - - def inner_product(self, x, y): - """ - Faster to reimplement than to use natural representations. - - SETUP:: - - sage: from mjo.eja.eja_algebra import JordanSpinEJA - - TESTS: + TESTS: - Ensure that this is the usual inner product for the algebras - over `R^n`:: + Ensure that we have the usual inner product on `R^n`:: sage: set_random_seed() sage: J = JordanSpinEJA.random_instance() @@ -2101,8 +2125,11 @@ class JordanSpinEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA): sage: x.inner_product(y) == J.natural_inner_product(X,Y) True - """ - return x.to_vector().inner_product(y.to_vector()) + """ + def __init__(self, n, field=QQ, **kwargs): + # This is a special case of the BilinearFormEJA with the identity + # matrix as its bilinear form. + return super(JordanSpinEJA, self).__init__(n, field, **kwargs) class TrivialEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA):