]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_subalgebra.py
eja: implement subalgebra_generated_by() in terms of the new class.
[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 @staticmethod
13 def __classcall_private__(cls, elt):
14 superalgebra = elt.parent()
15
16 # First compute the vector subspace spanned by the powers of
17 # the given element.
18 V = superalgebra.vector_space()
19 superalgebra_basis = [superalgebra.one()]
20 basis_vectors = [superalgebra.one().vector()]
21 W = V.span_of_basis(basis_vectors)
22 for exponent in range(1, V.dimension()):
23 new_power = elt**exponent
24 basis_vectors.append( new_power.vector() )
25 try:
26 W = V.span_of_basis(basis_vectors)
27 superalgebra_basis.append( new_power )
28 except ValueError:
29 # Vectors weren't independent; bail and keep the
30 # last subspace that worked.
31 break
32
33 # Make the basis hashable for UniqueRepresentation.
34 superalgebra_basis = tuple(superalgebra_basis)
35
36 # Now figure out the entries of the right-multiplication
37 # matrix for the successive basis elements b0, b1,... of
38 # that subspace.
39 F = superalgebra.base_ring()
40 mult_table = []
41 for b_right in superalgebra_basis:
42 b_right_rows = []
43 # The first row of the right-multiplication matrix by
44 # b1 is what we get if we apply that matrix to b1. The
45 # second row of the right multiplication matrix by b1
46 # is what we get when we apply that matrix to b2...
47 #
48 # IMPORTANT: this assumes that all vectors are COLUMN
49 # vectors, unlike our superclass (which uses row vectors).
50 for b_left in superalgebra_basis:
51 # Multiply in the original EJA, but then get the
52 # coordinates from the subalgebra in terms of its
53 # basis.
54 this_row = W.coordinates((b_left*b_right).vector())
55 b_right_rows.append(this_row)
56 b_right_matrix = matrix(F, b_right_rows)
57 mult_table.append(b_right_matrix)
58
59 for m in mult_table:
60 m.set_immutable()
61 mult_table = tuple(mult_table)
62
63 # The rank is the highest possible degree of a minimal
64 # polynomial, and is bounded above by the dimension. We know
65 # in this case that there's an element whose minimal
66 # polynomial has the same degree as the space's dimension
67 # (remember how we constructed the space?), so that must be
68 # its rank too.
69 rank = W.dimension()
70
71 # EJAs are power-associative, and this algebra is nothin but
72 # powers.
73 assume_associative=True
74
75 # TODO: Un-hard-code this. It should be possible to get the "next"
76 # name based on the parent's generator names.
77 names = 'f'
78 names = normalize_names(W.dimension(), names)
79
80 cat = superalgebra.category().Associative()
81
82 # TODO: compute this and actually specify it.
83 natural_basis = None
84
85 fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, cls)
86 return fdeja.__classcall__(cls,
87 F,
88 mult_table,
89 rank,
90 superalgebra_basis,
91 W,
92 assume_associative=assume_associative,
93 names=names,
94 category=cat,
95 natural_basis=natural_basis)
96
97 def __init__(self,
98 field,
99 mult_table,
100 rank,
101 superalgebra_basis,
102 vector_space,
103 assume_associative=True,
104 names='f',
105 category=None,
106 natural_basis=None):
107
108 self._superalgebra = superalgebra_basis[0].parent()
109 self._vector_space = vector_space
110 self._superalgebra_basis = superalgebra_basis
111
112 fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, self)
113 fdeja.__init__(field,
114 mult_table,
115 rank,
116 assume_associative=assume_associative,
117 names=names,
118 category=category,
119 natural_basis=natural_basis)
120
121
122 def superalgebra(self):
123 """
124 Return the superalgebra that this algebra was generated from.
125 """
126 return self._superalgebra
127
128
129 def vector_space(self):
130 """
131 SETUP::
132
133 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
134 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
135
136 EXAMPLES::
137
138 sage: J = RealSymmetricEJA(3)
139 sage: x = sum( i*J.gens()[i] for i in range(6) )
140 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
141 sage: K.vector_space()
142 Vector space of degree 6 and dimension 3 over Rational Field
143 User basis matrix:
144 [ 1 0 0 1 0 1]
145 [ 0 1 2 3 4 5]
146 [ 5 11 14 26 34 45]
147 sage: (x^0).vector()
148 (1, 0, 0, 1, 0, 1)
149 sage: (x^1).vector()
150 (0, 1, 2, 3, 4, 5)
151 sage: (x^2).vector()
152 (5, 11, 14, 26, 34, 45)
153
154 """
155 return self._vector_space
156
157
158 class Element(FiniteDimensionalEuclideanJordanAlgebraElement):
159 def __init__(self, A, elt=None):
160 """
161 SETUP::
162
163 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
164 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
165
166 EXAMPLES::
167
168 sage: J = RealSymmetricEJA(3)
169 sage: x = sum( i*J.gens()[i] for i in range(6) )
170 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
171 sage: [ K(x^k) for k in range(J.rank()) ]
172 [f0, f1, f2]
173
174 ::
175
176 """
177 if elt in A.superalgebra():
178 # Try to convert a parent algebra element into a
179 # subalgebra element...
180 try:
181 coords = A.vector_space().coordinates(elt.vector())
182 elt = A(coords)
183 except AttributeError:
184 # Catches a missing method in elt.vector()
185 pass
186
187 FiniteDimensionalEuclideanJordanAlgebraElement.__init__(self,
188 A,
189 elt)
190
191 def superalgebra_element(self):
192 """
193 Return the object in our algebra's superalgebra that corresponds
194 to myself.
195
196 SETUP::
197
198 sage: from mjo.eja.eja_algebra import (RealSymmetricEJA,
199 ....: random_eja)
200
201 EXAMPLES::
202
203 sage: J = RealSymmetricEJA(3)
204 sage: x = sum(J.gens())
205 sage: x
206 e0 + e1 + e2 + e3 + e4 + e5
207 sage: A = x.subalgebra_generated_by()
208 sage: A(x)
209 f1
210 sage: A(x).superalgebra_element()
211 e0 + e1 + e2 + e3 + e4 + e5
212
213 TESTS:
214
215 We can convert back and forth faithfully::
216
217 sage: set_random_seed()
218 sage: J = random_eja()
219 sage: x = J.random_element()
220 sage: A = x.subalgebra_generated_by()
221 sage: A(x).superalgebra_element() == x
222 True
223 sage: y = A.random_element()
224 sage: A(y.superalgebra_element()) == y
225 True
226
227 """
228 return self.parent().superalgebra().linear_combination(
229 zip(self.vector(), self.parent()._superalgebra_basis) )