check_field=False,
check_axioms=False)
+ def rational_algebra(self):
+ # Using None as a flag here (rather than just assigning "self"
+ # to self._rational_algebra by default) feels a little bit
+ # more sane to me in a garbage-collected environment.
+ if self._rational_algebra is None:
+ return self
+ else:
+ return self._rational_algebra
+
@cached_method
def _charpoly_coefficients(self):
r"""
Algebraic Real Field
"""
- if self._rational_algebra is None:
- # There's no need to construct *another* algebra over the
- # rationals if this one is already over the
- # rationals. Likewise, if we never orthonormalized our
- # basis, we might as well just use the given one.
+ if self.rational_algebra() is self:
+ # Bypass the hijinks if they won't benefit us.
return super()._charpoly_coefficients()
# Do the computation over the rationals. The answer will be
# the same, because all we've done is a change of basis.
# Then, change back from QQ to our real base ring
a = ( a_i.change_ring(self.base_ring())
- for a_i in self._rational_algebra._charpoly_coefficients() )
+ for a_i in self.rational_algebra()._charpoly_coefficients() )
# Otherwise, convert the coordinate variables back to the
# deorthonormalized ones.
from mjo.eja.eja_cache import real_symmetric_eja_coeffs
a = real_symmetric_eja_coeffs(self)
if a is not None:
- if self._rational_algebra is None:
- self._charpoly_coefficients.set_cache(a)
- else:
- self._rational_algebra._charpoly_coefficients.set_cache(a)
+ self.rational_algebra()._charpoly_coefficients.set_cache(a)
from mjo.eja.eja_cache import complex_hermitian_eja_coeffs
a = complex_hermitian_eja_coeffs(self)
if a is not None:
- if self._rational_algebra is None:
- self._charpoly_coefficients.set_cache(a)
- else:
- self._rational_algebra._charpoly_coefficients.set_cache(a)
+ self.rational_algebra()._charpoly_coefficients.set_cache(a)
@staticmethod
def _max_random_instance_size(max_dimension):
from mjo.eja.eja_cache import quaternion_hermitian_eja_coeffs
a = quaternion_hermitian_eja_coeffs(self)
if a is not None:
- if self._rational_algebra is None:
- self._charpoly_coefficients.set_cache(a)
- else:
- self._rational_algebra._charpoly_coefficients.set_cache(a)
+ self.rational_algebra()._charpoly_coefficients.set_cache(a)
from mjo.eja.eja_cache import octonion_hermitian_eja_coeffs
a = octonion_hermitian_eja_coeffs(self)
if a is not None:
- if self._rational_algebra is None:
- self._charpoly_coefficients.set_cache(a)
- else:
- self._rational_algebra._charpoly_coefficients.set_cache(a)
+ self.rational_algebra()._charpoly_coefficients.set_cache(a)
class AlbertEJA(OctonionHermitianEJA):
self._inner_product_matrix = matrix.block_diagonal(
[J._inner_product_matrix for J in factors]
)
+ self._inner_product_matrix._cache = {'hermitian': True}
+ self._inner_product_matrix.set_immutable()
# Building the multiplication table is a bit more tricky
# because we have to embed the entries of the factors'
SETUP::
- sage: from mjo.eja.eja_algebra import (HadamardEJA,
+ sage: from mjo.eja.eja_algebra import (FiniteDimensionalEJA,
+ ....: HadamardEJA,
....: JordanSpinEJA,
- ....: OctonionHermitianEJA,
....: RealSymmetricEJA)
EXAMPLES:
The ``cartesian_product()`` function only uses the first factor to
decide where the result will live; thus we have to be careful to
- check that all factors do indeed have a `_rational_algebra` member
- before we try to access it::
-
- sage: J1 = OctonionHermitianEJA(1) # no rational basis
- sage: J2 = HadamardEJA(2)
- sage: cartesian_product([J1,J2])
- Euclidean Jordan algebra of dimension 1 over Algebraic Real Field
- (+) Euclidean Jordan algebra of dimension 2 over Algebraic Real Field
- sage: cartesian_product([J2,J1])
- Euclidean Jordan algebra of dimension 2 over Algebraic Real Field
- (+) Euclidean Jordan algebra of dimension 1 over Algebraic Real Field
+ check that all factors do indeed have a ``rational_algebra()`` method
+ before we construct an algebra that claims to have a rational basis::
+
+ sage: J1 = HadamardEJA(2)
+ sage: jp = lambda X,Y: X*Y
+ sage: ip = lambda X,Y: X[0,0]*Y[0,0]
+ sage: b1 = matrix(QQ, [[1]])
+ sage: J2 = FiniteDimensionalEJA((b1,), jp, ip)
+ sage: cartesian_product([J2,J1]) # factor one not RationalBasisEJA
+ Euclidean Jordan algebra of dimension 1 over Algebraic Real
+ Field (+) Euclidean Jordan algebra of dimension 2 over Algebraic
+ Real Field
+ sage: cartesian_product([J1,J2]) # factor one is RationalBasisEJA
+ Traceback (most recent call last):
+ ...
+ ValueError: factor not a RationalBasisEJA
"""
def __init__(self, algebras, **kwargs):
+ if not all( hasattr(r, "rational_algebra") for r in algebras ):
+ raise ValueError("factor not a RationalBasisEJA")
+
CartesianProductEJA.__init__(self, algebras, **kwargs)
- self._rational_algebra = None
- if self.vector_space().base_field() is not QQ:
- if all( hasattr(r, "_rational_algebra") for r in algebras ):
- self._rational_algebra = cartesian_product([
- r._rational_algebra for r in algebras
- ])
+ @cached_method
+ def rational_algebra(self):
+ if self.base_ring() is QQ:
+ return self
+
+ return cartesian_product([
+ r.rational_algebra() for r in self.cartesian_factors()
+ ])
RationalBasisEJA.CartesianProduct = RationalBasisCartesianProductEJA