return tuple( self.random_element() for idx in range(count) )
- def _rank_computation1(self):
+ def _rank_computation(self):
r"""
- Compute the rank of this algebra using highly suspicious voodoo.
-
- ALGORITHM:
-
- We first compute the basis representation of the operator L_x
- using polynomial indeterminates are placeholders for the
- coordinates of "x", which is arbitrary. We then use that
- matrix to compute the (polynomial) entries of x^0, x^1, ...,
- x^d,... for increasing values of "d", starting at zero. The
- idea is that. If we also add "coefficient variables" a_0,
- a_1,... to the ring, we can form the linear combination
- a_0*x^0 + ... + a_d*x^d = 0, and ask what dimension the
- solution space has as an affine variety. When "d" is smaller
- than the rank, we expect that dimension to be the number of
- coordinates of "x", since we can set *those* to whatever we
- want, but linear independence forces the coefficients a_i to
- be zero. Eventually, when "d" passes the rank, the dimension
- of the solution space begins to grow, because we can *still*
- set the coordinates of "x" arbitrarily, but now there are some
- coefficients that make the sum zero as well. So, when the
- dimension of the variety jumps, we return the corresponding
- "d" as the rank of the algebra. This appears to work.
+ Compute the rank of this algebra.
SETUP::
EXAMPLES::
- sage: J = HadamardEJA(5)
+ sage: J = HadamardEJA(4)
sage: J._rank_computation() == J.rank()
True
- sage: J = JordanSpinEJA(5)
+ sage: J = JordanSpinEJA(4)
sage: J._rank_computation() == J.rank()
True
- sage: J = RealSymmetricEJA(4)
+ sage: J = RealSymmetricEJA(3)
sage: J._rank_computation() == J.rank()
True
- sage: J = ComplexHermitianEJA(3)
+ sage: J = ComplexHermitianEJA(2)
sage: J._rank_computation() == J.rank()
True
sage: J = QuaternionHermitianEJA(2)
sage: J._rank_computation() == J.rank()
True
- """
- n = self.dimension()
- var_names = [ "X" + str(z) for z in range(1,n+1) ]
- d = 0
- ideal_dim = len(var_names)
- def L_x_i_j(i,j):
- # From a result in my book, these are the entries of the
- # basis representation of L_x.
- return sum( vars[d+k]*self.monomial(k).operator().matrix()[i,j]
- for k in range(n) )
-
- while ideal_dim == len(var_names):
- coeff_names = [ "a" + str(z) for z in range(d) ]
- R = PolynomialRing(self.base_ring(), coeff_names + var_names)
- vars = R.gens()
- L_x = matrix(R, n, n, L_x_i_j)
- x_powers = [ vars[k]*(L_x**k)*self.one().to_vector()
- for k in range(d) ]
- eqs = [ sum(x_powers[k][j] for k in range(d)) for j in range(n) ]
- ideal_dim = R.ideal(eqs).dimension()
- d += 1
-
- # Subtract one because we increment one too many times, and
- # subtract another one because "d" is one greater than the
- # answer anyway; when d=3, we go up to x^2.
- return d-2
-
- def _rank_computation2(self):
- r"""
- Instead of using the dimension of an ideal, find the rank of a
- matrix containing polynomials.
- """
- n = self.dimension()
- var_names = [ "X" + str(z) for z in range(1,n+1) ]
- R = PolynomialRing(self.base_ring(), var_names)
- vars = R.gens()
-
- def L_x_i_j(i,j):
- # From a result in my book, these are the entries of the
- # basis representation of L_x.
- return sum( vars[k]*self.monomial(k).operator().matrix()[i,j]
- for k in range(n) )
-
- L_x = matrix(R, n, n, L_x_i_j)
- x_powers = [ (vars[k]*(L_x**k)*self.one().to_vector()).row()
- for k in range(n) ]
-
- from sage.matrix.constructor import block_matrix
- M = block_matrix(n,1,x_powers)
- return M.rank()
-
- def _rank_computation3(self):
- r"""
- Similar to :meth:`_rank_computation2`, but it stops echelonizing
- as soon as it hits the first zero row.
"""
n = self.dimension()
if n == 0:
for k in range(n) ]
# Can assume n >= 2
- rows = [x_powers[0]]
- M = matrix(rows)
+ M = matrix([x_powers[0]])
old_rank = 1
for d in range(1,n):
- rows = M.rows() + [x_powers[d]]
- M = matrix(rows)
+ M = matrix(M.rows() + [x_powers[d]])
M.echelonize()
new_rank = M.rank()
if new_rank == old_rank:
else:
old_rank = new_rank
+ return n
+
def rank(self):
"""
Return the rank of this EJA.
**kwargs)
+ def _rank_computation(self):
+ r"""
+ 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)._rank_computation()
+ else:
+ basis = ( (b/n) for (b,n) in zip(self.natural_basis(),
+ self._basis_normalizers) )
+
+ # Do this over the rationals and convert back at the end.
+ # Only works because we know the entries of the basis are
+ # integers.
+ J = MatrixEuclideanJordanAlgebra(QQ,
+ basis,
+ self.rank(),
+ normalize_basis=False)
+ return J._rank_computation()
+
@cached_method
def _charpoly_coeff(self, i):
"""