]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_subalgebra.py
eja: compute a natural basis for subalgebras.
[sage.d.git] / mjo / eja / eja_subalgebra.py
1 from sage.matrix.constructor import matrix
2 from sage.structure.category_object import normalize_names
3
4 from mjo.eja.eja_algebra import FiniteDimensionalEuclideanJordanAlgebra
5 from mjo.eja.eja_element import FiniteDimensionalEuclideanJordanAlgebraElement
6
7
8 class FiniteDimensionalEuclideanJordanElementSubalgebra(FiniteDimensionalEuclideanJordanAlgebra):
9 """
10 The subalgebra of an EJA generated by a single element.
11
12 SETUP::
13
14 sage: from mjo.eja.eja_algebra import FiniteDimensionalEuclideanJordanAlgebra
15
16 TESTS:
17
18 Ensure that non-clashing names are chosen::
19
20 sage: m1 = matrix.identity(QQ,2)
21 sage: m2 = matrix(QQ, [[0,1],
22 ....: [1,0]])
23 sage: J = FiniteDimensionalEuclideanJordanAlgebra(QQ,
24 ....: [m1,m2],
25 ....: 2,
26 ....: names='f')
27 sage: J.variable_names()
28 ('f0', 'f1')
29 sage: A = sum(J.gens()).subalgebra_generated_by()
30 sage: A.variable_names()
31 ('g0', 'g1')
32
33 """
34 @staticmethod
35 def __classcall_private__(cls, elt):
36 superalgebra = elt.parent()
37
38 # First compute the vector subspace spanned by the powers of
39 # the given element.
40 V = superalgebra.vector_space()
41 superalgebra_basis = [superalgebra.one()]
42 basis_vectors = [superalgebra.one().vector()]
43 W = V.span_of_basis(basis_vectors)
44 for exponent in range(1, V.dimension()):
45 new_power = elt**exponent
46 basis_vectors.append( new_power.vector() )
47 try:
48 W = V.span_of_basis(basis_vectors)
49 superalgebra_basis.append( new_power )
50 except ValueError:
51 # Vectors weren't independent; bail and keep the
52 # last subspace that worked.
53 break
54
55 # Make the basis hashable for UniqueRepresentation.
56 superalgebra_basis = tuple(superalgebra_basis)
57
58 # Now figure out the entries of the right-multiplication
59 # matrix for the successive basis elements b0, b1,... of
60 # that subspace.
61 F = superalgebra.base_ring()
62 mult_table = []
63 for b_right in superalgebra_basis:
64 b_right_rows = []
65 # The first row of the right-multiplication matrix by
66 # b1 is what we get if we apply that matrix to b1. The
67 # second row of the right multiplication matrix by b1
68 # is what we get when we apply that matrix to b2...
69 #
70 # IMPORTANT: this assumes that all vectors are COLUMN
71 # vectors, unlike our superclass (which uses row vectors).
72 for b_left in superalgebra_basis:
73 # Multiply in the original EJA, but then get the
74 # coordinates from the subalgebra in terms of its
75 # basis.
76 this_row = W.coordinates((b_left*b_right).vector())
77 b_right_rows.append(this_row)
78 b_right_matrix = matrix(F, b_right_rows)
79 mult_table.append(b_right_matrix)
80
81 for m in mult_table:
82 m.set_immutable()
83 mult_table = tuple(mult_table)
84
85 # The rank is the highest possible degree of a minimal
86 # polynomial, and is bounded above by the dimension. We know
87 # in this case that there's an element whose minimal
88 # polynomial has the same degree as the space's dimension
89 # (remember how we constructed the space?), so that must be
90 # its rank too.
91 rank = W.dimension()
92
93 # EJAs are power-associative, and this algebra is nothin but
94 # powers.
95 assume_associative=True
96
97 # Figure out a non-conflicting set of names to use.
98 valid_names = ['f','g','h','a','b','c','d']
99 name_idx = 0
100 names = normalize_names(W.dimension(), valid_names[0])
101 # This loops so long as the list of collisions is nonempty.
102 # Just crash if we run out of names without finding a set that
103 # don't conflict with the parent algebra.
104 while [y for y in names if y in superalgebra.variable_names()]:
105 name_idx += 1
106 names = normalize_names(W.dimension(), valid_names[name_idx])
107
108 cat = superalgebra.category().Associative()
109 natural_basis = tuple( b.natural_representation()
110 for b in superalgebra_basis )
111
112 fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, cls)
113 return fdeja.__classcall__(cls,
114 F,
115 mult_table,
116 rank,
117 superalgebra_basis,
118 W,
119 assume_associative=assume_associative,
120 names=names,
121 category=cat,
122 natural_basis=natural_basis)
123
124 def __init__(self,
125 field,
126 mult_table,
127 rank,
128 superalgebra_basis,
129 vector_space,
130 assume_associative=True,
131 names='f',
132 category=None,
133 natural_basis=None):
134
135 self._superalgebra = superalgebra_basis[0].parent()
136 self._vector_space = vector_space
137 self._superalgebra_basis = superalgebra_basis
138
139 fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, self)
140 fdeja.__init__(field,
141 mult_table,
142 rank,
143 assume_associative=assume_associative,
144 names=names,
145 category=category,
146 natural_basis=natural_basis)
147
148
149 def superalgebra(self):
150 """
151 Return the superalgebra that this algebra was generated from.
152 """
153 return self._superalgebra
154
155
156 def vector_space(self):
157 """
158 SETUP::
159
160 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
161 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
162
163 EXAMPLES::
164
165 sage: J = RealSymmetricEJA(3)
166 sage: x = sum( i*J.gens()[i] for i in range(6) )
167 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
168 sage: K.vector_space()
169 Vector space of degree 6 and dimension 3 over Rational Field
170 User basis matrix:
171 [ 1 0 0 1 0 1]
172 [ 0 1 2 3 4 5]
173 [ 5 11 14 26 34 45]
174 sage: (x^0).vector()
175 (1, 0, 0, 1, 0, 1)
176 sage: (x^1).vector()
177 (0, 1, 2, 3, 4, 5)
178 sage: (x^2).vector()
179 (5, 11, 14, 26, 34, 45)
180
181 """
182 return self._vector_space
183
184
185 class Element(FiniteDimensionalEuclideanJordanAlgebraElement):
186 """
187
188 SETUP::
189
190 sage: from mjo.eja.eja_algebra import random_eja
191
192 TESTS::
193
194 The natural representation of an element in the subalgebra is
195 the same as its natural representation in the superalgebra::
196
197 sage: set_random_seed()
198 sage: A = random_eja().random_element().subalgebra_generated_by()
199 sage: y = A.random_element()
200 sage: actual = y.natural_representation()
201 sage: expected = y.superalgebra_element().natural_representation()
202 sage: actual == expected
203 True
204
205 """
206 def __init__(self, A, elt=None):
207 """
208 SETUP::
209
210 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
211 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
212
213 EXAMPLES::
214
215 sage: J = RealSymmetricEJA(3)
216 sage: x = sum( i*J.gens()[i] for i in range(6) )
217 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
218 sage: [ K(x^k) for k in range(J.rank()) ]
219 [f0, f1, f2]
220
221 ::
222
223 """
224 if elt in A.superalgebra():
225 # Try to convert a parent algebra element into a
226 # subalgebra element...
227 try:
228 coords = A.vector_space().coordinates(elt.vector())
229 elt = A(coords)
230 except AttributeError:
231 # Catches a missing method in elt.vector()
232 pass
233
234 FiniteDimensionalEuclideanJordanAlgebraElement.__init__(self,
235 A,
236 elt)
237
238 def superalgebra_element(self):
239 """
240 Return the object in our algebra's superalgebra that corresponds
241 to myself.
242
243 SETUP::
244
245 sage: from mjo.eja.eja_algebra import (RealSymmetricEJA,
246 ....: random_eja)
247
248 EXAMPLES::
249
250 sage: J = RealSymmetricEJA(3)
251 sage: x = sum(J.gens())
252 sage: x
253 e0 + e1 + e2 + e3 + e4 + e5
254 sage: A = x.subalgebra_generated_by()
255 sage: A(x)
256 f1
257 sage: A(x).superalgebra_element()
258 e0 + e1 + e2 + e3 + e4 + e5
259
260 TESTS:
261
262 We can convert back and forth faithfully::
263
264 sage: set_random_seed()
265 sage: J = random_eja()
266 sage: x = J.random_element()
267 sage: A = x.subalgebra_generated_by()
268 sage: A(x).superalgebra_element() == x
269 True
270 sage: y = A.random_element()
271 sage: A(y.superalgebra_element()) == y
272 True
273
274 """
275 return self.parent().superalgebra().linear_combination(
276 zip(self.vector(), self.parent()._superalgebra_basis) )