]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_subalgebra.py
eja: fix the subalgebra generated by zero.
[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 _element_constructor_(self, elt):
201 """
202 Construct an element of this subalgebra from the given one.
203 The only valid arguments are elements of the parent algebra
204 that happen to live in this subalgebra.
205
206 SETUP::
207
208 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
209 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
210
211 EXAMPLES::
212
213 sage: J = RealSymmetricEJA(3)
214 sage: x = sum( i*J.gens()[i] for i in range(6) )
215 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
216 sage: [ K(x^k) for k in range(J.rank()) ]
217 [f0, f1, f2]
218
219 ::
220
221 """
222 if elt == 0:
223 # Just as in the superalgebra class, we need to hack
224 # this special case to ensure that random_element() can
225 # coerce a ring zero into the algebra.
226 return self.zero()
227
228 if elt in self.superalgebra():
229 coords = self.vector_space().coordinate_vector(elt.to_vector())
230 return self.from_vector(coords)
231
232
233 def one_basis(self):
234 """
235 Return the basis-element-index of this algebra's unit element.
236 """
237 return 0
238
239
240 def one(self):
241 """
242 Return the multiplicative identity element of this algebra.
243
244 The superclass method computes the identity element, which is
245 beyond overkill in this case: the algebra identity should be our
246 first basis element. We implement this via :meth:`one_basis`
247 because that method can optionally be used by other parts of the
248 category framework.
249
250 SETUP::
251
252 sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
253 ....: random_eja)
254
255 EXAMPLES::
256
257 sage: J = RealCartesianProductEJA(5)
258 sage: J.one()
259 e0 + e1 + e2 + e3 + e4
260 sage: x = sum(J.gens())
261 sage: A = x.subalgebra_generated_by()
262 sage: A.one()
263 f0
264 sage: A.one().superalgebra_element()
265 e0 + e1 + e2 + e3 + e4
266
267 TESTS:
268
269 The identity element acts like the identity::
270
271 sage: set_random_seed()
272 sage: J = random_eja().random_element().subalgebra_generated_by()
273 sage: x = J.random_element()
274 sage: J.one()*x == x and x*J.one() == x
275 True
276
277 The matrix of the unit element's operator is the identity::
278
279 sage: set_random_seed()
280 sage: J = random_eja().random_element().subalgebra_generated_by()
281 sage: actual = J.one().operator().matrix()
282 sage: expected = matrix.identity(J.base_ring(), J.dimension())
283 sage: actual == expected
284 True
285 """
286 if self.dimension() == 0:
287 return self.zero()
288 else:
289 return self.monomial(self.one_basis())
290
291
292 def superalgebra(self):
293 """
294 Return the superalgebra that this algebra was generated from.
295 """
296 return self._superalgebra
297
298
299 def vector_space(self):
300 """
301 SETUP::
302
303 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
304 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
305
306 EXAMPLES::
307
308 sage: J = RealSymmetricEJA(3)
309 sage: x = sum( i*J.gens()[i] for i in range(6) )
310 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
311 sage: K.vector_space()
312 Vector space of degree 6 and dimension 3 over Rational Field
313 User basis matrix:
314 [ 1 0 1 0 0 1]
315 [ 0 1 2 3 4 5]
316 [10 14 21 19 31 50]
317 sage: (x^0).to_vector()
318 (1, 0, 1, 0, 0, 1)
319 sage: (x^1).to_vector()
320 (0, 1, 2, 3, 4, 5)
321 sage: (x^2).to_vector()
322 (10, 14, 21, 19, 31, 50)
323
324 """
325 return self._vector_space
326
327
328 Element = FiniteDimensionalEuclideanJordanElementSubalgebraElement