for k in range(n) )
L_x = matrix(F, n, n, L_x_i_j)
+
+ r = None
+ if self.rank.is_in_cache():
+ r = self.rank()
+ # There's no need to pad the system with redundant
+ # columns if we *know* they'll be redundant.
+ n = r
+
# Compute an extra power in case the rank is equal to
# the dimension (otherwise, we would stop at x^(r-1)).
x_powers = [ (L_x**k)*self.one().to_vector()
AE = A.extended_echelon_form()
E = AE[:,n:]
A_rref = AE[:,:n]
- r = A_rref.rank()
+ if r is None:
+ r = A_rref.rank()
b = x_powers[r]
# The theory says that only the first "r" coefficients are
J = MatrixEuclideanJordanAlgebra(QQ,
basis,
normalize_basis=False)
- return J._charpoly_coefficients()
+ a = J._charpoly_coefficients()
+
+ # Unfortunately, changing the basis does change the
+ # coefficients of the characteristic polynomial, but since
+ # these are really the coefficients of the "characteristic
+ # polynomial of" function, everything is still nice and
+ # unevaluated. It's therefore "obvious" how scaling the
+ # basis affects the coordinate variables X1, X2, et
+ # cetera. Scaling the first basis vector up by "n" adds a
+ # factor of 1/n into every "X1" term, for example. So here
+ # we simply undo the basis_normalizer scaling that we
+ # performed earlier.
+ #
+ # TODO: make this access safe.
+ XS = a[0].variables()
+ subs_dict = { XS[i]: self._basis_normalizers[i]*XS[i]
+ for i in range(len(XS)) }
+ return tuple( a_i.subs(subs_dict) for a_i in a )
@staticmethod