def __init__(self,
field,
mult_table,
- rank,
prefix='e',
category=None,
natural_basis=None,
# a real embedding.
raise ValueError('field is not real')
- self._rank = rank
self._natural_basis = natural_basis
if category is None:
coords = W.coordinate_vector(_mat2vec(elt))
return self.from_vector(coords)
+ @staticmethod
+ def _max_test_case_size():
+ """
+ Return an integer "size" that is an upper bound on the size of
+ this algebra when it is used in a random test
+ case. Unfortunately, the term "size" is quite vague -- when
+ dealing with `R^n` under either the Hadamard or Jordan spin
+ product, the "size" refers to the dimension `n`. When dealing
+ with a matrix algebra (real symmetric or complex/quaternion
+ Hermitian), it refers to the size of the matrix, which is
+ far less than the dimension of the underlying vector space.
+
+ We default to five in this class, which is safe in `R^n`. The
+ matrix algebra subclasses (or any class where the "size" is
+ interpreted to be far less than the dimension) should override
+ with a smaller number.
+ """
+ return 5
def _repr_(self):
"""
"""
return tuple( self.random_element() for idx in range(count) )
+ @classmethod
+ def random_instance(cls, field=AA, **kwargs):
+ """
+ Return a random instance of this type of algebra.
+
+ Beware, this will crash for "most instances" because the
+ constructor below looks wrong.
+ """
+ if cls is TrivialEJA:
+ # The TrivialEJA class doesn't take an "n" argument because
+ # there's only one.
+ return cls(field)
+
+ n = ZZ.random_element(cls._max_test_case_size()) + 1
+ return cls(n, field, **kwargs)
+
@cached_method
def rank(self):
"""
SETUP::
- sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+ sage: from mjo.eja.eja_algebra import (HadamardEJA,
+ ....: JordanSpinEJA,
....: RealSymmetricEJA,
....: ComplexHermitianEJA,
....: QuaternionHermitianEJA,
Element = FiniteDimensionalEuclideanJordanAlgebraElement
-class KnownRankEJA(object):
- """
- A class for algebras that we actually know we can construct. The
- main issue is that, for most of our methods to make sense, we need
- to know the rank of our algebra. Thus we can't simply generate a
- "random" algebra, or even check that a given basis and product
- satisfy the axioms; because even if everything looks OK, we wouldn't
- know the rank we need to actuallty build the thing.
-
- Not really a subclass of FDEJA because doing that causes method
- resolution errors, e.g.
-
- TypeError: Error when calling the metaclass bases
- Cannot create a consistent method resolution
- order (MRO) for bases FiniteDimensionalEuclideanJordanAlgebra,
- KnownRankEJA
-
- """
- @staticmethod
- def _max_test_case_size():
- """
- Return an integer "size" that is an upper bound on the size of
- this algebra when it is used in a random test
- case. Unfortunately, the term "size" is quite vague -- when
- dealing with `R^n` under either the Hadamard or Jordan spin
- product, the "size" refers to the dimension `n`. When dealing
- with a matrix algebra (real symmetric or complex/quaternion
- Hermitian), it refers to the size of the matrix, which is
- far less than the dimension of the underlying vector space.
-
- We default to five in this class, which is safe in `R^n`. The
- matrix algebra subclasses (or any class where the "size" is
- interpreted to be far less than the dimension) should override
- with a smaller number.
- """
- return 5
-
- @classmethod
- def random_instance(cls, field=AA, **kwargs):
- """
- Return a random instance of this type of algebra.
-
- Beware, this will crash for "most instances" because the
- constructor below looks wrong.
- """
- if cls is TrivialEJA:
- # The TrivialEJA class doesn't take an "n" argument because
- # there's only one.
- return cls(field)
-
- n = ZZ.random_element(cls._max_test_case_size()) + 1
- return cls(n, field, **kwargs)
-
-
-class HadamardEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA):
+class HadamardEJA(FiniteDimensionalEuclideanJordanAlgebra):
"""
Return the Euclidean Jordan Algebra corresponding to the set
`R^n` under the Hadamard product.
for i in range(n) ]
fdeja = super(HadamardEJA, self)
- return fdeja.__init__(field, mult_table, rank=n, **kwargs)
+ fdeja.__init__(field, mult_table, **kwargs)
+ self.rank.set_cache(n)
def inner_product(self, x, y):
"""
Euclidean Jordan algebra of dimension...
"""
- eja_classes = KnownRankEJA.__subclasses__()
- if nontrivial:
- eja_classes.remove(TrivialEJA)
+ eja_classes = [HadamardEJA,
+ JordanSpinEJA,
+ RealSymmetricEJA,
+ ComplexHermitianEJA,
+ QuaternionHermitianEJA]
+ if not nontrivial:
+ eja_classes.append(TrivialEJA)
classname = choice(eja_classes)
return classname.random_instance(field=field)
# field can have dimension 4 (quaternions) too.
return 2
- def __init__(self, field, basis, rank, normalize_basis=True, **kwargs):
+ def __init__(self, field, basis, 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
# time to ensure that it isn't a generator expression.
basis = tuple(basis)
- if rank > 1 and normalize_basis:
+ if len(basis) > 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.
Qs = self.multiplication_table_from_matrix_basis(basis)
fdeja = super(MatrixEuclideanJordanAlgebra, self)
- return fdeja.__init__(field,
- Qs,
- rank=rank,
- natural_basis=basis,
- **kwargs)
+ fdeja.__init__(field, Qs, natural_basis=basis, **kwargs)
+ return
- def _rank_computation(self):
+ @cached_method
+ def rank(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()
+ return super(MatrixEuclideanJordanAlgebra, self).rank()
else:
basis = ( (b/n) for (b,n) in zip(self.natural_basis(),
self._basis_normalizers) )
# integers.
J = MatrixEuclideanJordanAlgebra(QQ,
basis,
- self.rank(),
normalize_basis=False)
- return J._rank_computation()
+ return J.rank()
@cached_method
def _charpoly_coeff(self, i):
# 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)
return M
-class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra, KnownRankEJA):
+class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra):
"""
The rank-n simple EJA consisting of real symmetric n-by-n
matrices, the usual symmetric Jordan product, and the trace inner
def __init__(self, n, field=AA, **kwargs):
basis = self._denormalized_basis(n, field)
- super(RealSymmetricEJA, self).__init__(field, basis, n, **kwargs)
+ super(RealSymmetricEJA, self).__init__(field, basis, **kwargs)
+ self.rank.set_cache(n)
class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
return RealMatrixEuclideanJordanAlgebra.natural_inner_product(X,Y)/2
-class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra, KnownRankEJA):
+class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra):
"""
The rank-n simple EJA consisting of complex Hermitian n-by-n
matrices over the real numbers, the usual symmetric Jordan product,
def __init__(self, n, field=AA, **kwargs):
basis = self._denormalized_basis(n,field)
- super(ComplexHermitianEJA,self).__init__(field, basis, n, **kwargs)
+ super(ComplexHermitianEJA,self).__init__(field, basis, **kwargs)
+ self.rank.set_cache(n)
class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
return RealMatrixEuclideanJordanAlgebra.natural_inner_product(X,Y)/4
-class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra,
- KnownRankEJA):
+class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra):
"""
The rank-n simple EJA consisting of self-adjoint n-by-n quaternion
matrices, the usual symmetric Jordan product, and the
def __init__(self, n, field=AA, **kwargs):
basis = self._denormalized_basis(n,field)
- super(QuaternionHermitianEJA,self).__init__(field, basis, n, **kwargs)
+ super(QuaternionHermitianEJA,self).__init__(field, basis, **kwargs)
+ self.rank.set_cache(n)
-class BilinearFormEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA):
+class BilinearFormEJA(FiniteDimensionalEuclideanJordanAlgebra):
r"""
The rank-2 simple EJA consisting of real vectors ``x=(x0, x_bar)``
with the half-trace inner product and jordan product ``x*y =
# one-dimensional ambient space (because the rank is bounded
# by the ambient dimension).
fdeja = super(BilinearFormEJA, self)
- return fdeja.__init__(field, mult_table, rank=min(n,2), **kwargs)
+ fdeja.__init__(field, mult_table, **kwargs)
+ self.rank.set_cache(min(n,2))
def inner_product(self, x, y):
r"""
return super(JordanSpinEJA, self).__init__(n, field, **kwargs)
-class TrivialEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA):
+class TrivialEJA(FiniteDimensionalEuclideanJordanAlgebra):
"""
The trivial Euclidean Jordan algebra consisting of only a zero element.
fdeja = super(TrivialEJA, self)
# The rank is zero using my definition, namely the dimension of the
# largest subalgebra generated by any element.
- return fdeja.__init__(field, mult_table, rank=0, **kwargs)
+ fdeja.__init__(field, mult_table, **kwargs)
+ self.rank.set_cache(0)