1 from sage
.matrix
.constructor
import matrix
3 from mjo
.eja
.eja_subalgebra
import FiniteDimensionalEuclideanJordanSubalgebra
6 class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclideanJordanSubalgebra
):
7 def __init__(self
, elt
, orthonormalize_basis
):
8 self
._superalgebra
= elt
.parent()
9 category
= self
._superalgebra
.category().Associative()
10 V
= self
._superalgebra
.vector_space()
11 field
= self
._superalgebra
.base_ring()
13 # This list is guaranteed to contain all independent powers,
14 # because it's the maximal set of powers that could possibly
15 # be independent (by a dimension argument).
16 powers
= [ elt
**k
for k
in range(V
.dimension()) ]
17 power_vectors
= [ p
.to_vector() for p
in powers
]
18 P
= matrix(field
, power_vectors
)
20 if orthonormalize_basis
== False:
21 # In this case, we just need to figure out which elements
22 # of the "powers" list are redundant... First compute the
23 # vector subspace spanned by the powers of the given
26 # Figure out which powers form a linearly-independent set.
27 ind_rows
= P
.pivot_rows()
29 # Pick those out of the list of all powers.
30 superalgebra_basis
= tuple(map(powers
.__getitem
__, ind_rows
))
32 # If our superalgebra is a subalgebra of something else, then
33 # these vectors won't have the right coordinates for
34 # V.span_of_basis() unless we use V.from_vector() on them.
35 basis_vectors
= map(power_vectors
.__getitem
__, ind_rows
)
37 # If we're going to orthonormalize the basis anyway, we
38 # might as well just do Gram-Schmidt on the whole list of
39 # powers. The redundant ones will get zero'd out. If this
40 # looks like a roundabout way to orthonormalize, it is.
41 # But converting everything from algebra elements to vectors
42 # to matrices and then back again turns out to be about
43 # as fast as reimplementing our own Gram-Schmidt that
45 G
,_
= P
.gram_schmidt(orthonormal
=True)
46 basis_vectors
= [ g
for g
in G
.rows() if not g
.is_zero() ]
47 superalgebra_basis
= [ self
._superalgebra
.from_vector(b
)
48 for b
in basis_vectors
]
50 W
= V
.span_of_basis( V
.from_vector(v
) for v
in basis_vectors
)
52 # The rank is the highest possible degree of a minimal
53 # polynomial, and is bounded above by the dimension. We know
54 # in this case that there's an element whose minimal
55 # polynomial has the same degree as the space's dimension
56 # (remember how we constructed the space?), so that must be
60 fdeja
= super(FiniteDimensionalEuclideanJordanElementSubalgebra
, self
)
61 return fdeja
.__init
__(self
._superalgebra
,
67 def _a_regular_element(self
):
69 Override the superalgebra method to return the one
70 regular element that is sure to exist in this
71 subalgebra, namely the element that generated it.
75 sage: from mjo.eja.eja_algebra import random_eja
79 sage: set_random_seed()
80 sage: J = random_eja().random_element().subalgebra_generated_by()
81 sage: J._a_regular_element().is_regular()
85 if self
.dimension() == 0:
88 return self
.monomial(1)
91 def _element_constructor_(self
, elt
):
93 Construct an element of this subalgebra from the given one.
94 The only valid arguments are elements of the parent algebra
95 that happen to live in this subalgebra.
99 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
100 sage: from mjo.eja.eja_element_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
104 sage: J = RealSymmetricEJA(3)
105 sage: x = sum( i*J.gens()[i] for i in range(6) )
106 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x,False)
107 sage: [ K(x^k) for k in range(J.rank()) ]
114 # Just as in the superalgebra class, we need to hack
115 # this special case to ensure that random_element() can
116 # coerce a ring zero into the algebra.
119 if elt
in self
.superalgebra():
120 coords
= self
.vector_space().coordinate_vector(elt
.to_vector())
121 return self
.from_vector(coords
)
127 Return the multiplicative identity element of this algebra.
129 The superclass method computes the identity element, which is
130 beyond overkill in this case: the superalgebra identity
131 restricted to this algebra is its identity. Note that we can't
132 count on the first basis element being the identity -- it migth
133 have been scaled if we orthonormalized the basis.
137 sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
142 sage: J = RealCartesianProductEJA(5)
144 e0 + e1 + e2 + e3 + e4
145 sage: x = sum(J.gens())
146 sage: A = x.subalgebra_generated_by()
149 sage: A.one().superalgebra_element()
150 e0 + e1 + e2 + e3 + e4
154 The identity element acts like the identity over the rationals::
156 sage: set_random_seed()
157 sage: x = random_eja().random_element()
158 sage: A = x.subalgebra_generated_by()
159 sage: x = A.random_element()
160 sage: A.one()*x == x and x*A.one() == x
163 The identity element acts like the identity over the algebraic
164 reals with an orthonormal basis::
166 sage: set_random_seed()
167 sage: x = random_eja(AA).random_element()
168 sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
169 sage: x = A.random_element()
170 sage: A.one()*x == x and x*A.one() == x
173 The matrix of the unit element's operator is the identity over
176 sage: set_random_seed()
177 sage: x = random_eja().random_element()
178 sage: A = x.subalgebra_generated_by()
179 sage: actual = A.one().operator().matrix()
180 sage: expected = matrix.identity(A.base_ring(), A.dimension())
181 sage: actual == expected
184 The matrix of the unit element's operator is the identity over
185 the algebraic reals with an orthonormal basis::
187 sage: set_random_seed()
188 sage: x = random_eja(AA).random_element()
189 sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
190 sage: actual = A.one().operator().matrix()
191 sage: expected = matrix.identity(A.base_ring(), A.dimension())
192 sage: actual == expected
196 if self
.dimension() == 0:
199 sa_one
= self
.superalgebra().one().to_vector()
200 sa_coords
= self
.vector_space().coordinate_vector(sa_one
)
201 return self
.from_vector(sa_coords
)
204 def natural_basis_space(self
):
206 Return the natural basis space of this algebra, which is identical
207 to that of its superalgebra.
209 This is correct "by definition," and avoids a mismatch when the
210 subalgebra is trivial (with no natural basis to infer anything
211 from) and the parent is not.
213 return self
.superalgebra().natural_basis_space()
216 def superalgebra(self
):
218 Return the superalgebra that this algebra was generated from.
220 return self
._superalgebra
223 def vector_space(self
):
227 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
228 sage: from mjo.eja.eja_element_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
232 sage: J = RealSymmetricEJA(3)
233 sage: x = J.monomial(0) + 2*J.monomial(2) + 5*J.monomial(5)
234 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x,False)
235 sage: K.vector_space()
236 Vector space of degree 6 and dimension 3 over...
241 sage: (x^0).to_vector()
243 sage: (x^1).to_vector()
245 sage: (x^2).to_vector()
249 return self
._vector
_space