]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_subalgebra.py
eja: fix construction of subalgebra-subalgebras.
[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 superalgebra = elt.parent()
104
105 # First compute the vector subspace spanned by the powers of
106 # the given element.
107 V = superalgebra.vector_space()
108 superalgebra_basis = [superalgebra.one()]
109 # If our superalgebra is a subalgebra of something else, then
110 # superalgebra.one().to_vector() won't have the right
111 # coordinates unless we use V.from_vector() below.
112 basis_vectors = [V.from_vector(superalgebra.one().to_vector())]
113 W = V.span_of_basis(basis_vectors)
114 for exponent in range(1, V.dimension()):
115 new_power = elt**exponent
116 basis_vectors.append( V.from_vector(new_power.to_vector()) )
117 try:
118 W = V.span_of_basis(basis_vectors)
119 superalgebra_basis.append( new_power )
120 except ValueError:
121 # Vectors weren't independent; bail and keep the
122 # last subspace that worked.
123 break
124
125 # Make the basis hashable for UniqueRepresentation.
126 superalgebra_basis = tuple(superalgebra_basis)
127
128 # Now figure out the entries of the right-multiplication
129 # matrix for the successive basis elements b0, b1,... of
130 # that subspace.
131 field = superalgebra.base_ring()
132 n = len(superalgebra_basis)
133 mult_table = [[W.zero() for i in range(n)] for j in range(n)]
134 for i in range(n):
135 for j in range(n):
136 product = superalgebra_basis[i]*superalgebra_basis[j]
137 # product.to_vector() might live in a vector subspace
138 # if our parent algebra is already a subalgebra. We
139 # use V.from_vector() to make it "the right size" in
140 # that case.
141 product_vector = V.from_vector(product.to_vector())
142 mult_table[i][j] = W.coordinate_vector(product_vector)
143
144 # A half-assed attempt to ensure that we don't collide with
145 # the superalgebra's prefix (ignoring the fact that there
146 # could be super-superelgrbas in scope). If possible, we
147 # try to "increment" the parent algebra's prefix, although
148 # this idea goes out the window fast because some prefixen
149 # are off-limits.
150 prefixen = [ 'f', 'g', 'h', 'a', 'b', 'c', 'd' ]
151 try:
152 prefix = prefixen[prefixen.index(superalgebra.prefix()) + 1]
153 except ValueError:
154 prefix = prefixen[0]
155
156 # The rank is the highest possible degree of a minimal
157 # polynomial, and is bounded above by the dimension. We know
158 # in this case that there's an element whose minimal
159 # polynomial has the same degree as the space's dimension
160 # (remember how we constructed the space?), so that must be
161 # its rank too.
162 rank = W.dimension()
163
164 category = superalgebra.category().Associative()
165 natural_basis = tuple( b.natural_representation()
166 for b in superalgebra_basis )
167
168 self._superalgebra = superalgebra
169 self._vector_space = W
170 self._superalgebra_basis = superalgebra_basis
171
172
173 fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, self)
174 return fdeja.__init__(field,
175 mult_table,
176 rank,
177 prefix=prefix,
178 category=category,
179 natural_basis=natural_basis)
180
181
182 def _element_constructor_(self, elt):
183 """
184 Construct an element of this subalgebra from the given one.
185 The only valid arguments are elements of the parent algebra
186 that happen to live in this subalgebra.
187
188 SETUP::
189
190 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
191 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
192
193 EXAMPLES::
194
195 sage: J = RealSymmetricEJA(3)
196 sage: x = sum( i*J.gens()[i] for i in range(6) )
197 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
198 sage: [ K(x^k) for k in range(J.rank()) ]
199 [f0, f1, f2]
200
201 ::
202
203 """
204 if elt == 0:
205 # Just as in the superalgebra class, we need to hack
206 # this special case to ensure that random_element() can
207 # coerce a ring zero into the algebra.
208 return self.zero()
209
210 if elt in self.superalgebra():
211 coords = self.vector_space().coordinate_vector(elt.to_vector())
212 return self.from_vector(coords)
213
214
215 def one_basis(self):
216 """
217 Return the basis-element-index of this algebra's unit element.
218 """
219 return 0
220
221
222 def one(self):
223 """
224 Return the multiplicative identity element of this algebra.
225
226 The superclass method computes the identity element, which is
227 beyond overkill in this case: the algebra identity should be our
228 first basis element. We implement this via :meth:`one_basis`
229 because that method can optionally be used by other parts of the
230 category framework.
231
232 SETUP::
233
234 sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
235 ....: random_eja)
236
237 EXAMPLES::
238
239 sage: J = RealCartesianProductEJA(5)
240 sage: J.one()
241 e0 + e1 + e2 + e3 + e4
242 sage: x = sum(J.gens())
243 sage: A = x.subalgebra_generated_by()
244 sage: A.one()
245 f0
246 sage: A.one().superalgebra_element()
247 e0 + e1 + e2 + e3 + e4
248
249 TESTS:
250
251 The identity element acts like the identity::
252
253 sage: set_random_seed()
254 sage: J = random_eja().random_element().subalgebra_generated_by()
255 sage: x = J.random_element()
256 sage: J.one()*x == x and x*J.one() == x
257 True
258
259 The matrix of the unit element's operator is the identity::
260
261 sage: set_random_seed()
262 sage: J = random_eja().random_element().subalgebra_generated_by()
263 sage: actual = J.one().operator().matrix()
264 sage: expected = matrix.identity(J.base_ring(), J.dimension())
265 sage: actual == expected
266 True
267 """
268 return self.monomial(self.one_basis())
269
270
271 def superalgebra(self):
272 """
273 Return the superalgebra that this algebra was generated from.
274 """
275 return self._superalgebra
276
277
278 def vector_space(self):
279 """
280 SETUP::
281
282 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
283 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
284
285 EXAMPLES::
286
287 sage: J = RealSymmetricEJA(3)
288 sage: x = sum( i*J.gens()[i] for i in range(6) )
289 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
290 sage: K.vector_space()
291 Vector space of degree 6 and dimension 3 over Rational Field
292 User basis matrix:
293 [ 1 0 1 0 0 1]
294 [ 0 1 2 3 4 5]
295 [10 14 21 19 31 50]
296 sage: (x^0).to_vector()
297 (1, 0, 1, 0, 0, 1)
298 sage: (x^1).to_vector()
299 (0, 1, 2, 3, 4, 5)
300 sage: (x^2).to_vector()
301 (10, 14, 21, 19, 31, 50)
302
303 """
304 return self._vector_space
305
306
307 Element = FiniteDimensionalEuclideanJordanElementSubalgebraElement