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