]> gitweb.michael.orlitzky.com - sage.d.git/commitdiff
eja: separate out the operator class and rename both files.
authorMichael Orlitzky <michael@orlitzky.com>
Sun, 28 Jul 2019 16:56:46 +0000 (12:56 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Mon, 29 Jul 2019 03:19:01 +0000 (23:19 -0400)
Let's start organizing. It's also time to get the test suite
working. I've added stupid SETUP blocks to each docstring to load the
stuff being tested.

mjo/eja/eja_algebra.py [moved from mjo/eja/euclidean_jordan_algebra.py with 85% similarity]
mjo/eja/eja_operator.py [new file with mode: 0644]

similarity index 85%
rename from mjo/eja/euclidean_jordan_algebra.py
rename to mjo/eja/eja_algebra.py
index 70a77701b342e36eec827d3ec151b87bf67fe902..8ab6afa33e8b8ccb9241099f5420fd035bd7b65c 100644 (file)
@@ -5,367 +5,15 @@ are used in optimization, and have some additional nice methods beyond
 what can be supported in a general Jordan Algebra.
 """
 
 what can be supported in a general Jordan Algebra.
 """
 
-from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis
-from sage.categories.map import Map
-from sage.structure.element import is_Matrix
-from sage.structure.category_object import normalize_names
+from sage.all import *
 
 from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra
 from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_element import FiniteDimensionalAlgebraElement
 
 from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra
 from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_element import FiniteDimensionalAlgebraElement
+from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis
+from sage.structure.element import is_Matrix
+from sage.structure.category_object import normalize_names
 
 
-
-class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
-    def __init__(self, domain_eja, codomain_eja, mat):
-        if not (
-          isinstance(domain_eja, FiniteDimensionalEuclideanJordanAlgebra) and
-          isinstance(codomain_eja, FiniteDimensionalEuclideanJordanAlgebra) ):
-            raise ValueError('(co)domains must be finite-dimensional Euclidean '
-                             'Jordan algebras')
-
-        F = domain_eja.base_ring()
-        if not (F == codomain_eja.base_ring()):
-            raise ValueError("domain and codomain must have the same base ring")
-
-        # We need to supply something here to avoid getting the
-        # default Homset of the parent FiniteDimensionalAlgebra class,
-        # which messes up e.g. equality testing. We use FreeModules(F)
-        # instead of VectorSpaces(F) because our characteristic polynomial
-        # algorithm will need to F to be a polynomial ring at some point.
-        # When F is a field, FreeModules(F) returns VectorSpaces(F) anyway.
-        parent = Hom(domain_eja, codomain_eja, FreeModules(F))
-
-        # The Map initializer will set our parent to a homset, which
-        # is explicitly NOT what we want, because these ain't algebra
-        # homomorphisms.
-        super(FiniteDimensionalEuclideanJordanAlgebraOperator,self).__init__(parent)
-
-        # Keep a matrix around to do all of the real work. It would
-        # be nice if we could use a VectorSpaceMorphism instead, but
-        # those use row vectors that we don't want to accidentally
-        # expose to our users.
-        self._matrix = mat
-
-
-    def _call_(self, x):
-        """
-        Allow this operator to be called only on elements of an EJA.
-
-        EXAMPLES::
-
-            sage: J = JordanSpinEJA(3)
-            sage: x = J.linear_combination(zip(range(len(J.gens())), J.gens()))
-            sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
-            sage: f(x) == x
-            True
-
-        """
-        return self.codomain()(self.matrix()*x.vector())
-
-
-    def _add_(self, other):
-        """
-        Add the ``other`` EJA operator to this one.
-
-        EXAMPLES:
-
-        When we add two EJA operators, we get another one back::
-
-            sage: J = RealSymmetricEJA(2)
-            sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
-            sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
-            sage: f + g
-            Linear operator between finite-dimensional Euclidean Jordan
-            algebras represented by the matrix:
-            [2 0 0]
-            [0 2 0]
-            [0 0 2]
-            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
-            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
-
-        If you try to add two identical vector space operators but on
-        different EJAs, that should blow up::
-
-            sage: J1 = RealSymmetricEJA(2)
-            sage: J2 = JordanSpinEJA(3)
-            sage: id = identity_matrix(QQ, 3)
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,J1,id)
-            sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,J2,id)
-            sage: f + g
-            Traceback (most recent call last):
-            ...
-            TypeError: unsupported operand parent(s) for +: ...
-
-        """
-        return FiniteDimensionalEuclideanJordanAlgebraOperator(
-                self.domain(),
-                self.codomain(),
-                self.matrix() + other.matrix())
-
-
-    def _composition_(self, other, homset):
-        """
-        Compose two EJA operators to get another one (and NOT a formal
-        composite object) back.
-
-        EXAMPLES::
-
-            sage: J1 = JordanSpinEJA(3)
-            sage: J2 = RealCartesianProductEJA(2)
-            sage: J3 = RealSymmetricEJA(1)
-            sage: mat1 = matrix(QQ, [[1,2,3],
-            ....:                    [4,5,6]])
-            sage: mat2 = matrix(QQ, [[7,8]])
-            sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,
-            ....:                                                     J2,
-            ....:                                                     mat1)
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,
-            ....:                                                     J3,
-            ....:                                                     mat2)
-            sage: f*g
-            Linear operator between finite-dimensional Euclidean Jordan
-            algebras represented by the matrix:
-            [39 54 69]
-            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
-            Codomain: Euclidean Jordan algebra of degree 1 over Rational Field
-
-        """
-        return FiniteDimensionalEuclideanJordanAlgebraOperator(
-          other.domain(),
-          self.codomain(),
-          self.matrix()*other.matrix())
-
-
-    def __eq__(self, other):
-        if self.domain() != other.domain():
-            return False
-        if self.codomain() != other.codomain():
-            return False
-        if self.matrix() != other.matrix():
-            return False
-        return True
-
-
-    def __invert__(self):
-        """
-        Invert this EJA operator.
-
-        EXAMPLES::
-
-            sage: J = RealSymmetricEJA(2)
-            sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
-            sage: ~f
-            Linear operator between finite-dimensional Euclidean Jordan
-            algebras represented by the matrix:
-            [1 0 0]
-            [0 1 0]
-            [0 0 1]
-            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
-            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
-
-        """
-        return FiniteDimensionalEuclideanJordanAlgebraOperator(
-                self.codomain(),
-                self.domain(),
-                ~self.matrix())
-
-
-    def __mul__(self, other):
-        """
-        Compose two EJA operators, or scale myself by an element of the
-        ambient vector space.
-
-        We need to override the real ``__mul__`` function to prevent the
-        coercion framework from throwing an error when it fails to convert
-        a base ring element into a morphism.
-
-        EXAMPLES:
-
-        We can scale an operator on a rational algebra by a rational number::
-
-            sage: J = RealSymmetricEJA(2)
-            sage: e0,e1,e2 = J.gens()
-            sage: x = 2*e0 + 4*e1 + 16*e2
-            sage: x.operator()
-            Linear operator between finite-dimensional Euclidean Jordan algebras
-            represented by the matrix:
-            [ 2  4  0]
-            [ 2  9  2]
-            [ 0  4 16]
-            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
-            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
-            sage: x.operator()*(1/2)
-            Linear operator between finite-dimensional Euclidean Jordan algebras
-            represented by the matrix:
-            [  1   2   0]
-            [  1 9/2   1]
-            [  0   2   8]
-            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
-            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
-
-        """
-        if other in self.codomain().base_ring():
-            return FiniteDimensionalEuclideanJordanAlgebraOperator(
-                self.domain(),
-                self.codomain(),
-                self.matrix()*other)
-
-        # This should eventually delegate to _composition_ after performing
-        # some sanity checks for us.
-        mor = super(FiniteDimensionalEuclideanJordanAlgebraOperator,self)
-        return mor.__mul__(other)
-
-
-    def _neg_(self):
-        """
-        Negate this EJA operator.
-
-        EXAMPLES::
-
-            sage: J = RealSymmetricEJA(2)
-            sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
-            sage: -f
-            Linear operator between finite-dimensional Euclidean Jordan
-            algebras represented by the matrix:
-            [-1  0  0]
-            [ 0 -1  0]
-            [ 0  0 -1]
-            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
-            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
-
-        """
-        return FiniteDimensionalEuclideanJordanAlgebraOperator(
-                self.domain(),
-                self.codomain(),
-                -self.matrix())
-
-
-    def __pow__(self, n):
-        """
-        Raise this EJA operator to the power ``n``.
-
-        TESTS:
-
-        Ensure that we get back another EJA operator that can be added,
-        subtracted, et cetera::
-
-            sage: J = RealSymmetricEJA(2)
-            sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
-            sage: f^0 + f^1 + f^2
-            Linear operator between finite-dimensional Euclidean Jordan
-            algebras represented by the matrix:
-            [3 0 0]
-            [0 3 0]
-            [0 0 3]
-            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
-            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
-
-        """
-        if (n == 1):
-            return self
-        elif (n == 0):
-            # Raising a vector space morphism to the zero power gives
-            # you back a special IdentityMorphism that is useless to us.
-            rows = self.codomain().dimension()
-            cols = self.domain().dimension()
-            mat = matrix.identity(self.base_ring(), rows, cols)
-        else:
-            mat = self.matrix()**n
-
-        return FiniteDimensionalEuclideanJordanAlgebraOperator(
-                 self.domain(),
-                 self.codomain(),
-                 mat)
-
-
-    def _repr_(self):
-        r"""
-
-        A text representation of this linear operator on a Euclidean
-        Jordan Algebra.
-
-        EXAMPLES::
-
-            sage: J = JordanSpinEJA(2)
-            sage: id = identity_matrix(J.base_ring(), J.dimension())
-            sage: FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
-            Linear operator between finite-dimensional Euclidean Jordan
-            algebras represented by the matrix:
-            [1 0]
-            [0 1]
-            Domain: Euclidean Jordan algebra of degree 2 over Rational Field
-            Codomain: Euclidean Jordan algebra of degree 2 over Rational Field
-
-        """
-        msg = ("Linear operator between finite-dimensional Euclidean Jordan "
-                "algebras represented by the matrix:\n",
-               "{!r}\n",
-               "Domain: {}\n",
-               "Codomain: {}")
-        return ''.join(msg).format(self.matrix(),
-                                   self.domain(),
-                                   self.codomain())
-
-
-    def _sub_(self, other):
-        """
-        Subtract ``other`` from this EJA operator.
-
-        EXAMPLES::
-
-            sage: J = RealSymmetricEJA(2)
-            sage: id = identity_matrix(J.base_ring(),J.dimension())
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
-            sage: f - (f*2)
-            Linear operator between finite-dimensional Euclidean Jordan
-            algebras represented by the matrix:
-            [-1  0  0]
-            [ 0 -1  0]
-            [ 0  0 -1]
-            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
-            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
-
-        """
-        return (self + (-other))
-
-
-    def matrix(self):
-        """
-        Return the matrix representation of this operator with respect
-        to the default bases of its (co)domain.
-
-        EXAMPLES::
-
-            sage: J = RealSymmetricEJA(2)
-            sage: mat = matrix(J.base_ring(), J.dimension(), range(9))
-            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,mat)
-            sage: f.matrix()
-            [0 1 2]
-            [3 4 5]
-            [6 7 8]
-
-        """
-        return self._matrix
-
-
-    def minimal_polynomial(self):
-        """
-        Return the minimal polynomial of this linear operator,
-        in the variable ``t``.
-
-        EXAMPLES::
-
-            sage: J = RealSymmetricEJA(3)
-            sage: J.one().operator().minimal_polynomial()
-            t - 1
-
-        """
-        # The matrix method returns a polynomial in 'x' but want one in 't'.
-        return self.matrix().minimal_polynomial().change_variable_name('t')
+from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
 
 
 class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
 
 
 class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
@@ -413,6 +61,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
                  rank=None,
                  natural_basis=None):
         """
                  rank=None,
                  natural_basis=None):
         """
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import random_eja
+
         EXAMPLES:
 
         By definition, Jordan multiplication commutes::
         EXAMPLES:
 
         By definition, Jordan multiplication commutes::
