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]
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::
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())
"""
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)) )
@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::
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):
# 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):