assume_associative=False,
category=None,
rank=None,
- natural_basis=None,
- inner_product=None):
+ natural_basis=None):
n = len(mult_table)
mult_table = [b.base_extend(field) for b in mult_table]
for b in mult_table:
names=names,
category=cat,
rank=rank,
- natural_basis=natural_basis,
- inner_product=inner_product)
+ natural_basis=natural_basis)
def __init__(self,
assume_associative=False,
category=None,
rank=None,
- natural_basis=None,
- inner_product=None):
+ natural_basis=None):
"""
EXAMPLES:
"""
self._rank = rank
self._natural_basis = natural_basis
- self._inner_product = inner_product
fda = super(FiniteDimensionalEuclideanJordanAlgebra, self)
fda.__init__(field,
mult_table,
"""
The inner product associated with this Euclidean Jordan algebra.
- Will default to the trace inner product if nothing else.
+ Defaults to the trace inner product, but can be overridden by
+ subclasses if they are sure that the necessary properties are
+ satisfied.
EXAMPLES:
"""
if (not x in self) or (not y in self):
raise TypeError("arguments must live in this algebra")
- if self._inner_product is None:
- return x.trace_inner_product(y)
- else:
- return self._inner_product(x,y)
+ return x.trace_inner_product(y)
def natural_basis(self):
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
+ zero, but we need the characteristic polynomial for the
+ determinant. The minimal polynomial is a lot easier to get,
+ so we use Corollary 2 in Chapter V of Koecher to check
+ whether or not the paren't algebra's zero element is a root
+ of this element's minimal polynomial.
+
+ TESTS:
+
+ The identity element is always invertible::
+
+ sage: set_random_seed()
+ sage: J = random_eja()
+ sage: J.one().is_invertible()
+ True
+
+ The zero element is never invertible::
+
+ sage: set_random_seed()
+ sage: J = random_eja()
+ sage: J.zero().is_invertible()
+ False
+
"""
- return not self.det().is_zero()
+ zero = self.parent().zero()
+ p = self.minimal_polynomial()
+ return not (p(zero) == zero)
def is_nilpotent(self):
def minimal_polynomial(self):
"""
+ ALGORITHM:
+
+ We restrict ourselves to the associative subalgebra
+ generated by this element, and then return the minimal
+ polynomial of this element's operator matrix (in that
+ subalgebra). This works by Baes Proposition 2.3.16.
+
EXAMPLES::
sage: set_random_seed()
True
"""
- # The element we're going to call "minimal_polynomial()" 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.minimal_polynomial()
+ 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_matrix().minimal_polynomial()
def natural_representation(self):
# 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.
- V = self.vector().parent()
+ #
+ # We do the extra ambient_vector_space() in case we're messing
+ # with polynomials and the direct parent is a module.
+ V = self.vector().parent().ambient_vector_space()
return V.span( (self**d).vector() for d in xrange(V.dimension()) )
TESTS::
sage: set_random_seed()
- sage: J = eja_rn(5)
+ sage: J = RealCartesianProductEJA(5)
sage: c = J.random_element().subalgebra_idempotent()
sage: c^2 == c
True
return (self*other).trace()
-def eja_rn(dimension, field=QQ):
+class RealCartesianProductEJA(FiniteDimensionalEuclideanJordanAlgebra):
"""
Return the Euclidean Jordan Algebra corresponding to the set
`R^n` under the Hadamard product.
+ Note: this is nothing more than the Cartesian product of ``n``
+ copies of the spin algebra. Once Cartesian product algebras
+ are implemented, this can go.
+
EXAMPLES:
This multiplication table can be verified by hand::
- sage: J = eja_rn(3)
+ sage: J = RealCartesianProductEJA(3)
sage: e0,e1,e2 = J.gens()
sage: e0*e0
e0
e2
"""
- # The FiniteDimensionalAlgebra constructor takes a list of
- # matrices, the ith representing right multiplication by the ith
- # basis element in the vector space. So if e_1 = (1,0,0), then
- # right (Hadamard) multiplication of x by e_1 picks out the first
- # component of x; and likewise for the ith basis element e_i.
- Qs = [ matrix(field, dimension, dimension, lambda k,j: 1*(k == j == i))
- for i in xrange(dimension) ]
+ @staticmethod
+ def __classcall_private__(cls, n, field=QQ):
+ # The FiniteDimensionalAlgebra constructor takes a list of
+ # matrices, the ith representing right multiplication by the ith
+ # basis element in the vector space. So if e_1 = (1,0,0), then
+ # right (Hadamard) multiplication of x by e_1 picks out the first
+ # component of x; and likewise for the ith basis element e_i.
+ Qs = [ matrix(field, n, n, lambda k,j: 1*(k == j == i))
+ for i in xrange(n) ]
- return FiniteDimensionalEuclideanJordanAlgebra(field,
- Qs,
- rank=dimension,
- inner_product=_usual_ip)
+ fdeja = super(RealCartesianProductEJA, cls)
+ return fdeja.__classcall_private__(cls, field, Qs, rank=n)
+ def inner_product(self, x, y):
+ return _usual_ip(x,y)
def random_eja():
"""
n = ZZ.random_element(1,5)
- constructor = choice([eja_rn,
+ constructor = choice([RealCartesianProductEJA,
JordanSpinEJA,
RealSymmetricEJA,
ComplexHermitianEJA,
Qi[0,0] = Qi[0,0] * ~field(2)
Qs.append(Qi)
+ # 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, cls)
- return fdeja.__classcall_private__(cls, field, Qs)
-
- def rank(self):
- """
- Return the rank of this Jordan Spin Algebra.
-
- 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).
- """
- return min(self.dimension(),2)
+ return fdeja.__classcall_private__(cls, field, Qs, rank=min(n,2))
def inner_product(self, x, y):
return _usual_ip(x,y)