@@ -569,6 +221,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             other words, we don't have to do a change of basis before e.g.
             computing the trace or determinant.
 
             other words, we don't have to do a change of basis before e.g.
             computing the trace or determinant.
 
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import JordanSpinEJA
+
         EXAMPLES:
 
         The characteristic polynomial in the spin algebra is given in
         EXAMPLES:
 
         The characteristic polynomial in the spin algebra is given in
@@ -620,6 +276,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
         subclasses if they are sure that the necessary properties are
         satisfied.
 
         subclasses if they are sure that the necessary properties are
         satisfied.
 
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import random_eja
+
         EXAMPLES:
 
         The inner product must satisfy its axiom for this algebra to truly
         EXAMPLES:
 
         The inner product must satisfy its axiom for this algebra to truly
@@ -652,6 +312,11 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
         Note that this will always return a matrix. The standard basis
         in `R^n` will be returned as `n`-by-`1` column matrices.
 
         Note that this will always return a matrix. The standard basis
         in `R^n` will be returned as `n`-by-`1` column matrices.
 
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+            ....:                                  RealSymmetricEJA)
+
         EXAMPLES::
 
             sage: J = RealSymmetricEJA(2)
         EXAMPLES::
 
             sage: J = RealSymmetricEJA(2)
@@ -690,10 +355,15 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
         else:
             return self._rank
 
         else:
             return self._rank
 
