]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/octonions.py
octonions: alias abs() to norm().
[sage.d.git] / mjo / octonions.py
index c2b829f98b9b49dbe078172a3669f0cb8b6406e4..bd014c22eb4c180117cf70291e4f2357c091bd20 100644 (file)
@@ -7,6 +7,8 @@ from sage.rings.all import AA, ZZ
 from sage.matrix.matrix_space import MatrixSpace
 from sage.misc.table import table
 
+from mjo.matrix_algebra import MatrixAlgebra
+
 class Octonion(IndexedFreeModuleElement):
     def conjugate(self):
         r"""
@@ -139,6 +141,11 @@ class Octonion(IndexedFreeModuleElement):
         """
         return self._norm_squared().sqrt()
 
+    # The absolute value notation is typically used for complex numbers...
+    # and norm() isn't supported in AA, so this lets us use abs() in all
+    # of the division algebras we need.
+    abs = norm
+
     def inverse(self):
         r"""
         Return the inverse of this element if it exists.
@@ -339,171 +346,8 @@ class Octonions(CombinatorialFreeModule):
         return table(M, header_row=True, header_column=True, frame=True)
 
 
-class OctonionMatrix(IndexedFreeModuleElement):
-    def nrows(self):
-        return self.parent().nrows()
-    ncols = nrows
-
-    @cached_method
-    def to_nested_list(self):
-        r"""
-        SETUP::
-
-            sage: from mjo.octonions import OctonionMatrixAlgebra
-
-        EXAMPLES::
-
-            sage: MS = OctonionMatrixAlgebra(3)
-            sage: E00e0 = MS.gens()[0]
-            sage: E00e0
-            +----+---+---+
-            | e0 | 0 | 0 |
-            +----+---+---+
-            | 0  | 0 | 0 |
-            +----+---+---+
-            | 0  | 0 | 0 |
-            +----+---+---+
-            sage: E00e3 = MS.gens()[3]
-            sage: E00e3
-            +----+---+---+
-            | e3 | 0 | 0 |
-            +----+---+---+
-            | 0  | 0 | 0 |
-            +----+---+---+
-            | 0  | 0 | 0 |
-            +----+---+---+
-            sage: (E00e0 + 2*E00e3).to_nested_list()
-            [[e0 + 2*e3, 0, 0], [0, 0, 0], [0, 0, 0]]
-
-        """
-        zero = self.parent().octonions().zero()
-        l = [[zero for j in range(self.ncols())] for i in range(self.nrows())]
-        for (k,v) in self.monomial_coefficients().items():
-            (i,j,e) = k
-            l[i][j] += v*e
-        return l
-
-    def __repr__(self):
-        r"""
-        SETUP::
-
-            sage: from mjo.octonions import OctonionMatrixAlgebra
-
-        EXAMPLES::
-
-            sage: OctonionMatrixAlgebra(3).one()
-            +----+----+----+
-            | e0 | 0  | 0  |
-             +----+----+----+
-            | 0  | e0 | 0  |
-            +----+----+----+
-            | 0  | 0  | e0 |
-            +----+----+----+
-
-        """
-        return table(self.to_nested_list(), frame=True)._repr_()
-
-
-    def list(self):
-        r"""
-        Return one long list of this matrix's entries.
-
-        SETUP::
-
-            sage: from mjo.octonions import OctonionMatrixAlgebra
-
-        EXAMPLES::
-
-            sage: MS = OctonionMatrixAlgebra(3)
-            sage: E00e0 = MS.gens()[0]
-            sage: E00e3 = MS.gens()[3]
-            sage: (E00e0 + 2*E00e3).to_nested_list()
-            [[e0 + 2*e3, 0, 0], [0, 0, 0], [0, 0, 0]]
-            sage: (E00e0 + 2*E00e3).list()
-            [e0 + 2*e3, 0, 0, 0, 0, 0, 0, 0, 0]
-
-        """
-        return sum( self.to_nested_list(), [] )
-
-
-    def __getitem__(self, indices):
-        r"""
-
-        SETUP::
-
-            sage: from mjo.octonions import OctonionMatrixAlgebra
-
-        EXAMPLES::
-
-            sage: MS = OctonionMatrixAlgebra(2)
-            sage: I = MS.one()
-            sage: I[0,0]
-            e0
-            sage: I[0,1]
-            0
-            sage: I[1,0]
-            0
-            sage: I[1,1]
-            e0
-
-        """
-        i,j = indices
-        return self.to_nested_list()[i][j]
-
-    def trace(self):
-        r"""
-
-        SETUP::
-
-            sage: from mjo.octonions import OctonionMatrixAlgebra
-
-        EXAMPLES::
-
-            sage: MS = OctonionMatrixAlgebra(3)
-            sage: MS.one().trace()
-            3*e0
-
-        """
-        zero = self.parent().octonions().zero()
-        return sum( (self[i,i] for i in range(self.nrows())), zero )
-
-    def matrix_space(self):
-        r"""
-
-        SETUP::
 
