"""
Return the matrix space in which this algebra's natural basis
elements live.
+
+ Generally this will be an `n`-by-`1` column-vector space,
+ except when the algebra is trivial. There it's `n`-by-`n`
+ (where `n` is zero), to ensure that two elements of the
+ natural basis space (empty matrices) can be multiplied.
"""
- if self._natural_basis is None or len(self._natural_basis) == 0:
+ if self.is_trivial():
+ return MatrixSpace(self.base_ring(), 0)
+ elif self._natural_basis is None or len(self._natural_basis) == 0:
return MatrixSpace(self.base_ring(), self.dimension(), 1)
else:
return self._natural_basis[0].matrix_space()
# there's only one.
return cls(field)
- n = ZZ.random_element(cls._max_test_case_size()) + 1
+ n = ZZ.random_element(cls._max_test_case_size() + 1)
return cls(n, field, **kwargs)
@cached_method
return x.to_vector().inner_product(y.to_vector())
-def random_eja(field=AA, nontrivial=False):
+def random_eja(field=AA):
"""
Return a "random" finite-dimensional Euclidean Jordan Algebra.
Euclidean Jordan algebra of dimension...
"""
- eja_classes = [HadamardEJA,
- JordanSpinEJA,
- RealSymmetricEJA,
- ComplexHermitianEJA,
- QuaternionHermitianEJA]
- if not nontrivial:
- eja_classes.append(TrivialEJA)
- classname = choice(eja_classes)
+ classname = choice([TrivialEJA,
+ HadamardEJA,
+ JordanSpinEJA,
+ RealSymmetricEJA,
+ ComplexHermitianEJA,
+ QuaternionHermitianEJA])
return classname.random_instance(field=field)
-
-
class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
@staticmethod
def _max_test_case_size():
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.
+ #
+ # The a[0] access here is safe because trivial algebras
+ # won't have any basis normalizers and therefore won't
+ # make it to this "else" branch.
+ XS = a[0].parent().gens()
+ 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
# is supposed to hold the entire long vector, and the subspace W
# of V will be spanned by the vectors that arise from symmetric
# matrices. Thus for S^2, dim(V) == 4 and dim(W) == 3.
+ if len(basis) == 0:
+ return []
+
field = basis[0].base_ring()
dimension = basis[0].nrows()
sage: x.operator().matrix().is_symmetric()
True
+ We can construct the (trivial) algebra of rank zero::
+
+ sage: RealSymmetricEJA(0)
+ Euclidean Jordan algebra of dimension 0 over Algebraic Real Field
+
"""
@classmethod
def _denormalized_basis(cls, n, field):
sage: x.operator().matrix().is_symmetric()
True
+ We can construct the (trivial) algebra of rank zero::
+
+ sage: ComplexHermitianEJA(0)
+ Euclidean Jordan algebra of dimension 0 over Algebraic Real Field
+
"""
@classmethod
sage: x.operator().matrix().is_symmetric()
True
+ We can construct the (trivial) algebra of rank zero::
+
+ sage: QuaternionHermitianEJA(0)
+ Euclidean Jordan algebra of dimension 0 over Algebraic Real Field
+
"""
@classmethod
def _denormalized_basis(cls, n, field):