]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_subalgebra.py
eja: rename operator_inner_product -> operator_trace inner_product.
[sage.d.git] / mjo / eja / eja_subalgebra.py
1 from sage.matrix.constructor import matrix
2 from sage.misc.cachefunc import cached_method
3
4 from mjo.eja.eja_algebra import EJA
5 from mjo.eja.eja_element import (EJAElement,
6 CartesianProductParentEJAElement)
7
8 class EJASubalgebraElement(EJAElement):
9 """
10 SETUP::
11
12 sage: from mjo.eja.eja_algebra import random_eja
13
14 TESTS::
15
16 The matrix representation of an element in the subalgebra is
17 the same as its matrix representation in the superalgebra::
18
19 sage: x = random_eja(field=QQ,orthonormalize=False).random_element()
20 sage: A = x.subalgebra_generated_by(orthonormalize=False)
21 sage: y = A.random_element()
22 sage: actual = y.to_matrix()
23 sage: expected = y.superalgebra_element().to_matrix()
24 sage: actual == expected
25 True
26
27 The left-multiplication-by operator for elements in the subalgebra
28 works like it does in the superalgebra, even if we orthonormalize
29 our basis::
30
31 sage: x = random_eja(field=AA).random_element() # long time
32 sage: A = x.subalgebra_generated_by(orthonormalize=True) # long time
33 sage: y = A.random_element() # long time
34 sage: y.operator()(A.one()) == y # long time
35 True
36
37 """
38
39 def superalgebra_element(self):
40 """
41 Return the object in our algebra's superalgebra that corresponds
42 to myself.
43
44 SETUP::
45
46 sage: from mjo.eja.eja_algebra import (RealSymmetricEJA,
47 ....: random_eja)
48
49 EXAMPLES::
50
51 sage: J = RealSymmetricEJA(3)
52 sage: x = sum(J.gens())
53 sage: x
54 b0 + b1 + b2 + b3 + b4 + b5
55 sage: A = x.subalgebra_generated_by(orthonormalize=False)
56 sage: A(x)
57 c1
58 sage: A(x).superalgebra_element()
59 b0 + b1 + b2 + b3 + b4 + b5
60 sage: y = sum(A.gens())
61 sage: y
62 c0 + c1
63 sage: B = y.subalgebra_generated_by(orthonormalize=False)
64 sage: B(y)
65 d1
66 sage: B(y).superalgebra_element()
67 c0 + c1
68
69 TESTS:
70
71 We can convert back and forth faithfully::
72
73 sage: J = random_eja(field=QQ, orthonormalize=False)
74 sage: x = J.random_element()
75 sage: A = x.subalgebra_generated_by(orthonormalize=False)
76 sage: A(x).superalgebra_element() == x
77 True
78 sage: y = A.random_element()
79 sage: A(y.superalgebra_element()) == y
80 True
81 sage: B = y.subalgebra_generated_by(orthonormalize=False)
82 sage: B(y).superalgebra_element() == y
83 True
84
85 """
86 return self.parent().superalgebra_embedding()(self)
87
88
89
90
91 class EJASubalgebra(EJA):
92 """
93 A subalgebra of an EJA with a given basis.
94
95 SETUP::
96
97 sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
98 ....: JordanSpinEJA,
99 ....: RealSymmetricEJA)
100 sage: from mjo.eja.eja_subalgebra import EJASubalgebra
101
102 EXAMPLES:
103
104 The following Peirce subalgebras of the 2-by-2 real symmetric
105 matrices do not contain the superalgebra's identity element::
106
107 sage: J = RealSymmetricEJA(2)
108 sage: E11 = matrix(AA, [ [1,0],
109 ....: [0,0] ])
110 sage: E22 = matrix(AA, [ [0,0],
111 ....: [0,1] ])
112 sage: K1 = EJASubalgebra(J, (J(E11),), associative=True)
113 sage: K1.one().to_matrix()
114 [1 0]
115 [0 0]
116 sage: K2 = EJASubalgebra(J, (J(E22),), associative=True)
117 sage: K2.one().to_matrix()
118 [0 0]
119 [0 1]
120
121 TESTS:
122
123 Ensure that our generator names don't conflict with the
124 superalgebra::
125
126 sage: J = JordanSpinEJA(3)
127 sage: J.one().subalgebra_generated_by().gens()
128 (c0,)
129 sage: J = JordanSpinEJA(3, prefix='f')
130 sage: J.one().subalgebra_generated_by().gens()
131 (g0,)
132 sage: J = JordanSpinEJA(3, prefix='a')
133 sage: J.one().subalgebra_generated_by().gens()
134 (b0,)
135
136 Ensure that we can find subalgebras of subalgebras::
137
138 sage: A = ComplexHermitianEJA(3).one().subalgebra_generated_by()
139 sage: B = A.one().subalgebra_generated_by()
140 sage: B.dimension()
141 1
142 """
143 def __init__(self, superalgebra, basis, **kwargs):
144 self._superalgebra = superalgebra
145 V = self._superalgebra.vector_space()
146 field = self._superalgebra.base_ring()
147
148 # A half-assed attempt to ensure that we don't collide with
149 # the superalgebra's prefix (ignoring the fact that there
150 # could be super-superelgrbas in scope). If possible, we
151 # try to "increment" the parent algebra's prefix, although
152 # this idea goes out the window fast because some prefixen
153 # are off-limits.
154 prefixen = ["b","c","d","e","f","g","h","l","m"]
155 try:
156 prefix = prefixen[prefixen.index(self._superalgebra.prefix()) + 1]
157 except ValueError:
158 prefix = prefixen[0]
159
160 # The superalgebra constructor expects these to be in original matrix
161 # form, not algebra-element form.
162 matrix_basis = tuple( b.to_matrix() for b in basis )
163 def jordan_product(x,y):
164 return (self._superalgebra(x)*self._superalgebra(y)).to_matrix()
165
166 def inner_product(x,y):
167 return self._superalgebra(x).inner_product(self._superalgebra(y))
168
169 super().__init__(matrix_basis,
170 jordan_product,
171 inner_product,
172 field=field,
173 matrix_space=superalgebra.matrix_space(),
174 prefix=prefix,
175 **kwargs)
176
177
178
179 def _element_constructor_(self, elt):
180 """
181 Construct an element of this subalgebra from the given one.
182 The only valid arguments are elements of the parent algebra
183 that happen to live in this subalgebra.
184
185 SETUP::
186
187 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
188 sage: from mjo.eja.eja_subalgebra import EJASubalgebra
189
190 EXAMPLES::
191
192 sage: J = RealSymmetricEJA(3)
193 sage: X = matrix(AA, [ [0,0,1],
194 ....: [0,1,0],
195 ....: [1,0,0] ])
196 sage: x = J(X)
197 sage: basis = ( x, x^2 ) # x^2 is the identity matrix
198 sage: K = EJASubalgebra(J,
199 ....: basis,
200 ....: associative=True,
201 ....: orthonormalize=False)
202 sage: K(J.one())
203 c1
204 sage: K(J.one() + x)
205 c0 + c1
206
207 ::
208
209 """
210 if elt in self.superalgebra():
211 # If the subalgebra is trivial, its _matrix_span will be empty
212 # but we still want to be able convert the superalgebra's zero()
213 # element into the subalgebra's zero() element. There's no great
214 # workaround for this because sage checks that your basis is
215 # linearly-independent everywhere, so we can't just give it a
216 # basis consisting of the zero element.
217 m = elt.to_matrix()
218 if self.is_trivial() and m.is_zero():
219 return self.zero()
220 else:
221 return super()._element_constructor_(m)
222 else:
223 return super()._element_constructor_(elt)
224
225
226 def superalgebra(self):
227 """
228 Return the superalgebra that this algebra was generated from.
229 """
230 return self._superalgebra
231
232
233 @cached_method
234 def superalgebra_embedding(self):
235 r"""
236 Return the embedding from this subalgebra into the superalgebra.
237
238 SETUP::
239
240 sage: from mjo.eja.eja_algebra import HadamardEJA
241
242 EXAMPLES::
243
244 sage: J = HadamardEJA(4)
245 sage: A = J.one().subalgebra_generated_by()
246 sage: iota = A.superalgebra_embedding()
247 sage: iota
248 Linear operator between finite-dimensional Euclidean Jordan algebras represented by the matrix:
249 [1/2]
250 [1/2]
251 [1/2]
252 [1/2]
253 Domain: Euclidean Jordan algebra of dimension 1 over Algebraic Real Field
254 Codomain: Euclidean Jordan algebra of dimension 4 over Algebraic Real Field
255 sage: iota(A.one()) == J.one()
256 True
257
258 """
259 from mjo.eja.eja_operator import EJAOperator
260 mm = self._module_morphism(lambda j: self.superalgebra()(self.monomial(j).to_matrix()),
261 codomain=self.superalgebra())
262 return EJAOperator(self,
263 self.superalgebra(),
264 mm.matrix())
265
266
267
268 Element = EJASubalgebraElement
269
270
271
272 class CartesianProductEJASubalgebraElement(EJASubalgebraElement,
273 CartesianProductParentEJAElement):
274 r"""
275 The class for elements that both belong to a subalgebra and
276 have a Cartesian product algebra as their parent. By inheriting
277 :class:`CartesianProductParentEJAElement` in addition to
278 :class:`EJASubalgebraElement`, we allow the
279 ``to_matrix()`` method to be overridden with the version that
280 works on Cartesian products.
281
282 SETUP::
283
284 sage: from mjo.eja.eja_algebra import (HadamardEJA,
285 ....: RealSymmetricEJA)
286
287 TESTS:
288
289 This used to fail when ``subalgebra_idempotent()`` tried to
290 embed the subalgebra element back into the original EJA::
291
292 sage: J1 = HadamardEJA(0, field=QQ, orthonormalize=False)
293 sage: J2 = RealSymmetricEJA(2, field=QQ, orthonormalize=False)
294 sage: J = cartesian_product([J1,J2])
295 sage: J.one().subalgebra_idempotent() == J.one()
296 True
297
298 """
299 pass
300
301 class CartesianProductEJASubalgebra(EJASubalgebra):
302 r"""
303 Subalgebras whose parents are Cartesian products. Exists only
304 to specify a special element class that will (in addition)
305 inherit from ``CartesianProductParentEJAElement``.
306 """
307 Element = CartesianProductEJASubalgebraElement