-            sage: from mjo.octonions import OctonionMatrixAlgebra
-
-        TESTS::
-
-            sage: set_random_seed()
-            sage: MS = OctonionMatrixAlgebra(2)
-            sage: MS.random_element().matrix_space()
-            Module of 2 by 2 matrices with octonion entries over the
-            scalar ring Algebraic Real Field
-
-        """
-        return self.parent()
-
-    def is_hermitian(self):
-        r"""
-
-        SETUP::
-
-            sage: from mjo.octonions import OctonionMatrixAlgebra
-
-        EXAMPLES::
-
-            sage: MS = OctonionMatrixAlgebra(3)
-            sage: MS.one().is_hermitian()
-            True
-
-        """
-        return all( self[i,j] == self[j,i].conjugate()
-                    for i in range(self.nrows())
-                    for j in range(self.ncols()) )
-
-class OctonionMatrixAlgebra(CombinatorialFreeModule):
+class OctonionMatrixAlgebra(MatrixAlgebra):
     r"""
     The algebra of ``n``-by-``n`` matrices with octonion entries over
     (a subfield of) the real numbers.
@@ -511,116 +355,45 @@ class OctonionMatrixAlgebra(CombinatorialFreeModule):
     The usual matrix spaces in SageMath don't support octonion entries
     because they assume that the entries of the matrix come from a
     commutative and associative ring (i.e. very NOT the octonions).
