]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_subalgebra.py
e7308ea34b9a36aef09a84069a1289e072487ec7
[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 matrix representation of an element in the subalgebra is
15 the same as its matrix 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.to_matrix()
21 sage: expected = y.superalgebra_element().to_matrix()
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(field=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().to_matrix()
125 [1 0]
126 [0 0]
127 sage: K2 = FiniteDimensionalEuclideanJordanSubalgebra(J, (J(E22),))
128 sage: K2.one().to_matrix()
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 check=check_axioms)
178
179 n = len(basis)
180 if check_axioms:
181 # The tables are square if we're verifying that they
182 # are commutative.
183 mult_table = [[W.zero() for j in range(n)] for i in range(n)]
184 ip_table = [ [ self._superalgebra.inner_product(basis[i],basis[j])
185 for j in range(n) ]
186 for i in range(n) ]
187 else:
188 mult_table = [[W.zero() for j in range(i+1)] for i in range(n)]
189 ip_table = [ [ self._superalgebra.inner_product(basis[i],basis[j])
190 for j in range(i+1) ]
191 for i in range(n) ]
192
193 for i in range(n):
194 for j in range(i+1):
195 product = basis[i]*basis[j]
196 # product.to_vector() might live in a vector subspace
197 # if our parent algebra is already a subalgebra. We
198 # use V.from_vector() to make it "the right size" in
199 # that case.
200 product_vector = V.from_vector(product.to_vector())
201 mult_table[i][j] = W.coordinate_vector(product_vector)
202 if check_axioms:
203 mult_table[j][i] = mult_table[i][j]
204
205 matrix_basis = tuple( b.to_matrix() for b in basis )
206
207
208 self._vector_space = W
209
210 fdeja = super(FiniteDimensionalEuclideanJordanSubalgebra, self)
211 fdeja.__init__(field,
212 mult_table,
213 ip_table,
214 prefix=prefix,
215 category=category,
216 matrix_basis=matrix_basis,
217 check_field=False,
218 check_axioms=check_axioms)
219
220
221
222 def _element_constructor_(self, elt):
223 """
224 Construct an element of this subalgebra from the given one.
225 The only valid arguments are elements of the parent algebra
226 that happen to live in this subalgebra.
227
228 SETUP::
229
230 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
231 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
232
233 EXAMPLES::
234
235 sage: J = RealSymmetricEJA(3)
236 sage: X = matrix(AA, [ [0,0,1],
237 ....: [0,1,0],
238 ....: [1,0,0] ])
239 sage: x = J(X)
240 sage: basis = ( x, x^2 ) # x^2 is the identity matrix
241 sage: K = FiniteDimensionalEuclideanJordanSubalgebra(J, basis)
242 sage: K(J.one())
243 f1
244 sage: K(J.one() + x)
245 f0 + f1
246
247 ::
248
249 """
250 if elt not in self.superalgebra():
251 raise ValueError("not an element of this subalgebra")
252
253 # The extra hackery is because foo.to_vector() might not live
254 # in foo.parent().vector_space()! Subspaces of subspaces still
255 # have user bases in the ambient space, though, so only one
256 # level of coordinate_vector() is needed. In other words, if V
257 # is itself a subspace, the basis elements for W will be of
258 # the same length as the basis elements for V -- namely
259 # whatever the dimension of the ambient (parent of V?) space is.
260 V = self.superalgebra().vector_space()
261 W = self.vector_space()
262
263 # Multiply on the left because basis_matrix() is row-wise.
264 ambient_coords = elt.to_vector()*V.basis_matrix()
265 W_coords = W.coordinate_vector(ambient_coords)
266 return self.from_vector(W_coords)
267
268
269
270 def matrix_space(self):
271 """
272 Return the matrix space of this algebra, which is identical to
273 that of its superalgebra.
274
275 This is correct "by definition," and avoids a mismatch when
276 the subalgebra is trivial (with no matrix basis elements to
277 infer anything from) and the parent is not.
278 """
279 return self.superalgebra().matrix_space()
280
281
282 def superalgebra(self):
283 """
284 Return the superalgebra that this algebra was generated from.
285 """
286 return self._superalgebra
287
288
289 def vector_space(self):
290 """
291 SETUP::
292
293 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
294 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanSubalgebra
295
296 EXAMPLES::
297
298 sage: J = RealSymmetricEJA(3)
299 sage: E11 = matrix(ZZ, [ [1,0,0],
300 ....: [0,0,0],
301 ....: [0,0,0] ])
302 sage: E22 = matrix(ZZ, [ [0,0,0],
303 ....: [0,1,0],
304 ....: [0,0,0] ])
305 sage: b1 = J(E11)
306 sage: b2 = J(E22)
307 sage: basis = (b1, b2)
308 sage: K = FiniteDimensionalEuclideanJordanSubalgebra(J,basis)
309 sage: K.vector_space()
310 Vector space of degree 6 and dimension 2 over...
311 User basis matrix:
312 [1 0 0 0 0 0]
313 [0 0 1 0 0 0]
314 sage: b1.to_vector()
315 (1, 0, 0, 0, 0, 0)
316 sage: b2.to_vector()
317 (0, 0, 1, 0, 0, 0)
318
319 """
320 return self._vector_space
321
322
323 Element = FiniteDimensionalEuclideanJordanSubalgebraElement