]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_subalgebra.py
eja: refactor the element subalgebra stuff into generic subalgebra.
[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 class FiniteDimensionalEuclideanJordanSubalgebraElement(FiniteDimensionalEuclideanJordanAlgebraElement):
7 """
8 SETUP::
9
10 sage: from mjo.eja.eja_algebra import random_eja
11
12 TESTS::
13
14 The natural representation of an element in the subalgebra is
15 the same as its natural representation in the superalgebra::
16
17 sage: set_random_seed()
18 sage: A = random_eja().random_element().subalgebra_generated_by()
19 sage: y = A.random_element()
20 sage: actual = y.natural_representation()
21 sage: expected = y.superalgebra_element().natural_representation()
22 sage: actual == expected
23 True
24
25 The left-multiplication-by operator for elements in the subalgebra
26 works like it does in the superalgebra, even if we orthonormalize
27 our basis::
28
29 sage: set_random_seed()
30 sage: x = random_eja(AA).random_element()
31 sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
32 sage: y = A.random_element()
33 sage: y.operator()(A.one()) == y
34 True
35
36 """
37
38 def superalgebra_element(self):
39 """
40 Return the object in our algebra's superalgebra that corresponds
41 to myself.
42
43 SETUP::
44
45 sage: from mjo.eja.eja_algebra import (RealSymmetricEJA,
46 ....: random_eja)
47
48 EXAMPLES::
49
50 sage: J = RealSymmetricEJA(3)
51 sage: x = sum(J.gens())
52 sage: x
53 e0 + e1 + e2 + e3 + e4 + e5
54 sage: A = x.subalgebra_generated_by()
55 sage: A(x)
56 f1
57 sage: A(x).superalgebra_element()
58 e0 + e1 + e2 + e3 + e4 + e5
59
60 TESTS:
61
62 We can convert back and forth faithfully::
63
64 sage: set_random_seed()
65 sage: J = random_eja()
66 sage: x = J.random_element()
67 sage: A = x.subalgebra_generated_by()
68 sage: A(x).superalgebra_element() == x
69 True
70 sage: y = A.random_element()
71 sage: A(y.superalgebra_element()) == y
72 True
73
74 """
75 return self.parent().superalgebra().linear_combination(
76 zip(self.parent()._superalgebra_basis, self.to_vector()) )
77
78
79
80
81 class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJordanAlgebra):
82 """
83 A subalgebra of an EJA with a given basis.
84
85 SETUP::
86
87 sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
88 ....: JordanSpinEJA)
89
90 TESTS:
91
92 Ensure that our generator names don't conflict with the superalgebra::
93
94 sage: J = JordanSpinEJA(3)
95 sage: J.one().subalgebra_generated_by().gens()
96 (f0,)
97 sage: J = JordanSpinEJA(3, prefix='f')
98 sage: J.one().subalgebra_generated_by().gens()
99 (g0,)
100 sage: J = JordanSpinEJA(3, prefix='b')
101 sage: J.one().subalgebra_generated_by().gens()
102 (c0,)
103
104 Ensure that we can find subalgebras of subalgebras::
105
106 sage: A = ComplexHermitianEJA(3).one().subalgebra_generated_by()
107 sage: B = A.one().subalgebra_generated_by()
108 sage: B.dimension()
109 1
110
111 """
112 def __init__(self, superalgebra, basis, rank=None, category=None):
113 self._superalgebra = superalgebra
114 V = self._superalgebra.vector_space()
115 field = self._superalgebra.base_ring()
116 if category is None:
117 category = self._superalgebra.category()
118
119 # A half-assed attempt to ensure that we don't collide with
120 # the superalgebra's prefix (ignoring the fact that there
121 # could be super-superelgrbas in scope). If possible, we
122 # try to "increment" the parent algebra's prefix, although
123 # this idea goes out the window fast because some prefixen
124 # are off-limits.
125 prefixen = [ 'f', 'g', 'h', 'a', 'b', 'c', 'd' ]
126 try:
127 prefix = prefixen[prefixen.index(self._superalgebra.prefix()) + 1]
128 except ValueError:
129 prefix = prefixen[0]
130
131 basis_vectors = [ b.to_vector() for b in basis ]
132 superalgebra_basis = [ self._superalgebra.from_vector(b)
133 for b in basis_vectors ]
134
135 W = V.span_of_basis( V.from_vector(v) for v in basis_vectors )
136 n = len(superalgebra_basis)
137 mult_table = [[W.zero() for i in range(n)] for j in range(n)]
138 for i in range(n):
139 for j in range(n):
140 product = superalgebra_basis[i]*superalgebra_basis[j]
141 # product.to_vector() might live in a vector subspace
142 # if our parent algebra is already a subalgebra. We
143 # use V.from_vector() to make it "the right size" in
144 # that case.
145 product_vector = V.from_vector(product.to_vector())
146 mult_table[i][j] = W.coordinate_vector(product_vector)
147
148 natural_basis = tuple( b.natural_representation()
149 for b in superalgebra_basis )
150
151
152 self._vector_space = W
153 self._superalgebra_basis = superalgebra_basis
154
155
156 fdeja = super(FiniteDimensionalEuclideanJordanSubalgebra, self)
157 return fdeja.__init__(field,
158 mult_table,
159 rank,
160 prefix=prefix,
161 category=category,
162 natural_basis=natural_basis)
163
164
165
166 def _element_constructor_(self, elt):
167 """
168 Construct an element of this subalgebra from the given one.
169 The only valid arguments are elements of the parent algebra
170 that happen to live in this subalgebra.
171
172 SETUP::
173
174 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
175 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
176
177 EXAMPLES::
178
179 sage: J = RealSymmetricEJA(3)
180 sage: x = sum( i*J.gens()[i] for i in range(6) )
181 sage: basis = tuple( x^k for k in range(J.rank()) )
182 sage: K = FiniteDimensionalEuclideanJordanSubalgebra(J,basis)
183 sage: [ K(x^k) for k in range(J.rank()) ]
184 [f0, f1, f2]
185
186 ::
187
188 """
189 if elt not in self.superalgebra():
190 raise ValueError("not an element of this subalgebra")
191
192 coords = self.vector_space().coordinate_vector(elt.to_vector())
193 return self.from_vector(coords)
194
195
196 def one(self):
197 """
198 Return the multiplicative identity element of this algebra.
199
200 The superclass method computes the identity element, which is
201 beyond overkill in this case: the superalgebra identity
202 restricted to this algebra is its identity. Note that we can't
203 count on the first basis element being the identity -- it migth
204 have been scaled if we orthonormalized the basis.
205
206 SETUP::
207
208 sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
209 ....: random_eja)
210
211 EXAMPLES::
212
213 sage: J = RealCartesianProductEJA(5)
214 sage: J.one()
215 e0 + e1 + e2 + e3 + e4
216 sage: x = sum(J.gens())
217 sage: A = x.subalgebra_generated_by()
218 sage: A.one()
219 f0
220 sage: A.one().superalgebra_element()
221 e0 + e1 + e2 + e3 + e4
222
223 TESTS:
224
225 The identity element acts like the identity over the rationals::
226
227 sage: set_random_seed()
228 sage: x = random_eja().random_element()
229 sage: A = x.subalgebra_generated_by()
230 sage: x = A.random_element()
231 sage: A.one()*x == x and x*A.one() == x
232 True
233
234 The identity element acts like the identity over the algebraic
235 reals with an orthonormal basis::
236
237 sage: set_random_seed()
238 sage: x = random_eja(AA).random_element()
239 sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
240 sage: x = A.random_element()
241 sage: A.one()*x == x and x*A.one() == x
242 True
243
244 The matrix of the unit element's operator is the identity over
245 the rationals::
246
247 sage: set_random_seed()
248 sage: x = random_eja().random_element()
249 sage: A = x.subalgebra_generated_by()
250 sage: actual = A.one().operator().matrix()
251 sage: expected = matrix.identity(A.base_ring(), A.dimension())
252 sage: actual == expected
253 True
254
255 The matrix of the unit element's operator is the identity over
256 the algebraic reals with an orthonormal basis::
257
258 sage: set_random_seed()
259 sage: x = random_eja(AA).random_element()
260 sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
261 sage: actual = A.one().operator().matrix()
262 sage: expected = matrix.identity(A.base_ring(), A.dimension())
263 sage: actual == expected
264 True
265
266 """
267 if self.dimension() == 0:
268 return self.zero()
269 else:
270 sa_one = self.superalgebra().one().to_vector()
271 sa_coords = self.vector_space().coordinate_vector(sa_one)
272 return self.from_vector(sa_coords)
273
274
275 def natural_basis_space(self):
276 """
277 Return the natural basis space of this algebra, which is identical
278 to that of its superalgebra.
279
280 This is correct "by definition," and avoids a mismatch when the
281 subalgebra is trivial (with no natural basis to infer anything
282 from) and the parent is not.
283 """
284 return self.superalgebra().natural_basis_space()
285
286
287 def superalgebra(self):
288 """
289 Return the superalgebra that this algebra was generated from.
290 """
291 return self._superalgebra
292
293
294 def vector_space(self):
295 """
296 SETUP::
297
298 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
299 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
300
301 EXAMPLES::
302
303 sage: J = RealSymmetricEJA(3)
304 sage: x = J.monomial(0) + 2*J.monomial(2) + 5*J.monomial(5)
305 sage: basis = (x^0, x^1, x^2)
306 sage: K = FiniteDimensionalEuclideanJordanSubalgebra(J,basis)
307 sage: K.vector_space()
308 Vector space of degree 6 and dimension 3 over...
309 User basis matrix:
310 [ 1 0 1 0 0 1]
311 [ 1 0 2 0 0 5]
312 [ 1 0 4 0 0 25]
313 sage: (x^0).to_vector()
314 (1, 0, 1, 0, 0, 1)
315 sage: (x^1).to_vector()
316 (1, 0, 2, 0, 0, 5)
317 sage: (x^2).to_vector()
318 (1, 0, 4, 0, 0, 25)
319
320 """
321 return self._vector_space
322
323
324 Element = FiniteDimensionalEuclideanJordanSubalgebraElement