+
     def vector_space(self):
         """
         Return the vector space that underlies this algebra.
 
     def vector_space(self):
         """
         Return the vector space that underlies this algebra.
 
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import RealSymmetricEJA
+
         EXAMPLES::
 
             sage: J = RealSymmetricEJA(2)
         EXAMPLES::
 
             sage: J = RealSymmetricEJA(2)
@@ -721,6 +391,11 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
 
         def __init__(self, A, elt=None):
             """
 
         def __init__(self, A, elt=None):
             """
+
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import RealSymmetricEJA
+
             EXAMPLES:
 
             The identity in `S^n` is converted to the identity in the EJA::
             EXAMPLES:
 
             The identity in `S^n` is converted to the identity in the EJA::
@@ -777,6 +452,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
                 instead of column vectors! We, on the other hand, assume column
                 vectors everywhere.
 
                 instead of column vectors! We, on the other hand, assume column
                 vectors everywhere.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import random_eja
+
             EXAMPLES::
 
                 sage: set_random_seed()
             EXAMPLES::
 
                 sage: set_random_seed()
@@ -825,6 +504,11 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             operation is ultimately kosher. This function sidesteps
             the CAS to get the answer we want and expect.
 
             operation is ultimately kosher. This function sidesteps
             the CAS to get the answer we want and expect.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import (RealCartesianProductEJA,
+                ....:                                  random_eja)
+
             EXAMPLES::
 
                 sage: R = PolynomialRing(QQ, 't')
             EXAMPLES::
 
                 sage: R = PolynomialRing(QQ, 't')
