]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/eja/eja_operator.py
eja: separate out the operator class and rename both files.
[sage.d.git] / mjo / eja / eja_operator.py
1 from sage.all 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(range(len(J.gens())), 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()(self.matrix()*x.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 degree 3 over Rational Field
85 Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
86
87 If you try to add two identical vector space operators but on
88 different EJAs, that should blow up::
89
90 sage: J1 = RealSymmetricEJA(2)
91 sage: J2 = JordanSpinEJA(3)
92 sage: id = identity_matrix(QQ, 3)
93 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,J1,id)
94 sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,J2,id)
95 sage: f + g
96 Traceback (most recent call last):
97 ...
98 TypeError: unsupported operand parent(s) for +: ...
99
100 """
101 return FiniteDimensionalEuclideanJordanAlgebraOperator(
102 self.domain(),
103 self.codomain(),
104 self.matrix() + other.matrix())
105
106
107 def _composition_(self, other, homset):
108 """
109 Compose two EJA operators to get another one (and NOT a formal
110 composite object) back.
111
112 SETUP::
113
114 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
115 sage: from mjo.eja.eja_algebra import (
116 ....: JordanSpinEJA,
117 ....: RealCartesianProductEJA,
118 ....: RealSymmetricEJA)
119
120 EXAMPLES::
121
122 sage: J1 = JordanSpinEJA(3)
123 sage: J2 = RealCartesianProductEJA(2)
124 sage: J3 = RealSymmetricEJA(1)
125 sage: mat1 = matrix(QQ, [[1,2,3],
126 ....: [4,5,6]])
127 sage: mat2 = matrix(QQ, [[7,8]])
128 sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,
129 ....: J2,
130 ....: mat1)
131 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,
132 ....: J3,
133 ....: mat2)
134 sage: f*g
135 Linear operator between finite-dimensional Euclidean Jordan
136 algebras represented by the matrix:
137 [39 54 69]
138 Domain: Euclidean Jordan algebra of degree 3 over Rational Field
139 Codomain: Euclidean Jordan algebra of degree 1 over Rational Field
140
141 """
142 return FiniteDimensionalEuclideanJordanAlgebraOperator(
143 other.domain(),
144 self.codomain(),
145 self.matrix()*other.matrix())
146
147
148 def __eq__(self, other):
149 if self.domain() != other.domain():
150 return False
151 if self.codomain() != other.codomain():
152 return False
153 if self.matrix() != other.matrix():
154 return False
155 return True
156
157
158 def __invert__(self):
159 """
160 Invert this EJA operator.
161
162 SETUP::
163
164 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
165 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
166
167 EXAMPLES::
168
169 sage: J = RealSymmetricEJA(2)
170 sage: id = identity_matrix(J.base_ring(), J.dimension())
171 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
172 sage: ~f
173 Linear operator between finite-dimensional Euclidean Jordan
174 algebras represented by the matrix:
175 [1 0 0]
176 [0 1 0]
177 [0 0 1]
178 Domain: Euclidean Jordan algebra of degree 3 over Rational Field
179 Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
180
181 """
182 return FiniteDimensionalEuclideanJordanAlgebraOperator(
183 self.codomain(),
184 self.domain(),
185 ~self.matrix())
186
187
188 def __mul__(self, other):
189 """
190 Compose two EJA operators, or scale myself by an element of the
191 ambient vector space.
192
193 We need to override the real ``__mul__`` function to prevent the
194 coercion framework from throwing an error when it fails to convert
195 a base ring element into a morphism.
196
197 SETUP::
198
199 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
200 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
201
202 EXAMPLES:
203
204 We can scale an operator on a rational algebra by a rational number::
205
206 sage: J = RealSymmetricEJA(2)
207 sage: e0,e1,e2 = J.gens()
208 sage: x = 2*e0 + 4*e1 + 16*e2
209 sage: x.operator()
210 Linear operator between finite-dimensional Euclidean Jordan algebras
211 represented by the matrix:
212 [ 2 4 0]
213 [ 2 9 2]
214 [ 0 4 16]
215 Domain: Euclidean Jordan algebra of degree 3 over Rational Field
216 Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
217 sage: x.operator()*(1/2)
218 Linear operator between finite-dimensional Euclidean Jordan algebras
219 represented by the matrix:
220 [ 1 2 0]
221 [ 1 9/2 1]
222 [ 0 2 8]
223 Domain: Euclidean Jordan algebra of degree 3 over Rational Field
224 Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
225
226 """
227 if other in self.codomain().base_ring():
228 return FiniteDimensionalEuclideanJordanAlgebraOperator(
229 self.domain(),
230 self.codomain(),
231 self.matrix()*other)
232
233 # This should eventually delegate to _composition_ after performing
234 # some sanity checks for us.
235 mor = super(FiniteDimensionalEuclideanJordanAlgebraOperator,self)
236 return mor.__mul__(other)
237
238
239 def _neg_(self):
240 """
241 Negate this EJA operator.
242
243 SETUP::
244
245 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
246 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
247
248 EXAMPLES::
249
250 sage: J = RealSymmetricEJA(2)
251 sage: id = identity_matrix(J.base_ring(), J.dimension())
252 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
253 sage: -f
254 Linear operator between finite-dimensional Euclidean Jordan
255 algebras represented by the matrix:
256 [-1 0 0]
257 [ 0 -1 0]
258 [ 0 0 -1]
259 Domain: Euclidean Jordan algebra of degree 3 over Rational Field
260 Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
261
262 """
263 return FiniteDimensionalEuclideanJordanAlgebraOperator(
264 self.domain(),
265 self.codomain(),
266 -self.matrix())
267
268
269 def __pow__(self, n):
270 """
271 Raise this EJA operator to the power ``n``.
272
273 SETUP::
274
275 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
276 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
277
278 TESTS:
279
280 Ensure that we get back another EJA operator that can be added,
281 subtracted, et cetera::
282
283 sage: J = RealSymmetricEJA(2)
284 sage: id = identity_matrix(J.base_ring(), J.dimension())
285 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
286 sage: f^0 + f^1 + f^2
287 Linear operator between finite-dimensional Euclidean Jordan
288 algebras represented by the matrix:
289 [3 0 0]
290 [0 3 0]
291 [0 0 3]
292 Domain: Euclidean Jordan algebra of degree 3 over Rational Field
293 Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
294
295 """
296 if (n == 1):
297 return self
298 elif (n == 0):
299 # Raising a vector space morphism to the zero power gives
300 # you back a special IdentityMorphism that is useless to us.
301 rows = self.codomain().dimension()
302 cols = self.domain().dimension()
303 mat = matrix.identity(self.base_ring(), rows, cols)
304 else:
305 mat = self.matrix()**n
306
307 return FiniteDimensionalEuclideanJordanAlgebraOperator(
308 self.domain(),
309 self.codomain(),
310 mat)
311
312
313 def _repr_(self):
314 r"""
315
316 A text representation of this linear operator on a Euclidean
317 Jordan Algebra.
318
319 SETUP::
320
321 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
322 sage: from mjo.eja.eja_algebra import JordanSpinEJA
323
324 EXAMPLES::
325
326 sage: J = JordanSpinEJA(2)
327 sage: id = identity_matrix(J.base_ring(), J.dimension())
328 sage: FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
329 Linear operator between finite-dimensional Euclidean Jordan
330 algebras represented by the matrix:
331 [1 0]
332 [0 1]
333 Domain: Euclidean Jordan algebra of degree 2 over Rational Field
334 Codomain: Euclidean Jordan algebra of degree 2 over Rational Field
335
336 """
337 msg = ("Linear operator between finite-dimensional Euclidean Jordan "
338 "algebras represented by the matrix:\n",
339 "{!r}\n",
340 "Domain: {}\n",
341 "Codomain: {}")
342 return ''.join(msg).format(self.matrix(),
343 self.domain(),
344 self.codomain())
345
346
347 def _sub_(self, other):
348 """
349 Subtract ``other`` from this EJA operator.
350
351 SETUP::
352
353 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
354 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
355
356 EXAMPLES::
357
358 sage: J = RealSymmetricEJA(2)
359 sage: id = identity_matrix(J.base_ring(),J.dimension())
360 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
361 sage: f - (f*2)
362 Linear operator between finite-dimensional Euclidean Jordan
363 algebras represented by the matrix:
364 [-1 0 0]
365 [ 0 -1 0]
366 [ 0 0 -1]
367 Domain: Euclidean Jordan algebra of degree 3 over Rational Field
368 Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
369
370 """
371 return (self + (-other))
372
373
374 def matrix(self):
375 """
376 Return the matrix representation of this operator with respect
377 to the default bases of its (co)domain.
378
379 SETUP::
380
381 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
382 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
383
384 EXAMPLES::
385
386 sage: J = RealSymmetricEJA(2)
387 sage: mat = matrix(J.base_ring(), J.dimension(), range(9))
388 sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,mat)
389 sage: f.matrix()
390 [0 1 2]
391 [3 4 5]
392 [6 7 8]
393
394 """
395 return self._matrix
396
397
398 def minimal_polynomial(self):
399 """
400 Return the minimal polynomial of this linear operator,
401 in the variable ``t``.
402
403 SETUP::
404
405 sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
406 sage: from mjo.eja.eja_algebra import RealSymmetricEJA
407
408 EXAMPLES::
409
410 sage: J = RealSymmetricEJA(3)
411 sage: J.one().operator().minimal_polynomial()
412 t - 1
413
414 """
415 # The matrix method returns a polynomial in 'x' but want one in 't'.
416 return self.matrix().minimal_polynomial().change_variable_name('t')