]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_subalgebra.py
eja: try to speed up super/subalgebra conversion.
[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 sage: y = sum(A.gens())
60 sage: y
61 f0 + f1
62 sage: B = y.subalgebra_generated_by()
63 sage: B(y)
64 g1
65 sage: B(y).superalgebra_element()
66 f0 + f1
67
68 TESTS:
69
70 We can convert back and forth faithfully::
71
72 sage: set_random_seed()
73 sage: J = random_eja()
74 sage: x = J.random_element()
75 sage: A = x.subalgebra_generated_by()
76 sage: A(x).superalgebra_element() == x
77 True
78 sage: y = A.random_element()
79 sage: A(y.superalgebra_element()) == y
80 True
81 sage: B = y.subalgebra_generated_by()
82 sage: B(y).superalgebra_element() == y
83 True
84
85 """
86 # As with the _element_constructor_() method on the
87 # algebra... even in a subspace of a subspace, the basis
88 # elements belong to the ambient space. As a result, only one
89 # level of coordinate_vector() is needed, regardless of how
90 # deeply we're nested.
91 W = self.parent().vector_space()
92 V = self.parent().superalgebra().vector_space()
93
94 # Multiply on the left because basis_matrix() is row-wise.
95 ambient_coords = self.to_vector()*W.basis_matrix()
96 V_coords = V.coordinate_vector(ambient_coords)
97 return self.parent().superalgebra().from_vector(V_coords)
98
99
100
101
102 class FiniteDimensionalEuclideanJordanSubalgebra(FiniteDimensionalEuclideanJordanAlgebra):
103 """
104 A subalgebra of an EJA with a given basis.
105
106 SETUP::
107
108 sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
109 ....: JordanSpinEJA,
110 ....: RealSymmetricEJA)
111 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
112
113 EXAMPLES:
114
115 The following Peirce subalgebras of the 2-by-2 real symmetric
116 matrices do not contain the superalgebra's identity element::
117
118 sage: J = RealSymmetricEJA(2)
119 sage: E11 = matrix(AA, [ [1,0],
120 ....: [0,0] ])
121 sage: E22 = matrix(AA, [ [0,0],
122 ....: [0,1] ])
123 sage: K1 = FiniteDimensionalEuclideanJordanSubalgebra(J, (J(E11),))
124 sage: K1.one().natural_representation()
125 [1 0]
126 [0 0]
127 sage: K2 = FiniteDimensionalEuclideanJordanSubalgebra(J, (J(E22),))
128 sage: K2.one().natural_representation()
129 [0 0]
130 [0 1]
131
132 TESTS:
133
134 Ensure that our generator names don't conflict with the superalgebra::
135
136 sage: J = JordanSpinEJA(3)
137 sage: J.one().subalgebra_generated_by().gens()
138 (f0,)
139 sage: J = JordanSpinEJA(3, prefix='f')
140 sage: J.one().subalgebra_generated_by().gens()
141 (g0,)
142 sage: J = JordanSpinEJA(3, prefix='b')
143 sage: J.one().subalgebra_generated_by().gens()
144 (c0,)
145
146 Ensure that we can find subalgebras of subalgebras::
147
148 sage: A = ComplexHermitianEJA(3).one().subalgebra_generated_by()
149 sage: B = A.one().subalgebra_generated_by()
150 sage: B.dimension()
151 1
152
153 """
154 def __init__(self, superalgebra, basis, category=None, check_axioms=True):
155 self._superalgebra = superalgebra
156 V = self._superalgebra.vector_space()
157 field = self._superalgebra.base_ring()
158 if category is None:
159 category = self._superalgebra.category()
160
161 # A half-assed attempt to ensure that we don't collide with
162 # the superalgebra's prefix (ignoring the fact that there
163 # could be super-superelgrbas in scope). If possible, we
164 # try to "increment" the parent algebra's prefix, although
165 # this idea goes out the window fast because some prefixen
166 # are off-limits.
167 prefixen = [ 'f', 'g', 'h', 'a', 'b', 'c', 'd' ]
168 try:
169 prefix = prefixen[prefixen.index(self._superalgebra.prefix()) + 1]
170 except ValueError:
171 prefix = prefixen[0]
172
173 # If our superalgebra is a subalgebra of something else, then
174 # these vectors won't have the right coordinates for
175 # V.span_of_basis() unless we use V.from_vector() on them.
176 W = V.span_of_basis( V.from_vector(b.to_vector()) for b in basis )
177
178 n = len(basis)
179 mult_table = [[W.zero() for i in range(n)] for j in range(n)]
180 for i in range(n):
181 for j in range(n):
182 product = basis[i]*basis[j]
183 # product.to_vector() might live in a vector subspace
184 # if our parent algebra is already a subalgebra. We
185 # use V.from_vector() to make it "the right size" in
186 # that case.
187 product_vector = V.from_vector(product.to_vector())
188 mult_table[i][j] = W.coordinate_vector(product_vector)
189
190 natural_basis = tuple( b.natural_representation() for b in basis )
191
192
193 self._vector_space = W
194
195 fdeja = super(FiniteDimensionalEuclideanJordanSubalgebra, self)
196 fdeja.__init__(field,
197 mult_table,
198 prefix=prefix,
199 category=category,
200 natural_basis=natural_basis,
201 check_field=False,
202 check_axioms=check_axioms)
203
204
205
206 def _element_constructor_(self, elt):
207 """
208 Construct an element of this subalgebra from the given one.
209 The only valid arguments are elements of the parent algebra
210 that happen to live in this subalgebra.
211
212 SETUP::
213
214 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
215 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
216
217 EXAMPLES::
218
219 sage: J = RealSymmetricEJA(3)
220 sage: X = matrix(AA, [ [0,0,1],
221 ....: [0,1,0],
222 ....: [1,0,0] ])
223 sage: x = J(X)
224 sage: basis = ( x, x^2 ) # x^2 is the identity matrix
225 sage: K = FiniteDimensionalEuclideanJordanSubalgebra(J, basis)
226 sage: K(J.one())
227 f1
228 sage: K(J.one() + x)
229 f0 + f1
230
231 ::
232
233 """
234 if elt not in self.superalgebra():
235 raise ValueError("not an element of this subalgebra")
236
237 # The extra hackery is because foo.to_vector() might not live
238 # in foo.parent().vector_space()! Subspaces of subspaces still
239 # have user bases in the ambient space, though, so only one
240 # level of coordinate_vector() is needed. In other words, if V
241 # is itself a subspace, the basis elements for W will be of
242 # the same length as the basis elements for V -- namely
243 # whatever the dimension of the ambient (parent of V?) space is.
244 V = self.superalgebra().vector_space()
245 W = self.vector_space()
246
247 # Multiply on the left because basis_matrix() is row-wise.
248 ambient_coords = elt.to_vector()*V.basis_matrix()
249 W_coords = W.coordinate_vector(ambient_coords)
250 return self.from_vector(W_coords)
251
252
253
254 def natural_basis_space(self):
255 """
256 Return the natural basis space of this algebra, which is identical
257 to that of its superalgebra.
258
259 This is correct "by definition," and avoids a mismatch when the
260 subalgebra is trivial (with no natural basis to infer anything
261 from) and the parent is not.
262 """
263 return self.superalgebra().natural_basis_space()
264
265
266 def superalgebra(self):
267 """
268 Return the superalgebra that this algebra was generated from.
269 """
270 return self._superalgebra
271
272
273 def vector_space(self):
274 """
275 SETUP::
276
277 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
278 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
279
280 EXAMPLES::
281
282 sage: J = RealSymmetricEJA(3)
283 sage: E11 = matrix(ZZ, [ [1,0,0],
284 ....: [0,0,0],
285 ....: [0,0,0] ])
286 sage: E22 = matrix(ZZ, [ [0,0,0],
287 ....: [0,1,0],
288 ....: [0,0,0] ])
289 sage: b1 = J(E11)
290 sage: b2 = J(E22)
291 sage: basis = (b1, b2)
292 sage: K = FiniteDimensionalEuclideanJordanSubalgebra(J,basis)
293 sage: K.vector_space()
294 Vector space of degree 6 and dimension 2 over...
295 User basis matrix:
296 [1 0 0 0 0 0]
297 [0 0 1 0 0 0]
298 sage: b1.to_vector()
299 (1, 0, 0, 0, 0, 0)
300 sage: b2.to_vector()
301 (0, 0, 1, 0, 0, 0)
302
303 """
304 return self._vector_space
305
306
307 Element = FiniteDimensionalEuclideanJordanSubalgebraElement