]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_subalgebra.py
eja: don't waste time computing the unit element in 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 def __init__(self, elt):
76 superalgebra = elt.parent()
77
78 # First compute the vector subspace spanned by the powers of
79 # the given element.
80 V = superalgebra.vector_space()
81 superalgebra_basis = [superalgebra.one()]
82 basis_vectors = [superalgebra.one().to_vector()]
83 W = V.span_of_basis(basis_vectors)
84 for exponent in range(1, V.dimension()):
85 new_power = elt**exponent
86 basis_vectors.append( new_power.to_vector() )
87 try:
88 W = V.span_of_basis(basis_vectors)
89 superalgebra_basis.append( new_power )
90 except ValueError:
91 # Vectors weren't independent; bail and keep the
92 # last subspace that worked.
93 break
94
95 # Make the basis hashable for UniqueRepresentation.
96 superalgebra_basis = tuple(superalgebra_basis)
97
98 # Now figure out the entries of the right-multiplication
99 # matrix for the successive basis elements b0, b1,... of
100 # that subspace.
101 field = superalgebra.base_ring()
102 n = len(superalgebra_basis)
103 mult_table = [[W.zero() for i in range(n)] for j in range(n)]
104 for i in range(n):
105 for j in range(n):
106 product = superalgebra_basis[i]*superalgebra_basis[j]
107 mult_table[i][j] = W.coordinate_vector(product.to_vector())
108
109 # TODO: We'll have to redo this and make it unique again...
110 prefix = 'f'
111
112 # The rank is the highest possible degree of a minimal
113 # polynomial, and is bounded above by the dimension. We know
114 # in this case that there's an element whose minimal
115 # polynomial has the same degree as the space's dimension
116 # (remember how we constructed the space?), so that must be
117 # its rank too.
118 rank = W.dimension()
119
120 category = superalgebra.category().Associative()
121 natural_basis = tuple( b.natural_representation()
122 for b in superalgebra_basis )
123
124 self._superalgebra = superalgebra
125 self._vector_space = W
126 self._superalgebra_basis = superalgebra_basis
127
128
129 fdeja = super(FiniteDimensionalEuclideanJordanElementSubalgebra, self)
130 return fdeja.__init__(field,
131 mult_table,
132 rank,
133 prefix=prefix,
134 category=category,
135 natural_basis=natural_basis)
136
137
138 def _element_constructor_(self, elt):
139 """
140 Construct an element of this subalgebra from the given one.
141 The only valid arguments are elements of the parent algebra
142 that happen to live in this subalgebra.
143
144 SETUP::
145
146 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
147 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
148
149 EXAMPLES::
150
151 sage: J = RealSymmetricEJA(3)
152 sage: x = sum( i*J.gens()[i] for i in range(6) )
153 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
154 sage: [ K(x^k) for k in range(J.rank()) ]
155 [f0, f1, f2]
156
157 ::
158
159 """
160 if elt in self.superalgebra():
161 coords = self.vector_space().coordinate_vector(elt.to_vector())
162 return self.from_vector(coords)
163
164
165 def one_basis(self):
166 """
167 Return the basis-element-index of this algebra's unit element.
168 """
169 return 0
170
171
172 def one(self):
173 """
174 Return the multiplicative identity element of this algebra.
175
176 The superclass method computes the identity element, which is
177 beyond overkill in this case: the algebra identity should be our
178 first basis element. We implement this via :meth:`one_basis`
179 because that method can optionally be used by other parts of the
180 category framework.
181
182 SETUP::
183
184 sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
185 ....: random_eja)
186
187 EXAMPLES::
188
189 sage: J = RealCartesianProductEJA(5)
190 sage: J.one()
191 e0 + e1 + e2 + e3 + e4
192 sage: x = sum(J.gens())
193 sage: A = x.subalgebra_generated_by()
194 sage: A.one()
195 f0
196 sage: A.one().superalgebra_element()
197 e0 + e1 + e2 + e3 + e4
198
199 TESTS:
200
201 The identity element acts like the identity::
202
203 sage: set_random_seed()
204 sage: J = random_eja().random_element().subalgebra_generated_by()
205 sage: x = J.random_element()
206 sage: J.one()*x == x and x*J.one() == x
207 True
208
209 The matrix of the unit element's operator is the identity::
210
211 sage: set_random_seed()
212 sage: J = random_eja().random_element().subalgebra_generated_by()
213 sage: actual = J.one().operator().matrix()
214 sage: expected = matrix.identity(J.base_ring(), J.dimension())
215 sage: actual == expected
216 True
217 """
218 return self.monomial(self.one_basis())
219
220
221 def superalgebra(self):
222 """
223 Return the superalgebra that this algebra was generated from.
224 """
225 return self._superalgebra
226
227
228 def vector_space(self):
229 """
230 SETUP::
231
232 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
233 sage: from mjo.eja.eja_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
234
235 EXAMPLES::
236
237 sage: J = RealSymmetricEJA(3)
238 sage: x = sum( i*J.gens()[i] for i in range(6) )
239 sage: K = FiniteDimensionalEuclideanJordanElementSubalgebra(x)
240 sage: K.vector_space()
241 Vector space of degree 6 and dimension 3 over Rational Field
242 User basis matrix:
243 [ 1 0 1 0 0 1]
244 [ 0 1 2 3 4 5]
245 [10 14 21 19 31 50]
246 sage: (x^0).to_vector()
247 (1, 0, 1, 0, 0, 1)
248 sage: (x^1).to_vector()
249 (0, 1, 2, 3, 4, 5)
250 sage: (x^2).to_vector()
251 (10, 14, 21, 19, 31, 50)
252
253 """
254 return self._vector_space
255
256
257 Element = FiniteDimensionalEuclideanJordanElementSubalgebraElement