X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feja_algebra.py;h=edba0987e946a23e193f45c62fec5288a416e617;hb=e2889fbafac1462ad8a8624266c5c659a7acc15f;hp=ed8c85c9f60dc30c0b1f959533208b81e542b734;hpb=f69c89ed86f1e6fd4ee44f5e7df73680801ed6f2;p=sage.d.git diff --git a/mjo/eja/eja_algebra.py b/mjo/eja/eja_algebra.py index ed8c85c..edba098 100644 --- a/mjo/eja/eja_algebra.py +++ b/mjo/eja/eja_algebra.py @@ -32,10 +32,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): def __classcall_private__(cls, field, mult_table, + rank, names='e', assume_associative=False, category=None, - rank=None, natural_basis=None): n = len(mult_table) mult_table = [b.base_extend(field) for b in mult_table] @@ -56,20 +56,20 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): return fda.__classcall__(cls, field, mult_table, + rank=rank, assume_associative=assume_associative, names=names, category=cat, - rank=rank, natural_basis=natural_basis) def __init__(self, field, mult_table, + rank, names='e', assume_associative=False, category=None, - rank=None, natural_basis=None): """ SETUP:: @@ -101,6 +101,20 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): def _repr_(self): """ Return a string representation of ``self``. + + SETUP:: + + sage: from mjo.eja.eja_algebra import JordanSpinEJA + + TESTS: + + Ensure that it says what we think it says:: + + sage: JordanSpinEJA(2, field=QQ) + Euclidean Jordan algebra of degree 2 over Rational Field + sage: JordanSpinEJA(3, field=RDF) + Euclidean Jordan algebra of degree 3 over Real Double Field + """ fmt = "Euclidean Jordan algebra of degree {} over {}" return fmt.format(self.degree(), self.base_ring()) @@ -110,6 +124,21 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): """ Guess a regular element. Needed to compute the basis for our characteristic polynomial coefficients. + + SETUP:: + + sage: from mjo.eja.eja_algebra import random_eja + + TESTS: + + Ensure that this hacky method succeeds for every algebra that we + know how to construct:: + + sage: set_random_seed() + sage: J = random_eja() + sage: J._a_regular_element().is_regular() + True + """ gs = self.gens() z = self.sum( (i+1)*gs[i] for i in range(len(gs)) ) @@ -218,19 +247,16 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): @cached_method def characteristic_polynomial(self): """ + Return a characteristic polynomial that works for all elements + of this algebra. - .. WARNING:: - - This implementation doesn't guarantee that the polynomial - denominator in the coefficients is not identically zero, so - theoretically it could crash. The way that this is handled - in e.g. Faraut and Koranyi is to use a basis that guarantees - the denominator is non-zero. But, doing so requires knowledge - of at least one regular element, and we don't even know how - to do that. The trade-off is that, if we use the standard basis, - the resulting polynomial will accept the "usual" coordinates. In - other words, we don't have to do a change of basis before e.g. - computing the trace or determinant. + The resulting polynomial has `n+1` variables, where `n` is the + dimension of this algebra. The first `n` variables correspond to + the coordinates of an algebra element: when evaluated at the + coordinates of an algebra element with respect to a certain + basis, the result is a univariate polynomial (in the one + remaining variable ``t``), namely the characteristic polynomial + of that element. SETUP:: @@ -360,11 +386,61 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): def rank(self): """ Return the rank of this EJA. + + ALGORITHM: + + The author knows of no algorithm to compute the rank of an EJA + where only the multiplication table is known. In lieu of one, we + require the rank to be specified when the algebra is created, + and simply pass along that number here. + + SETUP:: + + sage: from mjo.eja.eja_algebra import (JordanSpinEJA, + ....: RealSymmetricEJA, + ....: ComplexHermitianEJA, + ....: QuaternionHermitianEJA, + ....: random_eja) + + EXAMPLES: + + The rank of the Jordan spin algebra is always two:: + + sage: JordanSpinEJA(2).rank() + 2 + sage: JordanSpinEJA(3).rank() + 2 + sage: JordanSpinEJA(4).rank() + 2 + + The rank of the `n`-by-`n` Hermitian real, complex, or + quaternion matrices is `n`:: + + sage: RealSymmetricEJA(2).rank() + 2 + sage: ComplexHermitianEJA(2).rank() + 2 + sage: QuaternionHermitianEJA(2).rank() + 2 + sage: RealSymmetricEJA(5).rank() + 5 + sage: ComplexHermitianEJA(5).rank() + 5 + sage: QuaternionHermitianEJA(5).rank() + 5 + + TESTS: + + Ensure that every EJA that we know how to construct has a + positive integer rank:: + + sage: set_random_seed() + sage: r = random_eja().rank() + sage: r in ZZ and r > 0 + True + """ - if self._rank is None: - raise ValueError("no rank specified at genesis") - else: - return self._rank + return self._rank def vector_space(self): @@ -405,7 +481,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): SETUP:: - sage: from mjo.eja.eja_algebra import RealSymmetricEJA + sage: from mjo.eja.eja_algebra import (RealSymmetricEJA, + ....: random_eja) EXAMPLES: @@ -425,6 +502,18 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): ... ArithmeticError: vector is not in free module + TESTS: + + Ensure that we can convert any element of the parent's + underlying vector space back into an algebra element whose + vector representation is what we started with:: + + sage: set_random_seed() + sage: J = random_eja() + sage: v = J.vector_space().random_element() + sage: J(v).vector() == v + True + """ # Goal: if we're given a matrix, and if it lives in our # parent algebra's "natural ambient space," convert it @@ -457,21 +546,21 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): Jordan algebras are always power-associative; see for example Faraut and Koranyi, Proposition II.1.2 (ii). - .. WARNING: - - We have to override this because our superclass uses row vectors - instead of column vectors! We, on the other hand, assume column - vectors everywhere. + We have to override this because our superclass uses row + vectors instead of column vectors! We, on the other hand, + assume column vectors everywhere. SETUP:: sage: from mjo.eja.eja_algebra import random_eja - EXAMPLES:: + TESTS: + + The definition of `x^2` is the unambiguous `x*x`:: sage: set_random_seed() sage: x = random_eja().random_element() - sage: x.operator()(x) == (x^2) + sage: x*x == (x^2) True A few examples of power-associativity:: @@ -577,6 +666,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): sage: J.zero().characteristic_polynomial() t^3 + TESTS: + The characteristic polynomial of an element should evaluate to zero on that element:: @@ -694,8 +785,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): sage: lhs == rhs True - Test the first polarization identity from my notes, Koecher Chapter - III, or from Baes (2.3):: + Test the first polarization identity from my notes, Koecher + Chapter III, or from Baes (2.3):: sage: set_random_seed() sage: J = random_eja() @@ -878,9 +969,6 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): """ Return whether or not this element is invertible. - We can't use the superclass method because it relies on - the algebra being associative. - ALGORITHM: The usual way to do this is to check if the determinant is @@ -890,6 +978,9 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): whether or not the paren't algebra's zero element is a root of this element's minimal polynomial. + Beware that we can't use the superclass method, because it + relies on the algebra being associative. + SETUP:: sage: from mjo.eja.eja_algebra import random_eja @@ -920,14 +1011,26 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): """ Return whether or not some power of this element is zero. - The superclass method won't work unless we're in an - associative algebra, and we aren't. However, we generate - an assocoative subalgebra and we're nilpotent there if and - only if we're nilpotent here (probably). + ALGORITHM: + + We use Theorem 5 in Chapter III of Koecher, which says that + an element ``x`` is nilpotent if and only if ``x.operator()`` + is nilpotent. And it is a basic fact of linear algebra that + an operator on an `n`-dimensional space is nilpotent if and + only if, when raised to the `n`th power, it equals the zero + operator (for example, see Axler Corollary 8.8). SETUP:: - sage: from mjo.eja.eja_algebra import random_eja + sage: from mjo.eja.eja_algebra import (JordanSpinEJA, + ....: random_eja) + + EXAMPLES:: + + sage: J = JordanSpinEJA(3) + sage: x = sum(J.gens()) + sage: x.is_nilpotent() + False TESTS: @@ -944,25 +1047,9 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): True """ - # The element we're going to call "is_nilpotent()" on. - # Either myself, interpreted as an element of a finite- - # dimensional algebra, or an element of an associative - # subalgebra. - elt = None - - if self.parent().is_associative(): - elt = FiniteDimensionalAlgebraElement(self.parent(), self) - else: - 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())) - - # Recursive call, but should work since elt lives in an - # associative algebra. - return elt.is_nilpotent() + P = self.parent() + zero_operator = P.zero().operator() + return self.operator()**P.dimension() == zero_operator def is_regular(self): @@ -1388,7 +1475,17 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): # are power-associative. # # TODO: choose generator names intelligently. - return FiniteDimensionalEuclideanJordanAlgebra(F, mats, assume_associative=True, names='f') + # + # 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') def subalgebra_idempotent(self):