-    """
-    Element = OctonionMatrix
 
-    def __init__(self, n, field=AA, prefix="E", **kwargs):
-        # Not associative, not commutative
-        category = MagmaticAlgebras(field).FiniteDimensional()
-        category = category.WithBasis().Unital()
+    SETUP::
 
-        self._nrows = n
+        sage: from mjo.octonions import Octonions, OctonionMatrixAlgebra
 
-        # Since the scalar field is real but the entries are octonion,
-        # sticking a "1" in each position doesn't give us a basis for
-        # the space. We actually need to stick each of e0, e1, ..., e7
-        # (a basis for the Octonions themselves) into each position.
-        from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
-        from sage.categories.sets_cat import cartesian_product
+    EXAMPLES::
 
-        I = FiniteEnumeratedSet(range(n))
-        J = FiniteEnumeratedSet(range(n))
-        self._octonions = Octonions(field=field)
-        entry_basis = self._octonions.gens()
+        sage: OctonionMatrixAlgebra(3)
+        Module of 3 by 3 matrices with entries in Octonion algebra with base
+        ring Algebraic Real Field over the scalar ring Algebraic Real Field
+        sage: OctonionMatrixAlgebra(3,QQ)
+        Module of 3 by 3 matrices with entries in Octonion algebra with base
+        ring Rational Field over the scalar ring Rational Field
+
+    ::
+
+        sage: O = Octonions(QQ)
+        sage: e0,e1,e2,e3,e4,e5,e6,e7 = O.gens()
+        sage: MS = OctonionMatrixAlgebra(2)
+        sage: MS.from_list([ [e0+e4, e1+e5],
+        ....:                [e2-e6, e3-e7] ])
+        +---------+---------+
+        | e0 + e4 | e1 + e5 |
+        +---------+---------+
+        | e2 - e6 | e3 - e7 |
+        +---------+---------+
+
+    TESTS::
+
+        sage: set_random_seed()
+        sage: MS = OctonionMatrixAlgebra(ZZ.random_element(10))
+        sage: x = MS.random_element()
+        sage: x*MS.one() == x and MS.one()*x == x
+        True
 
-        basis_indices = cartesian_product([I,J,entry_basis])
-        super().__init__(field,
-                         basis_indices,
-                         category=category,
+    """
+    def __init__(self, n, scalars=AA, prefix="E", **kwargs):
+        super().__init__(Octonions(field=scalars),
+                         scalars,
+                         n,
                          prefix=prefix,
-                         bracket='(')
-
-    def _repr_(self):
-        return ("Module of %d by %d matrices with octonion entries"
-                " over the scalar ring %s" %
-                (self.nrows(), self.ncols(), self.base_ring()) )
-
-    def octonions(self):
-        r"""
-        Return the Octonion algebra that our elements' entries come from.
-        """
-        return self._octonions
-
-    def nrows(self):
-        return self._nrows
-    ncols = nrows
-
-    def product_on_basis(self, mon1, mon2):
-        (i,j,oct1) = mon1
-        (k,l,oct2) = mon2
-        if j == k:
-            return self.monomial((i,l,oct1*oct2))
-        else:
-            return self.zero()
-
-    def one(self):
-        r"""
-        SETUP::
-
-            sage: from mjo.octonions import OctonionMatrixAlgebra
-
-        TESTS::
-
-            sage: set_random_seed()
-            sage: MS = OctonionMatrixAlgebra(ZZ.random_element(10))
-            sage: x = MS.random_element()
-            sage: x*MS.one() == x and MS.one()*x == x
-            True
-
-        """
-        return sum( (self.monomial((i,i,self._octonions.one()))
-                     for i in range(self.nrows()) ),
-                    self.zero() )
-
-    def from_list(self, entries):
-        r"""
-        Construct an element of this algebra from a list of lists of
-        octonions.
-
-        SETUP::
-
-            sage: from mjo.octonions import Octonions, OctonionMatrixAlgebra
-
-        EXAMPLES::
-
-            sage: O = Octonions(QQ)
-            sage: e0,e1,e2,e3,e4,e5,e6,e7 = O.gens()
-            sage: MS = OctonionMatrixAlgebra(2)
-            sage: MS.from_list([ [e0+e4, e1+e5],
-            ....:                [e2-e6, e3-e7] ])
-            +---------+---------+
-            | e0 + e4 | e1 + e5 |
-            +---------+---------+
-            | e2 - e6 | e3 - e7 |
-            +---------+---------+
-
-        """
-        nrows = len(entries)
-        ncols = 0
-        if nrows > 0:
-            ncols = len(entries[0])
-
-        if (not all( len(r) == ncols for r in entries )) or (ncols != nrows):
-            raise ValueError("list must be square")
-
-        def convert(e_ij):
-            # We have to pass through vectors to convert from the
-            # given octonion algebra to ours. Otherwise we can fail
-            # to convert an element of (for example) Octonions(QQ)
-            # to Octonions(AA).
-            return self.octonions().from_vector(e_ij.to_vector())
-
-        return sum( (self.monomial( (i,j, convert(entries[i][j])) )
-                     for i in range(nrows)
-                     for j in range(ncols) ),
-                    self.zero() )
+                         **kwargs)