]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_element_subalgebra.py
eja: refactor the element subalgebra stuff into generic subalgebra.
[sage.d.git] / mjo / eja / eja_element_subalgebra.py
1 from sage.matrix.constructor import matrix
2
3 from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
4
5
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()
12
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)
19
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
24 # element.
25
26 # Figure out which powers form a linearly-independent set.
27 ind_rows = P.pivot_rows()
28
29 # Pick those out of the list of all powers.
30 superalgebra_basis = tuple(map(powers.__getitem__, ind_rows))
31
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)
36 else:
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
44 # works in an EJA.
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 ]
49
50 W = V.span_of_basis( V.from_vector(v) for v in basis_vectors )
51
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
57 # its rank too.
58 rank = W.dimension()
59
60 fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, self)
61 return fdeja.__init__(self._superalgebra,
62 superalgebra_basis,
63 rank=rank,
64 category=category)
65
66
67 def _a_regular_element(self):
68 """
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.
72
73 SETUP::
74
75 sage: from mjo.eja.eja_algebra import random_eja
76
77 TESTS::
78
79 sage: set_random_seed()
80 sage: J = random_eja().random_element().subalgebra_generated_by()
81 sage: J._a_regular_element().is_regular()
82 True
83
84 """
85 if self.dimension() == 0:
86 return self.zero()
87 else:
88 return self.monomial(1)
89
90
91 def _element_constructor_(self, elt):
92 """
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.
96
97 SETUP::
98
99 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
100 sage: from mjo.eja.eja_element_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
101
102 EXAMPLES::
103
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()) ]
108 [f0, f1, f2]
109
110 ::
111
112 """
113 if elt == 0:
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.
117 return self.zero()
118
119 if elt in self.superalgebra():
120 coords = self.vector_space().coordinate_vector(elt.to_vector())
121 return self.from_vector(coords)
122
123
124
125 def one(self):
126 """
127 Return the multiplicative identity element of this algebra.
128
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.
134
135 SETUP::
136
137 sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
138 ....: random_eja)
139
140 EXAMPLES::
141
142 sage: J = RealCartesianProductEJA(5)
143 sage: J.one()
144 e0 + e1 + e2 + e3 + e4
145 sage: x = sum(J.gens())
146 sage: A = x.subalgebra_generated_by()
147 sage: A.one()
148 f0
149 sage: A.one().superalgebra_element()
150 e0 + e1 + e2 + e3 + e4
151
152 TESTS:
153
154 The identity element acts like the identity over the rationals::
155
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
161 True
162
163 The identity element acts like the identity over the algebraic
164 reals with an orthonormal basis::
165
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
171 True
172
173 The matrix of the unit element's operator is the identity over
174 the rationals::
175
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
182 True
183
184 The matrix of the unit element's operator is the identity over
185 the algebraic reals with an orthonormal basis::
186
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
193 True
194
195 """
196 if self.dimension() == 0:
197 return self.zero()
198 else:
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)
202
203
204 def natural_basis_space(self):
205 """
206 Return the natural basis space of this algebra, which is identical
207 to that of its superalgebra.
208
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.
212 """
213 return self.superalgebra().natural_basis_space()
214
215
216 def superalgebra(self):
217 """
218 Return the superalgebra that this algebra was generated from.
219 """
220 return self._superalgebra
221
222
223 def vector_space(self):
224 """
225 SETUP::
226
227 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
228 sage: from mjo.eja.eja_element_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
229
230 EXAMPLES::
231
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...
237 User basis matrix:
238 [ 1 0 1 0 0 1]
239 [ 1 0 2 0 0 5]
240 [ 1 0 4 0 0 25]
241 sage: (x^0).to_vector()
242 (1, 0, 1, 0, 0, 1)
243 sage: (x^1).to_vector()
244 (1, 0, 2, 0, 0, 5)
245 sage: (x^2).to_vector()
246 (1, 0, 4, 0, 0, 25)
247
248 """
249 return self._vector_space
250