for i in range(n) ]
return table(M, header_row=True, header_column=True, frame=True)
+
+
+class OctonionMatrix:
+ r"""
+ A pseudo-matrix class that supports octonion entries.
+
+ Matrices in SageMath can't have base rings that are
+ non-commutative, much less non-associative. The "matrix" scaling,
+ addition, and multiplication operations for this class are all
+ wholly inefficient, but are hand-written to guarantee that they
+ are performed in the correct order. Of course, it can't guarantee
+ that you won't write something visually ambiguous like
+ `A*B*C`... but you already have that problem with the
+ non-associative octonions themselves.
+
+ This class is only as sophisticated as it need to be to implement
+ the Jordan and inner-products in the space of Hermitian matrices
+ with octonion entries, namely ``(X*Y+Y*X)/2`` and
+ ``(X*Y).trace().real()`` for two octonion matrices ``X`` and
+ ``Y``.
+
+ .. WARNING:
+
+ These are not matrices in the usual sense! Matrix
+ multiplication is associative. Multiplication of octonion
+ "matrices" cannot be, since the multiplication of the
+ underlying octonions is not (consider two 1-by-1 matrices each
+ containing a single octonion).
+ """
+ def __init__(self, entries):
+ r"""
+ Initialize this matrix with a list of lists in (row,column) order,
+ just like in SageMath.
+ """
+ self._nrows = len(entries)
+
+ if self._nrows == 0:
+ self._ncols = 0
+ else:
+ # We don't check that you haven't supplied two rows (or
+ # columns) of different lengths!
+ self._ncols = len(entries[0])
+
+ self._entries = entries
+
+ def __getitem__(self, indices):
+ r"""
+ SETUP::
+
+ sage: from mjo.octonions import Octonions, OctonionMatrix
+
+ EXAMPLES::
+
+ sage: O = Octonions(field=QQ)
+ sage: M = OctonionMatrix([ [O.one(), O.zero()],
+ ....: [O.zero(), O.one() ] ])
+ sage: M[0,0]
+ e0
+ sage: M[0,1]
+ 0
+ sage: M[1,0]
+ 0
+ sage: M[1,1]
+ e0
+ """
+ i,j = indices
+ return self._entries[i][j]
+
+ def nrows(self):
+ r"""
+ SETUP::
+
+ sage: from mjo.octonions import Octonions, OctonionMatrix
+
+ EXAMPLES::
+
+ sage: O = Octonions(field=QQ)
+ sage: M = OctonionMatrix([ [O.one(), O.zero()],
+ ....: [O.zero(), O.one() ],
+ ....: [O.zero(), O.zero()] ])
+ sage: M.nrows()
+ 3
+
+ """
+ return self._nrows
+
+ def ncols(self):
+ r"""
+
+ SETUP::
+
+ sage: from mjo.octonions import Octonions, OctonionMatrix
+
+ EXAMPLES::
+
+ sage: O = Octonions(field=QQ)
+ sage: M = OctonionMatrix([ [O.one(), O.zero()],
+ ....: [O.zero(), O.one() ],
+ ....: [O.zero(), O.zero()] ])
+ sage: M.ncols()
+ 2
+
+ """
+ return self._ncols
+
+ def __repr__(self):
+ return table(self._entries, frame=True)._repr_()
+
+ def __mul__(self,rhs):
+ r"""
+
+ SETUP::
+
+ sage: from mjo.octonions import Octonions, OctonionMatrix
+
+ EXAMPLES::
+
+ sage: O = Octonions(QQ)
+ sage: e1 = O.monomial(1)
+ sage: e2 = O.monomial(2)
+ sage: e1*e2
+ e3
+ sage: e2*e1
+ -e3
+ sage: E1 = OctonionMatrix([[e1]])
+ sage: E2 = OctonionMatrix([[e2]])
+ sage: E1*E2
+ +----+
+ | e3 |
+ +----+
+ sage: E2*E1
+ +-----+
+ | -e3 |
+ +-----+
+
+ """
+ if not self.ncols() == rhs.nrows():
+ raise ValueError("dimension mismatch")
+
+ m = self.nrows()
+ n = self.ncols()
+ p = rhs.ncols()
+
+ C = lambda i,j: sum( self[i,k]*rhs[k,j] for k in range(n) )
+ return OctonionMatrix([ [C(i,j) for j in range(m)]
+ for i in range(p) ] )
+
+ def __rmul__(self,scalar):
+ r"""
+
+ SETUP::
+
+ sage: from mjo.octonions import Octonions, OctonionMatrix
+
+ EXAMPLES::
+
+ sage: O = Octonions(QQ)
+ sage: M = OctonionMatrix([[O.one(), O.zero()],
+ ....: [O.zero(),O.one() ] ])
+ sage: 2*M
+ +------+------+
+ | 2*e0 | 0 |
+ +------+------+
+ | 0 | 2*e0 |
+ +------+------+
+
+ r"""
+ # SCALAR GOES ON THE LEFT HERE
+ return OctonionMatrix([ [scalar*self[i,j]
+ for j in range(self.ncols())]
+ for i in range(self.nrows()) ])
+
+ def __add__(self,rhs):
+ r"""
+ SETUP::
+
+ sage: from mjo.octonions import Octonions, OctonionMatrix
+
+ EXAMPLES::
+
+ sage: O = Octonions(QQ)
+ sage: e0,e1,e2,e3,e4,e5,e6,e7 = O.gens()
+ sage: A = OctonionMatrix([ [e0,e1],
+ ....: [e2,e3] ])
+ sage: B = OctonionMatrix([ [e4,e5],
+ ....: [e6,e7] ])
+ sage: A+B
+ +---------+---------+
+ | e0 + e4 | e1 + e5 |
+ +---------+---------+
+ | e2 + e6 | e3 + e7 |
+ +---------+---------+
+
+ """
+ if not self.ncols() == rhs.ncols():
+ raise ValueError("column dimension mismatch")
+ if not self.nrows() == rhs.nrows():
+ raise ValueError("row dimension mismatch")
+ return OctonionMatrix([ [self[i,j] + rhs[i,j]
+ for j in range(self.ncols())]
+ for i in range(self.nrows()) ])