]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_operator.py
7c3b2a6a4721848caaaf4d30cecbb08d0eab587f
[sage.d.git] / mjo / eja / eja_operator.py
1 from sage.matrix.constructor import matrix
2 from sage.categories.all import FreeModules
3 from sage.categories.map import Map
4
5 class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
6 def __init__(self, domain_eja, codomain_eja, mat):
7 # if not (
8 # isinstance(domain_eja, FiniteDimensionalEuclideanJordanAlgebra) and
9 # isinstance(codomain_eja, FiniteDimensionalEuclideanJordanAlgebra) ):
10 # raise ValueError('(co)domains must be finite-dimensional Euclidean '
11 # 'Jordan algebras')
12
13 F = domain_eja.base_ring()
14 if not (F == codomain_eja.base_ring()):
15 raise ValueError("domain and codomain must have the same base ring")
16
17 # We need to supply something here to avoid getting the
18 # default Homset of the parent FiniteDimensionalAlgebra class,
19 # which messes up e.g. equality testing. We use FreeModules(F)
20 # instead of VectorSpaces(F) because our characteristic polynomial
21 # algorithm will need to F to be a polynomial ring at some point.
22 # When F is a field, FreeModules(F) returns VectorSpaces(F) anyway.
23 parent = domain_eja.Hom(codomain_eja, FreeModules(F))
24
25 # The Map initializer will set our parent to a homset, which
26 # is explicitly NOT what we want, because these ain't algebra
27 # homomorphisms.
28 super(FiniteDimensionalEuclideanJordanAlgebraOperator,self).__init__(parent)
29
30 # Keep a matrix around to do all of the real work. It would
31 # be nice if we could use a VectorSpaceMorphism instead, but
32 # those use row vectors that we don't want to accidentally
33 # expose to our users.
34 self._matrix = mat
35
36
37 def _call_(self, x):
38 """
39 Allow this operator to be called only on elements of an EJA.
40
41 SETUP::
42
43 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
44 sage: from mjo.eja.eja_algebra import JordanSpinEJA
45
46 EXAMPLES::
47
48 sage: J = JordanSpinEJA(3)
49 sage: x = J.linear_combination(zip(J.gens(),range(len(J.gens()))))
50 sage: id = identity_matrix(J.base_ring(), J.dimension())
51 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
52 sage: f(x) == x
53 True
54
55 """
56 return self.codomain().from_vector(self.matrix()*x.to_vector())
57
58
59 def _add_(self, other):
60 """
61 Add the ``other`` EJA operator to this one.
62
63 SETUP::
64
65 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
66 sage: from mjo.eja.eja_algebra import (
67 ....: JordanSpinEJA,
68 ....: RealSymmetricEJA )
69
70 EXAMPLES:
71
72 When we add two EJA operators, we get another one back::
73
74 sage: J = RealSymmetricEJA(2)
75 sage: id = identity_matrix(J.base_ring(), J.dimension())
76 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
77 sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
78 sage: f + g
79 Linear operator between finite-dimensional Euclidean Jordan
80 algebras represented by the matrix:
81 [2 0 0]
82 [0 2 0]
83 [0 0 2]
84 Domain: Euclidean Jordan algebra of dimension 3 over
85 Rational Field
86 Codomain: Euclidean Jordan algebra of dimension 3 over
87 Rational Field
88
89 If you try to add two identical vector space operators but on
90 different EJAs, that should blow up::
91
92 sage: J1 = RealSymmetricEJA(2)
93 sage: J2 = JordanSpinEJA(3)
94 sage: id = identity_matrix(QQ, 3)
95 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,J1,id)
96 sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,J2,id)
97 sage: f + g
98 Traceback (most recent call last):
99 ...
100 TypeError: unsupported operand parent(s) for +: ...
101
102 """
103 return FiniteDimensionalEuclideanJordanAlgebraOperator(
104 self.domain(),
105 self.codomain(),
106 self.matrix() + other.matrix())
107
108
109 def _composition_(self, other, homset):
110 """
111 Compose two EJA operators to get another one (and NOT a formal
112 composite object) back.
113
114 SETUP::
115
116 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
117 sage: from mjo.eja.eja_algebra import (
118 ....: JordanSpinEJA,
119 ....: RealCartesianProductEJA,
120 ....: RealSymmetricEJA)
121
122 EXAMPLES::
123
124 sage: J1 = JordanSpinEJA(3)
125 sage: J2 = RealCartesianProductEJA(2)
126 sage: J3 = RealSymmetricEJA(1)
127 sage: mat1 = matrix(QQ, [[1,2,3],
128 ....: [4,5,6]])
129 sage: mat2 = matrix(QQ, [[7,8]])
130 sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,
131 ....: J2,
132 ....: mat1)
133 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,
134 ....: J3,
135 ....: mat2)
136 sage: f*g
137 Linear operator between finite-dimensional Euclidean Jordan
138 algebras represented by the matrix:
139 [39 54 69]
140 Domain: Euclidean Jordan algebra of dimension 3 over
141 Rational Field
142 Codomain: Euclidean Jordan algebra of dimension 1 over
143 Rational Field
144
145 """
146 return FiniteDimensionalEuclideanJordanAlgebraOperator(
147 other.domain(),
148 self.codomain(),
149 self.matrix()*other.matrix())
150
151
152 def __eq__(self, other):
153 if self.domain() != other.domain():
154 return False
155 if self.codomain() != other.codomain():
156 return False
157 if self.matrix() != other.matrix():
158 return False
159 return True
160
161
162 def __invert__(self):
163 """
164 Invert this EJA operator.
165
166 SETUP::
167
168 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
169 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
170
171 EXAMPLES::
172
173 sage: J = RealSymmetricEJA(2)
174 sage: id = identity_matrix(J.base_ring(), J.dimension())
175 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
176 sage: ~f
177 Linear operator between finite-dimensional Euclidean Jordan
178 algebras represented by the matrix:
179 [1 0 0]
180 [0 1 0]
181 [0 0 1]
182 Domain: Euclidean Jordan algebra of dimension 3 over
183 Rational Field
184 Codomain: Euclidean Jordan algebra of dimension 3 over
185 Rational Field
186
187 """
188 return FiniteDimensionalEuclideanJordanAlgebraOperator(
189 self.codomain(),
190 self.domain(),
191 ~self.matrix())
192
193
194 def __mul__(self, other):
195 """
196 Compose two EJA operators, or scale myself by an element of the
197 ambient vector space.
198
199 We need to override the real ``__mul__`` function to prevent the
200 coercion framework from throwing an error when it fails to convert
201 a base ring element into a morphism.
202
203 SETUP::
204
205 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
206 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
207
208 EXAMPLES:
209
210 We can scale an operator on a rational algebra by a rational number::
211
212 sage: J = RealSymmetricEJA(2)
213 sage: e0,e1,e2 = J.gens()
214 sage: x = 2*e0 + 4*e1 + 16*e2
215 sage: x.operator()
216 Linear operator between finite-dimensional Euclidean Jordan algebras
217 represented by the matrix:
218 [ 2 4 0]
219 [ 2 9 2]
220 [ 0 4 16]
221 Domain: Euclidean Jordan algebra of dimension 3 over
222 Rational Field
223 Codomain: Euclidean Jordan algebra of dimension 3 over
224 Rational Field
225 sage: x.operator()*(1/2)
226 Linear operator between finite-dimensional Euclidean Jordan algebras
227 represented by the matrix:
228 [ 1 2 0]
229 [ 1 9/2 1]
230 [ 0 2 8]
231 Domain: Euclidean Jordan algebra of dimension 3 over
232 Rational Field
233 Codomain: Euclidean Jordan algebra of dimension 3 over
234 Rational Field
235
236 """
237 if other in self.codomain().base_ring():
238 return FiniteDimensionalEuclideanJordanAlgebraOperator(
239 self.domain(),
240 self.codomain(),
241 self.matrix()*other)
242
243 # This should eventually delegate to _composition_ after performing
244 # some sanity checks for us.
245 mor = super(FiniteDimensionalEuclideanJordanAlgebraOperator,self)
246 return mor.__mul__(other)
247
248
249 def _neg_(self):
250 """
251 Negate this EJA operator.
252
253 SETUP::
254
255 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
256 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
257
258 EXAMPLES::
259
260 sage: J = RealSymmetricEJA(2)
261 sage: id = identity_matrix(J.base_ring(), J.dimension())
262 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
263 sage: -f
264 Linear operator between finite-dimensional Euclidean Jordan
265 algebras represented by the matrix:
266 [-1 0 0]
267 [ 0 -1 0]
268 [ 0 0 -1]
269 Domain: Euclidean Jordan algebra of dimension 3 over
270 Rational Field
271 Codomain: Euclidean Jordan algebra of dimension 3 over
272 Rational Field
273
274 """
275 return FiniteDimensionalEuclideanJordanAlgebraOperator(
276 self.domain(),
277 self.codomain(),
278 -self.matrix())
279
280
281 def __pow__(self, n):
282 """
283 Raise this EJA operator to the power ``n``.
284
285 SETUP::
286
287 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
288 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
289
290 TESTS:
291
292 Ensure that we get back another EJA operator that can be added,
293 subtracted, et cetera::
294
295 sage: J = RealSymmetricEJA(2)
296 sage: id = identity_matrix(J.base_ring(), J.dimension())
297 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
298 sage: f^0 + f^1 + f^2
299 Linear operator between finite-dimensional Euclidean Jordan
300 algebras represented by the matrix:
301 [3 0 0]
302 [0 3 0]
303 [0 0 3]
304 Domain: Euclidean Jordan algebra of dimension 3 over
305 Rational Field
306 Codomain: Euclidean Jordan algebra of dimension 3 over
307 Rational Field
308
309 """
310 if (n == 1):
311 return self
312 elif (n == 0):
313 # Raising a vector space morphism to the zero power gives
314 # you back a special IdentityMorphism that is useless to us.
315 rows = self.codomain().dimension()
316 cols = self.domain().dimension()
317 mat = matrix.identity(self.base_ring(), rows, cols)
318 else:
319 mat = self.matrix()**n
320
321 return FiniteDimensionalEuclideanJordanAlgebraOperator(
322 self.domain(),
323 self.codomain(),
324 mat)
325
326
327 def _repr_(self):
328 r"""
329
330 A text representation of this linear operator on a Euclidean
331 Jordan Algebra.
332
333 SETUP::
334
335 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
336 sage: from mjo.eja.eja_algebra import JordanSpinEJA
337
338 EXAMPLES::
339
340 sage: J = JordanSpinEJA(2)
341 sage: id = identity_matrix(J.base_ring(), J.dimension())
342 sage: FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
343 Linear operator between finite-dimensional Euclidean Jordan
344 algebras represented by the matrix:
345 [1 0]
346 [0 1]
347 Domain: Euclidean Jordan algebra of dimension 2 over
348 Rational Field
349 Codomain: Euclidean Jordan algebra of dimension 2 over
350 Rational Field
351
352 """
353 msg = ("Linear operator between finite-dimensional Euclidean Jordan "
354 "algebras represented by the matrix:\n",
355 "{!r}\n",
356 "Domain: {}\n",
357 "Codomain: {}")
358 return ''.join(msg).format(self.matrix(),
359 self.domain(),
360 self.codomain())
361
362
363 def _sub_(self, other):
364 """
365 Subtract ``other`` from this EJA operator.
366
367 SETUP::
368
369 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
370 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
371
372 EXAMPLES::
373
374 sage: J = RealSymmetricEJA(2)
375 sage: id = identity_matrix(J.base_ring(),J.dimension())
376 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
377 sage: f - (f*2)
378 Linear operator between finite-dimensional Euclidean Jordan
379 algebras represented by the matrix:
380 [-1 0 0]
381 [ 0 -1 0]
382 [ 0 0 -1]
383 Domain: Euclidean Jordan algebra of dimension 3 over
384 Rational Field
385 Codomain: Euclidean Jordan algebra of dimension 3 over
386 Rational Field
387
388 """
389 return (self + (-other))
390
391
392 def matrix(self):
393 """
394 Return the matrix representation of this operator with respect
395 to the default bases of its (co)domain.
396
397 SETUP::
398
399 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
400 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
401
402 EXAMPLES::
403
404 sage: J = RealSymmetricEJA(2)
405 sage: mat = matrix(J.base_ring(), J.dimension(), range(9))
406 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,mat)
407 sage: f.matrix()
408 [0 1 2]
409 [3 4 5]
410 [6 7 8]
411
412 """
413 return self._matrix
414
415
416 def minimal_polynomial(self):
417 """
418 Return the minimal polynomial of this linear operator,
419 in the variable ``t``.
420
421 SETUP::
422
423 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
424 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
425
426 EXAMPLES::
427
428 sage: J = RealSymmetricEJA(3)
429 sage: J.one().operator().minimal_polynomial()
430 t - 1
431
432 """
433 # The matrix method returns a polynomial in 'x' but want one in 't'.
434 return self.matrix().minimal_polynomial().change_variable_name('t')