from sage.matrix.constructor import matrix
+from sage.misc.cachefunc import cached_method
+from sage.rings.all import QQ
-from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
-
-
-class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclideanJordanSubalgebra):
- def __init__(self, elt, orthonormalize_basis):
- self._superalgebra = elt.parent()
- category = self._superalgebra.category().Associative()
- V = self._superalgebra.vector_space()
- field = self._superalgebra.base_ring()
-
- # This list is guaranteed to contain all independent powers,
- # because it's the maximal set of powers that could possibly
- # be independent (by a dimension argument).
- powers = [ elt**k for k in range(V.dimension()) ]
- power_vectors = [ p.to_vector() for p in powers ]
- P = matrix(field, power_vectors)
-
- if orthonormalize_basis == False:
- # In this case, we just need to figure out which elements
- # of the "powers" list are redundant... First compute the
- # vector subspace spanned by the powers of the given
- # element.
-
- # Figure out which powers form a linearly-independent set.
- ind_rows = P.pivot_rows()
-
- # Pick those out of the list of all powers.
- superalgebra_basis = tuple(map(powers.__getitem__, ind_rows))
-
- # If our superalgebra is a subalgebra of something else, then
- # these vectors won't have the right coordinates for
- # V.span_of_basis() unless we use V.from_vector() on them.
- basis_vectors = map(power_vectors.__getitem__, ind_rows)
- else:
- # If we're going to orthonormalize the basis anyway, we
- # might as well just do Gram-Schmidt on the whole list of
- # powers. The redundant ones will get zero'd out. If this
- # looks like a roundabout way to orthonormalize, it is.
- # But converting everything from algebra elements to vectors
- # to matrices and then back again turns out to be about
- # as fast as reimplementing our own Gram-Schmidt that
- # works in an EJA.
- G,_ = P.gram_schmidt(orthonormal=True)
- basis_vectors = [ g for g in G.rows() if not g.is_zero() ]
- superalgebra_basis = [ self._superalgebra.from_vector(b)
- for b in basis_vectors ]
-
- W = V.span_of_basis( V.from_vector(v) for v in basis_vectors )
+from mjo.eja.eja_subalgebra import FiniteDimensionalEJASubalgebra
+
+
+class FiniteDimensionalEJAElementSubalgebra(FiniteDimensionalEJASubalgebra):
+ def __init__(self, elt, **kwargs):
+ superalgebra = elt.parent()
+
+ # TODO: going up to the superalgebra dimension here is
+ # overkill. We should append p vectors as rows to a matrix
+ # and continually rref() it until the rank stops going
+ # up. When n=10 but the dimension of the algebra is 1, that
+ # can save a shitload of time (especially over AA).
+ powers = tuple( elt**k for k in range(elt.degree()) )
+
+ super().__init__(superalgebra,
+ powers,
+ associative=True,
+ **kwargs)
# The rank is the highest possible degree of a minimal
# polynomial, and is bounded above by the dimension. We know
# polynomial has the same degree as the space's dimension
# (remember how we constructed the space?), so that must be
# its rank too.
- rank = W.dimension()
-
- fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, self)
- return fdeja.__init__(self._superalgebra,
- superalgebra_basis,
- rank=rank,
- category=category)
-
-
- def _a_regular_element(self):
- """
- Override the superalgebra method to return the one
- regular element that is sure to exist in this
- subalgebra, namely the element that generated it.
-
- SETUP::
-
- sage: from mjo.eja.eja_algebra import random_eja
-
- TESTS::
-
- sage: set_random_seed()
- sage: J = random_eja().random_element().subalgebra_generated_by()
- sage: J._a_regular_element().is_regular()
- True
-
- """
- if self.dimension() == 0:
- return self.zero()
- else:
- return self.monomial(1)
-
-
- def _element_constructor_(self, elt):
- """
- Construct an element of this subalgebra from the given one.
- The only valid arguments are elements of the parent algebra
- that happen to live in this subalgebra.
-
- SETUP::
-
- sage: from mjo.eja.eja_algebra import RealSymmetricEJA
- sage: from mjo.eja.eja_element_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
-
- EXAMPLES::
-
- sage: J = RealSymmetricEJA(3)
- sage: x = sum( i*J.gens()[i] for i in range(6) )
- sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x,False)
- sage: [ K(x^k) for k in range(J.rank()) ]
- [f0, f1, f2]
-
- ::
-
- """
- if elt == 0:
- # Just as in the superalgebra class, we need to hack
- # this special case to ensure that random_element() can
- # coerce a ring zero into the algebra.
- return self.zero()
-
- if elt in self.superalgebra():
- coords = self.vector_space().coordinate_vector(elt.to_vector())
- return self.from_vector(coords)
-
+ self.rank.set_cache(self.dimension())
+ @cached_method
def one(self):
"""
Return the multiplicative identity element of this algebra.
The superclass method computes the identity element, which is
beyond overkill in this case: the superalgebra identity
restricted to this algebra is its identity. Note that we can't
- count on the first basis element being the identity -- it migth
+ count on the first basis element being the identity -- it might
have been scaled if we orthonormalized the basis.
SETUP::
- sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
+ sage: from mjo.eja.eja_algebra import (HadamardEJA,
....: random_eja)
EXAMPLES::
- sage: J = RealCartesianProductEJA(5)
+ sage: J = HadamardEJA(5)
sage: J.one()
e0 + e1 + e2 + e3 + e4
sage: x = sum(J.gens())
- sage: A = x.subalgebra_generated_by()
+ sage: A = x.subalgebra_generated_by(orthonormalize=False)
sage: A.one()
f0
sage: A.one().superalgebra_element()
The identity element acts like the identity over the rationals::
sage: set_random_seed()
- sage: x = random_eja().random_element()
+ sage: x = random_eja(field=QQ,orthonormalize=False).random_element()
sage: A = x.subalgebra_generated_by()
sage: x = A.random_element()
sage: A.one()*x == x and x*A.one() == x
reals with an orthonormal basis::
sage: set_random_seed()
- sage: x = random_eja(AA).random_element()
- sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
+ sage: x = random_eja().random_element()
+ sage: A = x.subalgebra_generated_by()
sage: x = A.random_element()
sage: A.one()*x == x and x*A.one() == x
True
the rationals::
sage: set_random_seed()
- sage: x = random_eja().random_element()
- sage: A = x.subalgebra_generated_by()
+ sage: x = random_eja(field=QQ,orthonormalize=False).random_element()
+ sage: A = x.subalgebra_generated_by(orthonormalize=False)
sage: actual = A.one().operator().matrix()
sage: expected = matrix.identity(A.base_ring(), A.dimension())
sage: actual == expected
the algebraic reals with an orthonormal basis::
sage: set_random_seed()
- sage: x = random_eja(AA).random_element()
- sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
+ sage: x = random_eja().random_element()
+ sage: A = x.subalgebra_generated_by()
sage: actual = A.one().operator().matrix()
sage: expected = matrix.identity(A.base_ring(), A.dimension())
sage: actual == expected
"""
if self.dimension() == 0:
return self.zero()
- else:
- sa_one = self.superalgebra().one().to_vector()
- sa_coords = self.vector_space().coordinate_vector(sa_one)
- return self.from_vector(sa_coords)
-
-
- def natural_basis_space(self):
- """
- Return the natural basis space of this algebra, which is identical
- to that of its superalgebra.
- This is correct "by definition," and avoids a mismatch when the
- subalgebra is trivial (with no natural basis to infer anything
- from) and the parent is not.
- """
- return self.superalgebra().natural_basis_space()
-
-
- def superalgebra(self):
- """
- Return the superalgebra that this algebra was generated from.
- """
- return self._superalgebra
-
-
- def vector_space(self):
- """
- SETUP::
-
- sage: from mjo.eja.eja_algebra import RealSymmetricEJA
- sage: from mjo.eja.eja_element_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
-
- EXAMPLES::
-
- sage: J = RealSymmetricEJA(3)
- sage: x = J.monomial(0) + 2*J.monomial(2) + 5*J.monomial(5)
- sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x,False)
- sage: K.vector_space()
- Vector space of degree 6 and dimension 3 over...
- User basis matrix:
- [ 1 0 1 0 0 1]
- [ 1 0 2 0 0 5]
- [ 1 0 4 0 0 25]
- sage: (x^0).to_vector()
- (1, 0, 1, 0, 0, 1)
- sage: (x^1).to_vector()
- (1, 0, 2, 0, 0, 5)
- sage: (x^2).to_vector()
- (1, 0, 4, 0, 0, 25)
-
- """
- return self._vector_space
+ return self(self.superalgebra().one())