]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_subalgebra.py
eja: override _a_regular_element() in subalgebras, since we know one.
[sage.d.git] / mjo / eja / eja_subalgebra.py
1 from sage.matrix.constructor import matrix
2
3 from mjo.eja.eja_algebra import FiniteDimensionalEuclideanJordanAlgebra
4 from mjo.eja.eja_element import FiniteDimensionalEuclideanJordanAlgebraElement
5
6
7 class FiniteDimensionalEuclideanJordanElementSubalgebraElement(FiniteDimensionalEuclideanJordanAlgebraElement):
8 """
9 SETUP::
10
11 sage: from mjo.eja.eja_algebra import random_eja
12
13 TESTS::
14
15 The natural representation of an element in the subalgebra is
16 the same as its natural representation in the superalgebra::
17
18 sage: set_random_seed()
19 sage: A = random_eja().random_element().subalgebra_generated_by()
20 sage: y = A.random_element()
21 sage: actual = y.natural_representation()
22 sage: expected = y.superalgebra_element().natural_representation()
23 sage: actual == expected
24 True
25
26 """
27
28 def superalgebra_element(self):
29 """
30 Return the object in our algebra's superalgebra that corresponds
31 to myself.
32
33 SETUP::
34
35 sage: from mjo.eja.eja_algebra import (RealSymmetricEJA,
36 ....: random_eja)
37
38 EXAMPLES::
39
40 sage: J = RealSymmetricEJA(3)
41 sage: x = sum(J.gens())
42 sage: x
43 e0 + e1 + e2 + e3 + e4 + e5
44 sage: A = x.subalgebra_generated_by()
45 sage: A(x)
46 f1
47 sage: A(x).superalgebra_element()
48 e0 + e1 + e2 + e3 + e4 + e5
49
50 TESTS:
51
52 We can convert back and forth faithfully::
53
54 sage: set_random_seed()
55 sage: J = random_eja()
56 sage: x = J.random_element()
57 sage: A = x.subalgebra_generated_by()
58 sage: A(x).superalgebra_element() == x
59 True
60 sage: y = A.random_element()
61 sage: A(y.superalgebra_element()) == y
62 True
63
64 """
65 return self.parent().superalgebra().linear_combination(
66 zip(self.parent()._superalgebra_basis, self.to_vector()) )
67
68
69
70
71 class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclideanJordanAlgebra):
72 """
73 The subalgebra of an EJA generated by a single element.
74
75 SETUP::
76
77 sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
78 ....: JordanSpinEJA)
79
80 TESTS:
81
82 Ensure that our generator names don't conflict with the superalgebra::
83
84 sage: J = JordanSpinEJA(3)
85 sage: J.one().subalgebra_generated_by().gens()
86 (f0,)
87 sage: J = JordanSpinEJA(3, prefix='f')
88 sage: J.one().subalgebra_generated_by().gens()
89 (g0,)
90 sage: J = JordanSpinEJA(3, prefix='b')
91 sage: J.one().subalgebra_generated_by().gens()
92 (c0,)
93
94 Ensure that we can find subalgebras of subalgebras::
95
96 sage: A = ComplexHermitianEJA(3).one().subalgebra_generated_by()
97 sage: B = A.one().subalgebra_generated_by()
98 sage: B.dimension()
99 1
100
101 """
102 def __init__(self, elt):
103 self._superalgebra = elt.parent()
104 category = self._superalgebra.category().Associative()
105 V = self._superalgebra.vector_space()
106 field = self._superalgebra.base_ring()
107
108 # A half-assed attempt to ensure that we don't collide with
109 # the superalgebra's prefix (ignoring the fact that there
110 # could be super-superelgrbas in scope). If possible, we
111 # try to "increment" the parent algebra's prefix, although
112 # this idea goes out the window fast because some prefixen
113 # are off-limits.
114 prefixen = [ 'f', 'g', 'h', 'a', 'b', 'c', 'd' ]
115 try:
116 prefix = prefixen[prefixen.index(self._superalgebra.prefix()) + 1]
117 except ValueError:
118 prefix = prefixen[0]
119
120 if elt.is_zero():
121 # Short circuit because 0^0 == 1 is going to make us
122 # think we have a one-dimensional algebra otherwise.
123 natural_basis = tuple()
124 mult_table = tuple()
125 rank = 0
126 self._vector_space = V.zero_subspace()
127 self._superalgebra_basis = []
128 fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra,
129 self)
130 return fdeja.__init__(field,
131 mult_table,
132 rank,
133 prefix=prefix,
134 category=category,
135 natural_basis=natural_basis)
136
137
138 # First compute the vector subspace spanned by the powers of
139 # the given element.
140 superalgebra_basis = [self._superalgebra.one()]
141 # If our superalgebra is a subalgebra of something else, then
142 # superalgebra.one().to_vector() won't have the right
143 # coordinates unless we use V.from_vector() below.
144 basis_vectors = [V.from_vector(self._superalgebra.one().to_vector())]
145 W = V.span_of_basis(basis_vectors)
146 for exponent in range(1, V.dimension()):
147 new_power = elt**exponent
148 basis_vectors.append( V.from_vector(new_power.to_vector()) )
149 try:
150 W = V.span_of_basis(basis_vectors)
151 superalgebra_basis.append( new_power )
152 except ValueError:
153 # Vectors weren't independent; bail and keep the
154 # last subspace that worked.
155 break
156
157 # Make the basis hashable for UniqueRepresentation.
158 superalgebra_basis = tuple(superalgebra_basis)
159
160 # Now figure out the entries of the right-multiplication
161 # matrix for the successive basis elements b0, b1,... of
162 # that subspace.
163 n = len(superalgebra_basis)
164 mult_table = [[W.zero() for i in range(n)] for j in range(n)]
165 for i in range(n):
166 for j in range(n):
167 product = superalgebra_basis[i]*superalgebra_basis[j]
168 # product.to_vector() might live in a vector subspace
169 # if our parent algebra is already a subalgebra. We
170 # use V.from_vector() to make it "the right size" in
171 # that case.
172 product_vector = V.from_vector(product.to_vector())
173 mult_table[i][j] = W.coordinate_vector(product_vector)
174
175 # The rank is the highest possible degree of a minimal
176 # polynomial, and is bounded above by the dimension. We know
177 # in this case that there's an element whose minimal
178 # polynomial has the same degree as the space's dimension
179 # (remember how we constructed the space?), so that must be
180 # its rank too.
181 rank = W.dimension()
182
183 natural_basis = tuple( b.natural_representation()
184 for b in superalgebra_basis )
185
186
187 self._vector_space = W
188 self._superalgebra_basis = superalgebra_basis
189
190
191 fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, self)
192 return fdeja.__init__(field,
193 mult_table,
194 rank,
195 prefix=prefix,
196 category=category,
197 natural_basis=natural_basis)
198
199
200 def _a_regular_element(self):
201 """
202 Override the superalgebra method to return the one
203 regular element that is sure to exist in this
204 subalgebra, namely the element that generated it.
205
206 SETUP::
207
208 sage: from mjo.eja.eja_algebra import random_eja
209
210 TESTS::
211
212 sage: set_random_seed()
213 sage: J = random_eja().random_element().subalgebra_generated_by()
214 sage: J._a_regular_element().is_regular()
215 True
216
217 """
218 if self.dimension() == 0:
219 return self.zero()
220 else:
221 return self.monomial(1)
222
223
224 def _element_constructor_(self, elt):
225 """
226 Construct an element of this subalgebra from the given one.
227 The only valid arguments are elements of the parent algebra
228 that happen to live in this subalgebra.
229
230 SETUP::
231
232 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
233 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
234
235 EXAMPLES::
236
237 sage: J = RealSymmetricEJA(3)
238 sage: x = sum( i*J.gens()[i] for i in range(6) )
239 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
240 sage: [ K(x^k) for k in range(J.rank()) ]
241 [f0, f1, f2]
242
243 ::
244
245 """
246 if elt == 0:
247 # Just as in the superalgebra class, we need to hack
248 # this special case to ensure that random_element() can
249 # coerce a ring zero into the algebra.
250 return self.zero()
251
252 if elt in self.superalgebra():
253 coords = self.vector_space().coordinate_vector(elt.to_vector())
254 return self.from_vector(coords)
255
256
257 def one_basis(self):
258 """
259 Return the basis-element-index of this algebra's unit element.
260 """
261 return 0
262
263
264 def one(self):
265 """
266 Return the multiplicative identity element of this algebra.
267
268 The superclass method computes the identity element, which is
269 beyond overkill in this case: the algebra identity should be our
270 first basis element. We implement this via :meth:`one_basis`
271 because that method can optionally be used by other parts of the
272 category framework.
273
274 SETUP::
275
276 sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
277 ....: random_eja)
278
279 EXAMPLES::
280
281 sage: J = RealCartesianProductEJA(5)
282 sage: J.one()
283 e0 + e1 + e2 + e3 + e4
284 sage: x = sum(J.gens())
285 sage: A = x.subalgebra_generated_by()
286 sage: A.one()
287 f0
288 sage: A.one().superalgebra_element()
289 e0 + e1 + e2 + e3 + e4
290
291 TESTS:
292
293 The identity element acts like the identity::
294
295 sage: set_random_seed()
296 sage: J = random_eja().random_element().subalgebra_generated_by()
297 sage: x = J.random_element()
298 sage: J.one()*x == x and x*J.one() == x
299 True
300
301 The matrix of the unit element's operator is the identity::
302
303 sage: set_random_seed()
304 sage: J = random_eja().random_element().subalgebra_generated_by()
305 sage: actual = J.one().operator().matrix()
306 sage: expected = matrix.identity(J.base_ring(), J.dimension())
307 sage: actual == expected
308 True
309 """
310 if self.dimension() == 0:
311 return self.zero()
312 else:
313 return self.monomial(self.one_basis())
314
315
316 def superalgebra(self):
317 """
318 Return the superalgebra that this algebra was generated from.
319 """
320 return self._superalgebra
321
322
323 def vector_space(self):
324 """
325 SETUP::
326
327 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
328 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
329
330 EXAMPLES::
331
332 sage: J = RealSymmetricEJA(3)
333 sage: x = sum( i*J.gens()[i] for i in range(6) )
334 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
335 sage: K.vector_space()
336 Vector space of degree 6 and dimension 3 over Rational Field
337 User basis matrix:
338 [ 1 0 1 0 0 1]
339 [ 0 1 2 3 4 5]
340 [10 14 21 19 31 50]
341 sage: (x^0).to_vector()
342 (1, 0, 1, 0, 0, 1)
343 sage: (x^1).to_vector()
344 (0, 1, 2, 3, 4, 5)
345 sage: (x^2).to_vector()
346 (10, 14, 21, 19, 31, 50)
347
348 """
349 return self._vector_space
350
351
352 Element = FiniteDimensionalEuclideanJordanElementSubalgebraElement