]> gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/hurwitz.py
6767fe12fcd2d433c3b3a12324d6aab302d1b57b
[sage.d.git] / mjo / hurwitz.py
1 from sage.misc.cachefunc import cached_method
2 from sage.combinat.free_module import CombinatorialFreeModule
3 from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement
4 from sage.rings.all import AA
5
6 from mjo.matrix_algebra import MatrixAlgebra, MatrixAlgebraElement
7
8 class Octonion(IndexedFreeModuleElement):
9 def conjugate(self):
10 r"""
11 SETUP::
12
13 sage: from mjo.hurwitz import Octonions
14
15 EXAMPLES::
16
17 sage: O = Octonions()
18 sage: x = sum(O.gens())
19 sage: x.conjugate()
20 e0 - e1 - e2 - e3 - e4 - e5 - e6 - e7
21
22 TESTS::
23
24 Conjugating twice gets you the original element::
25
26 sage: O = Octonions()
27 sage: x = O.random_element()
28 sage: x.conjugate().conjugate() == x
29 True
30
31 """
32 from sage.rings.all import ZZ
33 from sage.matrix.matrix_space import MatrixSpace
34 C = MatrixSpace(ZZ,8).diagonal_matrix((1,-1,-1,-1,-1,-1,-1,-1))
35 return self.parent().from_vector(C*self.to_vector())
36
37 def real(self):
38 r"""
39 Return the real part of this octonion.
40
41 The real part of an octonion is its projection onto the span
42 of the first generator. In other words, the "first dimension"
43 is real and the others are imaginary.
44
45 SETUP::
46
47 sage: from mjo.hurwitz import Octonions
48
49 EXAMPLES::
50
51 sage: O = Octonions()
52 sage: x = sum(O.gens())
53 sage: x.real()
54 e0
55
56 TESTS:
57
58 This method is idempotent::
59
60 sage: O = Octonions()
61 sage: x = O.random_element()
62 sage: x.real().real() == x.real()
63 True
64
65 """
66 return (self + self.conjugate())/2
67
68 def imag(self):
69 r"""
70 Return the imaginary part of this octonion.
71
72 The imaginary part of an octonion is its projection onto the
73 orthogonal complement of the span of the first generator. In
74 other words, the "first dimension" is real and the others are
75 imaginary.
76
77 SETUP::
78
79 sage: from mjo.hurwitz import Octonions
80
81 EXAMPLES::
82
83 sage: O = Octonions()
84 sage: x = sum(O.gens())
85 sage: x.imag()
86 e1 + e2 + e3 + e4 + e5 + e6 + e7
87
88 TESTS:
89
90 This method is idempotent::
91
92 sage: O = Octonions()
93 sage: x = O.random_element()
94 sage: x.imag().imag() == x.imag()
95 True
96
97 """
98 return (self - self.conjugate())/2
99
100 def _norm_squared(self):
101 return (self*self.conjugate()).coefficient(0)
102
103 def norm(self):
104 r"""
105 Return the norm of this octonion.
106
107 SETUP::
108
109 sage: from mjo.hurwitz import Octonions
110
111 EXAMPLES::
112
113 sage: O = Octonions()
114 sage: O.one().norm()
115 1
116
117 TESTS:
118
119 The norm is nonnegative and belongs to the base field::
120
121 sage: O = Octonions()
122 sage: n = O.random_element().norm()
123 sage: n >= 0 and n in O.base_ring()
124 True
125
126 The norm is homogeneous::
127
128 sage: O = Octonions()
129 sage: x = O.random_element()
130 sage: alpha = O.base_ring().random_element()
131 sage: (alpha*x).norm() == alpha.abs()*x.norm()
132 True
133
134 """
135 return self._norm_squared().sqrt()
136
137 # The absolute value notation is typically used for complex numbers...
138 # and norm() isn't supported in AA, so this lets us use abs() in all
139 # of the division algebras we need.
140 abs = norm
141
142 def inverse(self):
143 r"""
144 Return the inverse of this element if it exists.
145
146 SETUP::
147
148 sage: from mjo.hurwitz import Octonions
149
150 EXAMPLES::
151
152 sage: O = Octonions()
153 sage: x = sum(O.gens())
154 sage: x*x.inverse() == O.one()
155 True
156
157 ::
158
159 sage: O = Octonions()
160 sage: O.one().inverse() == O.one()
161 True
162
163 TESTS::
164
165 sage: O = Octonions()
166 sage: x = O.random_element()
167 sage: x.is_zero() or ( x*x.inverse() == O.one() )
168 True
169
170 """
171 if self.is_zero():
172 raise ValueError("zero is not invertible")
173 return self.conjugate()/self._norm_squared()
174
175
176
177 class Octonions(CombinatorialFreeModule):
178 r"""
179 SETUP::
180
181 sage: from mjo.hurwitz import Octonions
182
183 EXAMPLES::
184
185 sage: Octonions()
186 Octonion algebra with base ring Algebraic Real Field
187 sage: Octonions(field=QQ)
188 Octonion algebra with base ring Rational Field
189
190 """
191 def __init__(self,
192 field=AA,
193 prefix="e"):
194
195 # Not associative, not commutative
196 from sage.categories.magmatic_algebras import MagmaticAlgebras
197 category = MagmaticAlgebras(field).FiniteDimensional()
198 category = category.WithBasis().Unital()
199
200 super().__init__(field,
201 range(8),
202 element_class=Octonion,
203 category=category,
204 prefix=prefix,
205 bracket=False)
206
207 # The product of each basis element is plus/minus another
208 # basis element that can simply be looked up on
209 # https://en.wikipedia.org/wiki/Octonion
210 e0, e1, e2, e3, e4, e5, e6, e7 = self.gens()
211 self._multiplication_table = (
212 (e0, e1, e2, e3, e4, e5, e6, e7),
213 (e1,-e0, e3,-e2, e5,-e4,-e7, e6),
214 (e2,-e3,-e0, e1, e6, e7,-e4,-e5),
215 (e3, e2,-e1,-e0, e7,-e6, e5,-e4),
216 (e4,-e5,-e6,-e7,-e0, e1, e2, e3),
217 (e5, e4,-e7, e6,-e1,-e0,-e3, e2),
218 (e6, e7, e4,-e5,-e2, e3,-e0,-e1),
219 (e7,-e6, e5, e4,-e3,-e2, e1,-e0),
220 )
221
222 def product_on_basis(self, i, j):
223 return self._multiplication_table[i][j]
224
225 def one_basis(self):
226 r"""
227 Return the monomial index (basis element) corresponding to the
228 octonion unit element.
229
230 SETUP::
231
232 sage: from mjo.hurwitz import Octonions
233
234 TESTS:
235
236 This gives the correct unit element::
237
238 sage: O = Octonions()
239 sage: x = O.random_element()
240 sage: x*O.one() == x and O.one()*x == x
241 True
242
243 """
244 return 0
245
246 def _repr_(self):
247 return ("Octonion algebra with base ring %s" % self.base_ring())
248
249 def multiplication_table(self):
250 """
251 Return a visual representation of this algebra's multiplication
252 table (on basis elements).
253
254 SETUP::
255
256 sage: from mjo.hurwitz import Octonions
257
258 EXAMPLES:
259
260 The multiplication table is what Wikipedia says it is::
261
262 sage: Octonions().multiplication_table()
263 +----++----+-----+-----+-----+-----+-----+-----+-----+
264 | * || e0 | e1 | e2 | e3 | e4 | e5 | e6 | e7 |
265 +====++====+=====+=====+=====+=====+=====+=====+=====+
266 | e0 || e0 | e1 | e2 | e3 | e4 | e5 | e6 | e7 |
267 +----++----+-----+-----+-----+-----+-----+-----+-----+
268 | e1 || e1 | -e0 | e3 | -e2 | e5 | -e4 | -e7 | e6 |
269 +----++----+-----+-----+-----+-----+-----+-----+-----+
270 | e2 || e2 | -e3 | -e0 | e1 | e6 | e7 | -e4 | -e5 |
271 +----++----+-----+-----+-----+-----+-----+-----+-----+
272 | e3 || e3 | e2 | -e1 | -e0 | e7 | -e6 | e5 | -e4 |
273 +----++----+-----+-----+-----+-----+-----+-----+-----+
274 | e4 || e4 | -e5 | -e6 | -e7 | -e0 | e1 | e2 | e3 |
275 +----++----+-----+-----+-----+-----+-----+-----+-----+
276 | e5 || e5 | e4 | -e7 | e6 | -e1 | -e0 | -e3 | e2 |
277 +----++----+-----+-----+-----+-----+-----+-----+-----+
278 | e6 || e6 | e7 | e4 | -e5 | -e2 | e3 | -e0 | -e1 |
279 +----++----+-----+-----+-----+-----+-----+-----+-----+
280 | e7 || e7 | -e6 | e5 | e4 | -e3 | -e2 | e1 | -e0 |
281 +----++----+-----+-----+-----+-----+-----+-----+-----+
282
283 """
284 n = self.dimension()
285 # Prepend the header row.
286 M = [["*"] + list(self.gens())]
287
288 # And to each subsequent row, prepend an entry that belongs to
289 # the left-side "header column."
290 M += [ [self.monomial(i)] + [ self.monomial(i)*self.monomial(j)
291 for j in range(n) ]
292 for i in range(n) ]
293
294 from sage.misc.table import table
295 return table(M, header_row=True, header_column=True, frame=True)
296
297
298
299
300
301 class HurwitzMatrixAlgebraElement(MatrixAlgebraElement):
302 def conjugate(self):
303 r"""
304 Return the entrywise conjugate of this matrix.
305
306 SETUP::
307
308 sage: from mjo.hurwitz import ComplexMatrixAlgebra
309
310 EXAMPLES::
311
312 sage: A = ComplexMatrixAlgebra(2, QQbar, ZZ)
313 sage: M = A([ [ I, 1 + 2*I],
314 ....: [ 3*I, 4*I] ])
315 sage: M.conjugate()
316 +------+----------+
317 | -I | -2*I + 1 |
318 +------+----------+
319 | -3*I | -4*I |
320 +------+----------+
321
322 """
323 entries = [ [ self[i,j].conjugate()
324 for j in range(self.ncols())]
325 for i in range(self.nrows()) ]
326 return self.parent()._element_constructor_(entries)
327
328 def conjugate_transpose(self):
329 r"""
330 Return the conjugate-transpose of this matrix.
331
332 SETUP::
333
334 sage: from mjo.hurwitz import ComplexMatrixAlgebra
335
336 EXAMPLES::
337
338 sage: A = ComplexMatrixAlgebra(2, QQbar, ZZ)
339 sage: M = A([ [ I, 2*I],
340 ....: [ 3*I, 4*I] ])
341 sage: M.conjugate_transpose()
342 +------+------+
343 | -I | -3*I |
344 +------+------+
345 | -2*I | -4*I |
346 +------+------+
347 sage: M.conjugate_transpose().to_vector()
348 (0, -1, 0, -3, 0, -2, 0, -4)
349
350 """
351 entries = [ [ self[j,i].conjugate()
352 for j in range(self.ncols())]
353 for i in range(self.nrows()) ]
354 return self.parent()._element_constructor_(entries)
355
356 def is_hermitian(self):
357 r"""
358
359 SETUP::
360
361 sage: from mjo.hurwitz import (ComplexMatrixAlgebra,
362 ....: HurwitzMatrixAlgebra)
363
364 EXAMPLES::
365
366 sage: A = ComplexMatrixAlgebra(2, QQbar, ZZ)
367 sage: M = A([ [ 0,I],
368 ....: [-I,0] ])
369 sage: M.is_hermitian()
370 True
371
372 ::
373
374 sage: A = HurwitzMatrixAlgebra(2, AA, QQ)
375 sage: M = A([ [1, 1],
376 ....: [1, 1] ])
377 sage: M.is_hermitian()
378 True
379
380 """
381 # A tiny bit faster than checking equality with the conjugate
382 # transpose.
383 return all( self[i,j] == self[j,i].conjugate()
384 for i in range(self.nrows())
385 for j in range(self.ncols()) )
386
387
388 def is_skew_symmetric(self):
389 r"""
390 Return whether or not this matrix is skew-symmetric.
391
392 SETUP::
393
394 sage: from mjo.hurwitz import (ComplexMatrixAlgebra,
395 ....: HurwitzMatrixAlgebra)
396
397 EXAMPLES::
398
399 sage: A = ComplexMatrixAlgebra(2, QQbar, ZZ)
400 sage: M = A([ [ 0,I],
401 ....: [-I,1] ])
402 sage: M.is_skew_symmetric()
403 False
404
405 ::
406
407 sage: A = ComplexMatrixAlgebra(2, QQbar, ZZ)
408 sage: M = A([ [ 0, 1+I],
409 ....: [-1-I, 0] ])
410 sage: M.is_skew_symmetric()
411 True
412
413 ::
414
415 sage: A = HurwitzMatrixAlgebra(2, AA, QQ)
416 sage: M = A([ [1, 1],
417 ....: [1, 1] ])
418 sage: M.is_skew_symmetric()
419 False
420
421 ::
422
423 sage: A = ComplexMatrixAlgebra(2, QQbar, ZZ)
424 sage: M = A([ [2*I , 1 + I],
425 ....: [-1 + I, -2*I] ])
426 sage: M.is_skew_symmetric()
427 False
428
429 """
430 # A tiny bit faster than checking equality with the negation
431 # of the transpose.
432 return all( self[i,j] == -self[j,i]
433 for i in range(self.nrows())
434 for j in range(self.ncols()) )
435
436
437 class HurwitzMatrixAlgebra(MatrixAlgebra):
438 r"""
439 A class of matrix algebras whose entries come from a Hurwitz
440 algebra.
441
442 For our purposes, we consider "a Hurwitz" algebra to be the real
443 or complex numbers, the quaternions, or the octonions. These are
444 typically also referred to as the Euclidean Hurwitz algebras, or
445 the normed division algebras.
446
447 By the Cayley-Dickson construction, each Hurwitz algebra is an
448 algebra over the real numbers, so we restrict the scalar field in
449 this case to be real. This also allows us to more accurately
450 produce the generators of the matrix algebra.
451 """
452 Element = HurwitzMatrixAlgebraElement
453
454 def __init__(self, n, entry_algebra, scalars, **kwargs):
455 from sage.rings.all import RR
456 if not scalars.is_subring(RR):
457 # Not perfect, but it's what we're using.
458 raise ValueError("scalar field is not real")
459
460 super().__init__(n, entry_algebra, scalars, **kwargs)
461
462 def entry_algebra_gens(self):
463 r"""
464 Return a tuple of the generators of (that is, a basis for) the
465 entries of this matrix algebra.
466
467 This works around the inconsistency in the ``gens()`` methods
468 of the real/complex numbers, quaternions, and octonions.
469
470 SETUP::
471
472 sage: from mjo.hurwitz import Octonions, HurwitzMatrixAlgebra
473
474 EXAMPLES:
475
476 The inclusion of the unit element is inconsistent across
477 (subalgebras of) Hurwitz algebras::
478
479 sage: AA.gens()
480 (1,)
481 sage: QQbar.gens()
482 (I,)
483 sage: QuaternionAlgebra(AA,1,-1).gens()
484 [i, j, k]
485 sage: Octonions().gens()
486 (e0, e1, e2, e3, e4, e5, e6, e7)
487
488 The unit element is always returned by this method, so the
489 sets of generators have cartinality 1,2,4, and 8 as you'd
490 expect::
491
492 sage: HurwitzMatrixAlgebra(2, AA, AA).entry_algebra_gens()
493 (1,)
494 sage: HurwitzMatrixAlgebra(2, QQbar, AA).entry_algebra_gens()
495 (1, I)
496 sage: Q = QuaternionAlgebra(AA,-1,-1)
497 sage: HurwitzMatrixAlgebra(2, Q, AA).entry_algebra_gens()
498 (1, i, j, k)
499 sage: O = Octonions()
500 sage: HurwitzMatrixAlgebra(2, O, AA).entry_algebra_gens()
501 (e0, e1, e2, e3, e4, e5, e6, e7)
502
503 """
504 gs = self.entry_algebra().gens()
505 one = self.entry_algebra().one()
506 if one in gs:
507 return gs
508 else:
509 return (one,) + tuple(gs)
510
511
512
513 class OctonionMatrixAlgebra(HurwitzMatrixAlgebra):
514 r"""
515 The algebra of ``n``-by-``n`` matrices with octonion entries over
516 (a subfield of) the real numbers.
517
518 The usual matrix spaces in SageMath don't support octonion entries
519 because they assume that the entries of the matrix come from a
520 commutative and associative ring, and the octonions are neither.
521
522 SETUP::
523
524 sage: from mjo.hurwitz import Octonions, OctonionMatrixAlgebra
525
526 EXAMPLES::
527
528 sage: OctonionMatrixAlgebra(3)
529 Module of 3 by 3 matrices with entries in Octonion algebra with base
530 ring Algebraic Real Field over the scalar ring Algebraic Real Field
531
532 ::
533
534 sage: OctonionMatrixAlgebra(3,scalars=QQ)
535 Module of 3 by 3 matrices with entries in Octonion algebra with
536 base ring Rational Field over the scalar ring Rational Field
537
538 ::
539
540 sage: O = Octonions(RR)
541 sage: A = OctonionMatrixAlgebra(1,O)
542 sage: A
543 Module of 1 by 1 matrices with entries in Octonion algebra with
544 base ring Real Field with 53 bits of precision over the scalar
545 ring Algebraic Real Field
546 sage: A.one()
547 +---------------------+
548 | 1.00000000000000*e0 |
549 +---------------------+
550 sage: A.gens()
551 (+---------------------+
552 | 1.00000000000000*e0 |
553 +---------------------+,
554 +---------------------+
555 | 1.00000000000000*e1 |
556 +---------------------+,
557 +---------------------+
558 | 1.00000000000000*e2 |
559 +---------------------+,
560 +---------------------+
561 | 1.00000000000000*e3 |
562 +---------------------+,
563 +---------------------+
564 | 1.00000000000000*e4 |
565 +---------------------+,
566 +---------------------+
567 | 1.00000000000000*e5 |
568 +---------------------+,
569 +---------------------+
570 | 1.00000000000000*e6 |
571 +---------------------+,
572 +---------------------+
573 | 1.00000000000000*e7 |
574 +---------------------+)
575
576 ::
577
578 sage: A = OctonionMatrixAlgebra(2)
579 sage: e0,e1,e2,e3,e4,e5,e6,e7 = A.entry_algebra().gens()
580 sage: A([ [e0+e4, e1+e5],
581 ....: [e2-e6, e3-e7] ])
582 +---------+---------+
583 | e0 + e4 | e1 + e5 |
584 +---------+---------+
585 | e2 - e6 | e3 - e7 |
586 +---------+---------+
587
588 ::
589
590 sage: A1 = OctonionMatrixAlgebra(1,scalars=QQ)
591 sage: A2 = OctonionMatrixAlgebra(1,scalars=QQ)
592 sage: cartesian_product([A1,A2])
593 Module of 1 by 1 matrices with entries in Octonion algebra with
594 base ring Rational Field over the scalar ring Rational Field (+)
595 Module of 1 by 1 matrices with entries in Octonion algebra with
596 base ring Rational Field over the scalar ring Rational Field
597
598 TESTS::
599
600 sage: A = OctonionMatrixAlgebra(ZZ.random_element(10))
601 sage: x = A.random_element()
602 sage: x*A.one() == x and A.one()*x == x
603 True
604
605 """
606 def __init__(self, n, entry_algebra=None, scalars=AA, **kwargs):
607 if entry_algebra is None:
608 entry_algebra = Octonions(field=scalars)
609 super().__init__(n,
610 entry_algebra,
611 scalars,
612 **kwargs)
613
614 class QuaternionMatrixAlgebra(HurwitzMatrixAlgebra):
615 r"""
616 The algebra of ``n``-by-``n`` matrices with quaternion entries over
617 (a subfield of) the real numbers.
618
619 The usual matrix spaces in SageMath don't support quaternion entries
620 because they assume that the entries of the matrix come from a
621 commutative ring, and the quaternions are not commutative.
622
623 SETUP::
624
625 sage: from mjo.hurwitz import QuaternionMatrixAlgebra
626
627 EXAMPLES::
628
629 sage: QuaternionMatrixAlgebra(3)
630 Module of 3 by 3 matrices with entries in Quaternion
631 Algebra (-1, -1) with base ring Algebraic Real Field
632 over the scalar ring Algebraic Real Field
633
634 ::
635
636 sage: QuaternionMatrixAlgebra(3,scalars=QQ)
637 Module of 3 by 3 matrices with entries in Quaternion
638 Algebra (-1, -1) with base ring Rational Field over
639 the scalar ring Rational Field
640
641 ::
642
643 sage: Q = QuaternionAlgebra(RDF, -1, -1)
644 sage: A = QuaternionMatrixAlgebra(1,Q)
645 sage: A
646 Module of 1 by 1 matrices with entries in Quaternion Algebra
647 (-1.0, -1.0) with base ring Real Double Field over the scalar
648 ring Algebraic Real Field
649 sage: A.one()
650 +-----+
651 | 1.0 |
652 +-----+
653 sage: A.gens()
654 (+-----+
655 | 1.0 |
656 +-----+,
657 +---+
658 | i |
659 +---+,
660 +---+
661 | j |
662 +---+,
663 +---+
664 | k |
665 +---+)
666
667 ::
668
669 sage: A = QuaternionMatrixAlgebra(2)
670 sage: i,j,k = A.entry_algebra().gens()
671 sage: A([ [1+i, j-2],
672 ....: [k, k+j] ])
673 +-------+--------+
674 | 1 + i | -2 + j |
675 +-------+--------+
676 | k | j + k |
677 +-------+--------+
678
679 ::
680
681 sage: A1 = QuaternionMatrixAlgebra(1,scalars=QQ)
682 sage: A2 = QuaternionMatrixAlgebra(2,scalars=QQ)
683 sage: cartesian_product([A1,A2])
684 Module of 1 by 1 matrices with entries in Quaternion Algebra
685 (-1, -1) with base ring Rational Field over the scalar ring
686 Rational Field (+) Module of 2 by 2 matrices with entries in
687 Quaternion Algebra (-1, -1) with base ring Rational Field over
688 the scalar ring Rational Field
689
690 TESTS::
691
692 sage: A = QuaternionMatrixAlgebra(ZZ.random_element(10))
693 sage: x = A.random_element()
694 sage: x*A.one() == x and A.one()*x == x
695 True
696
697 """
698 def __init__(self, n, entry_algebra=None, scalars=AA, **kwargs):
699 if entry_algebra is None:
700 # The -1,-1 gives us the "usual" definition of quaternion
701 from sage.algebras.quatalg.quaternion_algebra import (
702 QuaternionAlgebra
703 )
704 entry_algebra = QuaternionAlgebra(scalars,-1,-1)
705 super().__init__(n, entry_algebra, scalars, **kwargs)
706
707 def _entry_algebra_element_to_vector(self, entry):
708 r"""
709
710 SETUP::
711
712 sage: from mjo.hurwitz import QuaternionMatrixAlgebra
713
714 EXAMPLES::
715
716 sage: A = QuaternionMatrixAlgebra(2)
717 sage: u = A.entry_algebra().one()
718 sage: A._entry_algebra_element_to_vector(u)
719 (1, 0, 0, 0)
720 sage: i,j,k = A.entry_algebra().gens()
721 sage: A._entry_algebra_element_to_vector(i)
722 (0, 1, 0, 0)
723 sage: A._entry_algebra_element_to_vector(j)
724 (0, 0, 1, 0)
725 sage: A._entry_algebra_element_to_vector(k)
726 (0, 0, 0, 1)
727
728 """
729 from sage.modules.free_module import FreeModule
730 d = len(self.entry_algebra_gens())
731 V = FreeModule(self.entry_algebra().base_ring(), d)
732 return V(entry.coefficient_tuple())
733
734 class ComplexMatrixAlgebra(HurwitzMatrixAlgebra):
735 r"""
736 The algebra of ``n``-by-``n`` matrices with complex entries over
737 (a subfield of) the real numbers.
738
739 These differ from the usual complex matrix spaces in SageMath
740 because the scalar field is real (and not assumed to be the same
741 as the space from which the entries are drawn). The space of
742 `1`-by-`1` complex matrices will have dimension two, for example.
743
744 SETUP::
745
746 sage: from mjo.hurwitz import ComplexMatrixAlgebra
747
748 EXAMPLES::
749
750 sage: ComplexMatrixAlgebra(3)
751 Module of 3 by 3 matrices with entries in Algebraic Field
752 over the scalar ring Algebraic Real Field
753
754 ::
755
756 sage: ComplexMatrixAlgebra(3,scalars=QQ)
757 Module of 3 by 3 matrices with entries in Algebraic Field
758 over the scalar ring Rational Field
759
760 ::
761
762 sage: A = ComplexMatrixAlgebra(1,CC)
763 sage: A
764 Module of 1 by 1 matrices with entries in Complex Field with
765 53 bits of precision over the scalar ring Algebraic Real Field
766 sage: A.one()
767 +------------------+
768 | 1.00000000000000 |
769 +------------------+
770 sage: A.gens()
771 (+------------------+
772 | 1.00000000000000 |
773 +------------------+,
774 +--------------------+
775 | 1.00000000000000*I |
776 +--------------------+)
777
778 ::
779
780 sage: A = ComplexMatrixAlgebra(2)
781 sage: (I,) = A.entry_algebra().gens()
782 sage: A([ [1+I, 1],
783 ....: [-1, -I] ])
784 +---------+------+
785 | 1 + 1*I | 1 |
786 +---------+------+
787 | -1 | -1*I |
788 +---------+------+
789
790 ::
791
792 sage: A1 = ComplexMatrixAlgebra(1,scalars=QQ)
793 sage: A2 = ComplexMatrixAlgebra(2,scalars=QQ)
794 sage: cartesian_product([A1,A2])
795 Module of 1 by 1 matrices with entries in Algebraic Field over
796 the scalar ring Rational Field (+) Module of 2 by 2 matrices with
797 entries in Algebraic Field over the scalar ring Rational Field
798
799 TESTS::
800
801 sage: A = ComplexMatrixAlgebra(ZZ.random_element(10))
802 sage: x = A.random_element()
803 sage: x*A.one() == x and A.one()*x == x
804 True
805
806 """
807 def __init__(self, n, entry_algebra=None, scalars=AA, **kwargs):
808 if entry_algebra is None:
809 from sage.rings.all import QQbar
810 entry_algebra = QQbar
811 super().__init__(n, entry_algebra, scalars, **kwargs)
812
813 def _entry_algebra_element_to_vector(self, entry):
814 r"""
815
816 SETUP::
817
818 sage: from mjo.hurwitz import ComplexMatrixAlgebra
819
820 EXAMPLES::
821
822 sage: A = ComplexMatrixAlgebra(2, QQbar, QQ)
823 sage: A._entry_algebra_element_to_vector(QQbar(1))
824 (1, 0)
825 sage: A._entry_algebra_element_to_vector(QQbar(I))
826 (0, 1)
827
828 """
829 from sage.modules.free_module import FreeModule
830 d = len(self.entry_algebra_gens())
831 V = FreeModule(self.entry_algebra().base_ring(), d)
832 return V((entry.real(), entry.imag()))