@@ -861,6 +545,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             """
             Return the characteristic polynomial of this element.
 
             """
             Return the characteristic polynomial of this element.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import RealCartesianProductEJA
+
             EXAMPLES:
 
             The rank of `R^3` is three, and the minimal polynomial of
             EXAMPLES:
 
             The rank of `R^3` is three, and the minimal polynomial of
@@ -896,6 +584,15 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             """
             Return the parent algebra's inner product of myself and ``other``.
 
             """
             Return the parent algebra's inner product of myself and ``other``.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import (
+                ....:   ComplexHermitianEJA,
+                ....:   JordanSpinEJA,
+                ....:   QuaternionHermitianEJA,
+                ....:   RealSymmetricEJA,
+                ....:   random_eja)
+
             EXAMPLES:
 
             The inner product in the Jordan spin algebra is the usual
             EXAMPLES:
 
             The inner product in the Jordan spin algebra is the usual
@@ -959,6 +656,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             Return whether or not this element operator-commutes
             with ``other``.
 
             Return whether or not this element operator-commutes
             with ``other``.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import random_eja
+
             EXAMPLES:
 
             The definition of a Jordan algebra says that any element
             EXAMPLES:
 
             The definition of a Jordan algebra says that any element
@@ -1046,6 +747,11 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             """
             Return my determinant, the product of my eigenvalues.
 
             """
             Return my determinant, the product of my eigenvalues.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+                ....:                                  random_eja)
+
             EXAMPLES::
 
                 sage: J = JordanSpinEJA(2)
             EXAMPLES::
 
                 sage: J = JordanSpinEJA(2)
@@ -1092,6 +798,11 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             We appeal to the quadratic representation as in Koecher's
             Theorem 12 in Chapter III, Section 5.
 
             We appeal to the quadratic representation as in Koecher's
             Theorem 12 in Chapter III, Section 5.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+                ....:                                  random_eja)
+
             EXAMPLES:
 
             The inverse in the spin factor algebra is given in Alizadeh's
             EXAMPLES:
 
             The inverse in the spin factor algebra is given in Alizadeh's
@@ -1168,6 +879,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             whether or not the paren't algebra's zero element is a root
             of this element's minimal polynomial.
 
             whether or not the paren't algebra's zero element is a root
             of this element's minimal polynomial.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import random_eja
+
             TESTS:
 
             The identity element is always invertible::
             TESTS:
 
             The identity element is always invertible::
@@ -1199,6 +914,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             an assocoative subalgebra and we're nilpotent there if and
             only if we're nilpotent here (probably).
 
             an assocoative subalgebra and we're nilpotent there if and
             only if we're nilpotent here (probably).
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import random_eja
+
             TESTS:
 
             The identity element is never nilpotent::
             TESTS:
 
             The identity element is never nilpotent::
@@ -1239,6 +958,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             """
             Return whether or not this is a regular element.
 
             """
             Return whether or not this is a regular element.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import JordanSpinEJA
+
             EXAMPLES:
 
             The identity element always has degree one, but any element
             EXAMPLES:
 
             The identity element always has degree one, but any element
@@ -1267,6 +990,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             and figuring out its dimension (that is, whether or not
             they're linearly dependent).
 
             and figuring out its dimension (that is, whether or not
             they're linearly dependent).
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import JordanSpinEJA
+
             EXAMPLES::
 
                 sage: J = JordanSpinEJA(4)
             EXAMPLES::
 
                 sage: J = JordanSpinEJA(4)
@@ -1312,6 +1039,11 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             polynomial of this element's operator matrix (in that
             subalgebra). This works by Baes Proposition 2.3.16.
 
             polynomial of this element's operator matrix (in that
             subalgebra). This works by Baes Proposition 2.3.16.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+                ....:                                  random_eja)
+
             TESTS:
 
             The minimal polynomial of the identity and zero elements are
             TESTS:
 
             The minimal polynomial of the identity and zero elements are
@@ -1380,6 +1112,11 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             "natural" representation of this element as a Hermitian
             matrix, if it has one. If not, you get the usual representation.
 
             "natural" representation of this element as a Hermitian
             matrix, if it has one. If not, you get the usual representation.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
+                ....:                                  QuaternionHermitianEJA)
+
             EXAMPLES::
 
                 sage: J = ComplexHermitianEJA(3)
             EXAMPLES::
 
                 sage: J = ComplexHermitianEJA(3)
