+
+
+class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
+ @staticmethod
+ def _max_test_case_size():
+ # Play it safe, since this will be squared and the underlying
+ # field can have dimension 4 (quaternions) too.
+ return 2
+
+ def __init__(self, field, basis, rank, normalize_basis=True, **kwargs):
+ """
+ Compared to the superclass constructor, we take a basis instead of
+ a multiplication table because the latter can be computed in terms
+ of the former when the product is known (like it is here).
+ """
+ # Used in this class's fast _charpoly_coeff() override.
+ self._basis_normalizers = None
+
+ # We're going to loop through this a few times, so now's a good
+ # time to ensure that it isn't a generator expression.
+ basis = tuple(basis)
+
+ if rank > 1 and normalize_basis:
+ # We'll need sqrt(2) to normalize the basis, and this
+ # winds up in the multiplication table, so the whole
+ # algebra needs to be over the field extension.
+ R = PolynomialRing(field, 'z')
+ z = R.gen()
+ p = z**2 - 2
+ if p.is_irreducible():
+ field = field.extension(p, 'sqrt2', embedding=RLF(2).sqrt())
+ basis = tuple( s.change_ring(field) for s in basis )
+ self._basis_normalizers = tuple(
+ ~(self.natural_inner_product(s,s).sqrt()) for s in basis )
+ basis = tuple(s*c for (s,c) in izip(basis,self._basis_normalizers))
+
+ Qs = self.multiplication_table_from_matrix_basis(basis)
+
+ fdeja = super(MatrixEuclideanJordanAlgebra, self)
+ return fdeja.__init__(field,
+ Qs,
+ rank=rank,
+ natural_basis=basis,
+ **kwargs)
+
+
+ @cached_method
+ def _charpoly_coeff(self, i):
+ """
+ Override the parent method with something that tries to compute
+ over a faster (non-extension) field.
+ """
+ if self._basis_normalizers is None:
+ # We didn't normalize, so assume that the basis we started
+ # with had entries in a nice field.
+ return super(MatrixEuclideanJordanAlgebra, self)._charpoly_coeff(i)
+ else:
+ basis = ( (b/n) for (b,n) in izip(self.natural_basis(),
+ self._basis_normalizers) )
+
+ # Do this over the rationals and convert back at the end.
+ J = MatrixEuclideanJordanAlgebra(QQ,
+ basis,
+ self.rank(),
+ normalize_basis=False)
+ (_,x,_,_) = J._charpoly_matrix_system()
+ p = J._charpoly_coeff(i)
+ # p might be missing some vars, have to substitute "optionally"
+ pairs = izip(x.base_ring().gens(), self._basis_normalizers)
+ substitutions = { v: v*c for (v,c) in pairs }
+ result = p.subs(substitutions)
+
+ # The result of "subs" can be either a coefficient-ring
+ # element or a polynomial. Gotta handle both cases.
+ if result in QQ:
+ return self.base_ring()(result)