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()) )