@@ -1423,6 +1160,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             Return the left-multiplication-by-this-element
             operator on the ambient algebra.
 
             Return the left-multiplication-by-this-element
             operator on the ambient algebra.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import random_eja
+
             TESTS::
 
                 sage: set_random_seed()
             TESTS::
 
                 sage: set_random_seed()
@@ -1447,6 +1188,11 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             """
             Return the quadratic representation of this element.
 
             """
             Return the quadratic representation of this element.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+                ....:                                  random_eja)
+
             EXAMPLES:
 
             The explicit form in the spin factor algebra is given by
             EXAMPLES:
 
             The explicit form in the spin factor algebra is given by
@@ -1578,6 +1324,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             Return the associative subalgebra of the parent EJA generated
             by this element.
 
             Return the associative subalgebra of the parent EJA generated
             by this element.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import random_eja
+
             TESTS::
 
                 sage: set_random_seed()
             TESTS::
 
                 sage: set_random_seed()
@@ -1635,6 +1385,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             Find an idempotent in the associative subalgebra I generate
             using Proposition 2.3.5 in Baes.
 
             Find an idempotent in the associative subalgebra I generate
             using Proposition 2.3.5 in Baes.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import random_eja
+
             TESTS::
 
                 sage: set_random_seed()
             TESTS::
 
                 sage: set_random_seed()
@@ -1695,6 +1449,12 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             """
             Return my trace, the sum of my eigenvalues.
 
             """
             Return my trace, the sum of my eigenvalues.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+                ....:                                  RealCartesianProductEJA,
+                ....:                                  random_eja)
+
             EXAMPLES::
 
                 sage: J = JordanSpinEJA(3)
             EXAMPLES::
 
                 sage: J = JordanSpinEJA(3)
@@ -1732,6 +1492,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             """
             Return the trace inner product of myself and ``other``.
 
             """
             Return the trace inner product of myself and ``other``.
 
+            SETUP::
+
+                sage: from mjo.eja.eja_algebra import random_eja
+
             TESTS:
 
             The trace inner product is commutative::
             TESTS:
 
             The trace inner product is commutative::
@@ -1788,6 +1552,10 @@ class RealCartesianProductEJA(FiniteDimensionalEuclideanJordanAlgebra):
     copies of the spin algebra. Once Cartesian product algebras
     are implemented, this can go.
 
     copies of the spin algebra. Once Cartesian product algebras
     are implemented, this can go.
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import RealCartesianProductEJA
+
     EXAMPLES:
 
     This multiplication table can be verified by hand::
     EXAMPLES:
 
     This multiplication table can be verified by hand::
@@ -1851,6 +1619,10 @@ def random_eja():
     Later this might be extended to return Cartesian products of the
     EJAs above.
 
     Later this might be extended to return Cartesian products of the
     EJAs above.
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import random_eja
+
     TESTS::
 
         sage: random_eja()
     TESTS::
 
         sage: random_eja()
@@ -1895,6 +1667,10 @@ def _complex_hermitian_basis(n, field=QQ):
     """
     Returns a basis for the space of complex Hermitian n-by-n matrices.
 
     """
     Returns a basis for the space of complex Hermitian n-by-n matrices.
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import _complex_hermitian_basis
+
     TESTS::
 
         sage: set_random_seed()
     TESTS::
 
         sage: set_random_seed()
@@ -1932,6 +1708,10 @@ def _quaternion_hermitian_basis(n, field=QQ):
     """
     Returns a basis for the space of quaternion Hermitian n-by-n matrices.
 
     """
     Returns a basis for the space of quaternion Hermitian n-by-n matrices.
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import _quaternion_hermitian_basis
+
     TESTS::
 
         sage: set_random_seed()
     TESTS::
 
         sage: set_random_seed()
@@ -2029,6 +1809,10 @@ def _embed_complex_matrix(M):
     matrices of size 2n-by-2n via the map the sends each entry `z = a +
     bi` to the block matrix ``[[a,b],[-b,a]]``.
 
     matrices of size 2n-by-2n via the map the sends each entry `z = a +
     bi` to the block matrix ``[[a,b],[-b,a]]``.
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import _embed_complex_matrix
+
     EXAMPLES::
 
         sage: F = QuadraticField(-1,'i')
     EXAMPLES::
 
         sage: F = QuadraticField(-1,'i')
