]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_subalgebra.py
eja: use non-clashing generator names in 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
110 # TODO: compute this and actually specify it.
111 natural_basis = None
112
113 fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, cls)
114 return fdeja.__classcall__(cls,
115 F,
116 mult_table,
117 rank,
118 superalgebra_basis,
119 W,
120 assume_associative=assume_associative,
121 names=names,
122 category=cat,
123 natural_basis=natural_basis)
124
125 def __init__(self,
126 field,
127 mult_table,
128 rank,
129 superalgebra_basis,
130 vector_space,
131 assume_associative=True,
132 names='f',
133 category=None,
134 natural_basis=None):
135
136 self._superalgebra = superalgebra_basis[0].parent()
137 self._vector_space = vector_space
138 self._superalgebra_basis = superalgebra_basis
139
140 fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, self)
141 fdeja.__init__(field,
142 mult_table,
143 rank,
144 assume_associative=assume_associative,
145 names=names,
146 category=category,
147 natural_basis=natural_basis)
148
149
150 def superalgebra(self):
151 """
152 Return the superalgebra that this algebra was generated from.
153 """
154 return self._superalgebra
155
156
157 def vector_space(self):
158 """
159 SETUP::
160
161 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
162 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
163
164 EXAMPLES::
165
166 sage: J = RealSymmetricEJA(3)
167 sage: x = sum( i*J.gens()[i] for i in range(6) )
168 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
169 sage: K.vector_space()
170 Vector space of degree 6 and dimension 3 over Rational Field
171 User basis matrix:
172 [ 1 0 0 1 0 1]
173 [ 0 1 2 3 4 5]
174 [ 5 11 14 26 34 45]
175 sage: (x^0).vector()
176 (1, 0, 0, 1, 0, 1)
177 sage: (x^1).vector()
178 (0, 1, 2, 3, 4, 5)
179 sage: (x^2).vector()
180 (5, 11, 14, 26, 34, 45)
181
182 """
183 return self._vector_space
184
185
186 class Element(FiniteDimensionalEuclideanJordanAlgebraElement):
187 def __init__(self, A, elt=None):
188 """
189 SETUP::
190
191 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
192 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
193
194 EXAMPLES::
195
196 sage: J = RealSymmetricEJA(3)
197 sage: x = sum( i*J.gens()[i] for i in range(6) )
198 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
199 sage: [ K(x^k) for k in range(J.rank()) ]
200 [f0, f1, f2]
201
202 ::
203
204 """
205 if elt in A.superalgebra():
206 # Try to convert a parent algebra element into a
207 # subalgebra element...
208 try:
209 coords = A.vector_space().coordinates(elt.vector())
210 elt = A(coords)
211 except AttributeError:
212 # Catches a missing method in elt.vector()
213 pass
214
215 FiniteDimensionalEuclideanJordanAlgebraElement.__init__(self,
216 A,
217 elt)
218
219 def superalgebra_element(self):
220 """
221 Return the object in our algebra's superalgebra that corresponds
222 to myself.
223
224 SETUP::
225
226 sage: from mjo.eja.eja_algebra import (RealSymmetricEJA,
227 ....: random_eja)
228
229 EXAMPLES::
230
231 sage: J = RealSymmetricEJA(3)
232 sage: x = sum(J.gens())
233 sage: x
234 e0 + e1 + e2 + e3 + e4 + e5
235 sage: A = x.subalgebra_generated_by()
236 sage: A(x)
237 f1
238 sage: A(x).superalgebra_element()
239 e0 + e1 + e2 + e3 + e4 + e5
240
241 TESTS:
242
243 We can convert back and forth faithfully::
244
245 sage: set_random_seed()
246 sage: J = random_eja()
247 sage: x = J.random_element()
248 sage: A = x.subalgebra_generated_by()
249 sage: A(x).superalgebra_element() == x
250 True
251 sage: y = A.random_element()
252 sage: A(y.superalgebra_element()) == y
253 True
254
255 """
256 return self.parent().superalgebra().linear_combination(
257 zip(self.vector(), self.parent()._superalgebra_basis) )