@@ -2077,6 +1861,11 @@ def _unembed_complex_matrix(M):
     """
     The inverse of _embed_complex_matrix().
 
     """
     The inverse of _embed_complex_matrix().
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import (_embed_complex_matrix,
+        ....:                                  _unembed_complex_matrix)
+
     EXAMPLES::
 
         sage: A = matrix(QQ,[ [ 1,  2,   3,  4],
     EXAMPLES::
 
         sage: A = matrix(QQ,[ [ 1,  2,   3,  4],
@@ -2131,6 +1920,10 @@ def _embed_quaternion_matrix(M):
     ``[[a + bi, c+di],[-c + di, a-bi]]`, and then embedding those into
     a real matrix.
 
     ``[[a + bi, c+di],[-c + di, a-bi]]`, and then embedding those into
     a real matrix.
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import _embed_quaternion_matrix
+
     EXAMPLES::
 
         sage: Q = QuaternionAlgebra(QQ,-1,-1)
     EXAMPLES::
 
         sage: Q = QuaternionAlgebra(QQ,-1,-1)
@@ -2184,6 +1977,11 @@ def _unembed_quaternion_matrix(M):
     """
     The inverse of _embed_quaternion_matrix().
 
     """
     The inverse of _embed_quaternion_matrix().
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import (_embed_quaternion_matrix,
+        ....:                                  _unembed_quaternion_matrix)
+
     EXAMPLES::
 
         sage: M = matrix(QQ, [[ 1,  2,  3,  4],
     EXAMPLES::
 
         sage: M = matrix(QQ, [[ 1,  2,  3,  4],
@@ -2250,6 +2048,10 @@ class RealSymmetricEJA(FiniteDimensionalEuclideanJordanAlgebra):
     matrices, the usual symmetric Jordan product, and the trace inner
     product. It has dimension `(n^2 + n)/2` over the reals.
 
     matrices, the usual symmetric Jordan product, and the trace inner
     product. It has dimension `(n^2 + n)/2` over the reals.
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import RealSymmetricEJA
+
     EXAMPLES::
 
         sage: J = RealSymmetricEJA(2)
     EXAMPLES::
 
         sage: J = RealSymmetricEJA(2)
@@ -2311,6 +2113,10 @@ class ComplexHermitianEJA(FiniteDimensionalEuclideanJordanAlgebra):
     and the real-part-of-trace inner product. It has dimension `n^2` over
     the reals.
 
     and the real-part-of-trace inner product. It has dimension `n^2` over
     the reals.
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import ComplexHermitianEJA
+
     TESTS:
 
     The degree of this algebra is `n^2`::
     TESTS:
 
     The degree of this algebra is `n^2`::
@@ -2368,6 +2174,10 @@ class QuaternionHermitianEJA(FiniteDimensionalEuclideanJordanAlgebra):
     real-part-of-trace inner product. It has dimension `2n^2 - n` over
     the reals.
 
     real-part-of-trace inner product. It has dimension `2n^2 - n` over
     the reals.
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import QuaternionHermitianEJA
+
     TESTS:
 
     The degree of this algebra is `n^2`::
     TESTS:
 
     The degree of this algebra is `n^2`::
@@ -2427,6 +2237,10 @@ class JordanSpinEJA(FiniteDimensionalEuclideanJordanAlgebra):
     (<x_bar,y_bar>, x0*y_bar + y0*x_bar)``. It has dimension `n` over
     the reals.
 
     (<x_bar,y_bar>, x0*y_bar + y0*x_bar)``. It has dimension `n` over
     the reals.
 
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import JordanSpinEJA
+
     EXAMPLES:
 
     This multiplication table can be verified by hand::
     EXAMPLES:
 
     This multiplication table can be verified by hand::
diff --git a/mjo/eja/eja_operator.py b/mjo/eja/eja_operator.py
new file mode 100644 (file)
index 0000000..b225b29
--- /dev/null
@@ -0,0 +1,416 @@
+from sage.all import matrix
+from sage.categories.all import FreeModules
+from sage.categories.map import Map
+
+class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
+    def __init__(self, domain_eja, codomain_eja, mat):
+        # if not (
+        #   isinstance(domain_eja, FiniteDimensionalEuclideanJordanAlgebra) and
+        #   isinstance(codomain_eja, FiniteDimensionalEuclideanJordanAlgebra) ):
+        #     raise ValueError('(co)domains must be finite-dimensional Euclidean '
+        #                      'Jordan algebras')
+
+        F = domain_eja.base_ring()
+        if not (F == codomain_eja.base_ring()):
+            raise ValueError("domain and codomain must have the same base ring")
+
+        # We need to supply something here to avoid getting the
+        # default Homset of the parent FiniteDimensionalAlgebra class,
+        # which messes up e.g. equality testing. We use FreeModules(F)
+        # instead of VectorSpaces(F) because our characteristic polynomial
+        # algorithm will need to F to be a polynomial ring at some point.
+        # When F is a field, FreeModules(F) returns VectorSpaces(F) anyway.
+        parent = domain_eja.Hom(codomain_eja, FreeModules(F))
+
+        # The Map initializer will set our parent to a homset, which
+        # is explicitly NOT what we want, because these ain't algebra
+        # homomorphisms.
+        super(FiniteDimensionalEuclideanJordanAlgebraOperator,self).__init__(parent)
+
+        # Keep a matrix around to do all of the real work. It would
+        # be nice if we could use a VectorSpaceMorphism instead, but
+        # those use row vectors that we don't want to accidentally
+        # expose to our users.
+        self._matrix = mat
+
+
+    def _call_(self, x):
+        """
+        Allow this operator to be called only on elements of an EJA.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_algebra import JordanSpinEJA
+
+        EXAMPLES::
+
+            sage: J = JordanSpinEJA(3)
+            sage: x = J.linear_combination(zip(range(len(J.gens())), J.gens()))
+            sage: id = identity_matrix(J.base_ring(), J.dimension())
+            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: f(x) == x
+            True
+
+        """
+        return self.codomain()(self.matrix()*x.vector())
+
+
+    def _add_(self, other):
+        """
+        Add the ``other`` EJA operator to this one.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_algebra import (
+            ....:   JordanSpinEJA,
+            ....:   RealSymmetricEJA )
+
+        EXAMPLES:
+
+        When we add two EJA operators, we get another one back::
+
+            sage: J = RealSymmetricEJA(2)
+            sage: id = identity_matrix(J.base_ring(), J.dimension())
+            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: f + g
+            Linear operator between finite-dimensional Euclidean Jordan
+            algebras represented by the matrix:
+            [2 0 0]
+            [0 2 0]
+            [0 0 2]
+            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
+            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
+
+        If you try to add two identical vector space operators but on
+        different EJAs, that should blow up::
+
+            sage: J1 = RealSymmetricEJA(2)
+            sage: J2 = JordanSpinEJA(3)
+            sage: id = identity_matrix(QQ, 3)
+            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,J1,id)
+            sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,J2,id)
+            sage: f + g
+            Traceback (most recent call last):
+            ...
+            TypeError: unsupported operand parent(s) for +: ...
+
+        """
+        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+                self.domain(),
+                self.codomain(),
+                self.matrix() + other.matrix())
+
+
+    def _composition_(self, other, homset):
+        """
+        Compose two EJA operators to get another one (and NOT a formal
+        composite object) back.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_algebra import (
+            ....:   JordanSpinEJA,
+            ....:   RealCartesianProductEJA,
+            ....:   RealSymmetricEJA)
+
+        EXAMPLES::
+
+            sage: J1 = JordanSpinEJA(3)
+            sage: J2 = RealCartesianProductEJA(2)
+            sage: J3 = RealSymmetricEJA(1)
+            sage: mat1 = matrix(QQ, [[1,2,3],
+            ....:                    [4,5,6]])
+            sage: mat2 = matrix(QQ, [[7,8]])
+            sage: g = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,
+            ....:                                                     J2,
+            ....:                                                     mat1)
+            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,
+            ....:                                                     J3,
+            ....:                                                     mat2)
+            sage: f*g
+            Linear operator between finite-dimensional Euclidean Jordan
+            algebras represented by the matrix:
+            [39 54 69]
+            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
+            Codomain: Euclidean Jordan algebra of degree 1 over Rational Field
+
+        """
+        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+          other.domain(),
+          self.codomain(),
+          self.matrix()*other.matrix())
+
+
+    def __eq__(self, other):
+        if self.domain() != other.domain():
+            return False
+        if self.codomain() != other.codomain():
+            return False
+        if self.matrix() != other.matrix():
+            return False
+        return True
+
+
+    def __invert__(self):
+        """
+        Invert this EJA operator.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_algebra import RealSymmetricEJA
+
+        EXAMPLES::
+
+            sage: J = RealSymmetricEJA(2)
+            sage: id = identity_matrix(J.base_ring(), J.dimension())
+            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: ~f
+            Linear operator between finite-dimensional Euclidean Jordan
+            algebras represented by the matrix:
+            [1 0 0]
+            [0 1 0]
+            [0 0 1]
+            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
+            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
+
+        """
+        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+                self.codomain(),
+                self.domain(),
+                ~self.matrix())
+
+
+    def __mul__(self, other):
+        """
+        Compose two EJA operators, or scale myself by an element of the
+        ambient vector space.
+
+        We need to override the real ``__mul__`` function to prevent the
+        coercion framework from throwing an error when it fails to convert
+        a base ring element into a morphism.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_algebra import RealSymmetricEJA
+
+        EXAMPLES:
+
+        We can scale an operator on a rational algebra by a rational number::
+
+            sage: J = RealSymmetricEJA(2)
+            sage: e0,e1,e2 = J.gens()
+            sage: x = 2*e0 + 4*e1 + 16*e2
+            sage: x.operator()
+            Linear operator between finite-dimensional Euclidean Jordan algebras
+            represented by the matrix:
+            [ 2  4  0]
+            [ 2  9  2]
+            [ 0  4 16]
+            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
+            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
+            sage: x.operator()*(1/2)
+            Linear operator between finite-dimensional Euclidean Jordan algebras
+            represented by the matrix:
+            [  1   2   0]
+            [  1 9/2   1]
+            [  0   2   8]
+            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
+            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
+
+        """
+        if other in self.codomain().base_ring():
+            return FiniteDimensionalEuclideanJordanAlgebraOperator(
+                self.domain(),
+                self.codomain(),
+                self.matrix()*other)
+
+        # This should eventually delegate to _composition_ after performing
+        # some sanity checks for us.
+        mor = super(FiniteDimensionalEuclideanJordanAlgebraOperator,self)
+        return mor.__mul__(other)
+
+
+    def _neg_(self):
+        """
+        Negate this EJA operator.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_algebra import RealSymmetricEJA
+
+        EXAMPLES::
+
+            sage: J = RealSymmetricEJA(2)
+            sage: id = identity_matrix(J.base_ring(), J.dimension())
+            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: -f
+            Linear operator between finite-dimensional Euclidean Jordan
+            algebras represented by the matrix:
+            [-1  0  0]
+            [ 0 -1  0]
+            [ 0  0 -1]
+            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
+            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
+
+        """
+        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+                self.domain(),
+                self.codomain(),
+                -self.matrix())
+
+
+    def __pow__(self, n):
+        """
+        Raise this EJA operator to the power ``n``.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_algebra import RealSymmetricEJA
+
+        TESTS:
+
+        Ensure that we get back another EJA operator that can be added,
+        subtracted, et cetera::
+
+            sage: J = RealSymmetricEJA(2)
+            sage: id = identity_matrix(J.base_ring(), J.dimension())
+            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: f^0 + f^1 + f^2
+            Linear operator between finite-dimensional Euclidean Jordan
+            algebras represented by the matrix:
+            [3 0 0]
+            [0 3 0]
+            [0 0 3]
+            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
+            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
+
+        """
+        if (n == 1):
+            return self
+        elif (n == 0):
+            # Raising a vector space morphism to the zero power gives
+            # you back a special IdentityMorphism that is useless to us.
+            rows = self.codomain().dimension()
+            cols = self.domain().dimension()
+            mat = matrix.identity(self.base_ring(), rows, cols)
+        else:
+            mat = self.matrix()**n
+
+        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+                 self.domain(),
+                 self.codomain(),
+                 mat)
+
+
+    def _repr_(self):
+        r"""
+
+        A text representation of this linear operator on a Euclidean
+        Jordan Algebra.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_algebra import JordanSpinEJA
+
+        EXAMPLES::
+
+            sage: J = JordanSpinEJA(2)
+            sage: id = identity_matrix(J.base_ring(), J.dimension())
+            sage: FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            Linear operator between finite-dimensional Euclidean Jordan
+            algebras represented by the matrix:
+            [1 0]
+            [0 1]
+            Domain: Euclidean Jordan algebra of degree 2 over Rational Field
+            Codomain: Euclidean Jordan algebra of degree 2 over Rational Field
+
+        """
+        msg = ("Linear operator between finite-dimensional Euclidean Jordan "
+                "algebras represented by the matrix:\n",
+               "{!r}\n",
+               "Domain: {}\n",
+               "Codomain: {}")
+        return ''.join(msg).format(self.matrix(),
+                                   self.domain(),
+                                   self.codomain())
+
+
+    def _sub_(self, other):
+        """
+        Subtract ``other`` from this EJA operator.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_algebra import RealSymmetricEJA
+
+        EXAMPLES::
+
+            sage: J = RealSymmetricEJA(2)
+            sage: id = identity_matrix(J.base_ring(),J.dimension())
+            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,id)
+            sage: f - (f*2)
+            Linear operator between finite-dimensional Euclidean Jordan
+            algebras represented by the matrix:
+            [-1  0  0]
+            [ 0 -1  0]
+            [ 0  0 -1]
+            Domain: Euclidean Jordan algebra of degree 3 over Rational Field
+            Codomain: Euclidean Jordan algebra of degree 3 over Rational Field
+
+        """
+        return (self + (-other))
+
+
+    def matrix(self):
+        """
+        Return the matrix representation of this operator with respect
+        to the default bases of its (co)domain.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_algebra import RealSymmetricEJA
+
+        EXAMPLES::
+
+            sage: J = RealSymmetricEJA(2)
+            sage: mat = matrix(J.base_ring(), J.dimension(), range(9))
+            sage: f = FiniteDimensionalEuclideanJordanAlgebraOperator(J,J,mat)
+            sage: f.matrix()
+            [0 1 2]
+            [3 4 5]
+            [6 7 8]
+
+        """
+        return self._matrix
+
+
+    def minimal_polynomial(self):
+        """
+        Return the minimal polynomial of this linear operator,
+        in the variable ``t``.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
+            sage: from mjo.eja.eja_algebra import RealSymmetricEJA
+
+        EXAMPLES::
+
+            sage: J = RealSymmetricEJA(3)
+            sage: J.one().operator().minimal_polynomial()
+            t - 1
+
+        """
+        # The matrix method returns a polynomial in 'x' but want one in 't'.
+        return self.matrix().minimal_polynomial().change_variable_name('t')