]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/euclidean_jordan_algebra.py
eja: move a bunch of operator_matrix() tests to operator().
[sage.d.git] / mjo / eja / euclidean_jordan_algebra.py
index 9414d2cf27fd2728ef205650b128ab37d1b83949..750b6c1c37460a704f83aeb62b66aaf4ce1ca952 100644 (file)
@@ -6,262 +6,346 @@ 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.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_morphism import FiniteDimensionalAlgebraMorphism
 
 
-class FiniteDimensionalEuclideanJordanAlgebraMorphism(FiniteDimensionalAlgebraMorphism):
-    """
-    A linear map between two finite-dimensional EJAs.
+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')
 
-    This is a very thin wrapper around FiniteDimensionalAlgebraMorphism
-    that does only a few things:
+        F = domain_eja.base_ring()
+        if not (F == codomain_eja.base_ring()):
+            raise ValueError("domain and codomain must have the same base ring")
 
-      1. Avoids the ``unitary`` and ``check`` arguments to the constructor
-         that will always be ``False``. This is necessary because these
-         are homomorphisms with respect to ADDITION, but the SageMath
-         machinery wants to check that they're homomorphisms with respect
-         to (Jordan) MULTIPLICATION. That obviously doesn't work.
+        # We need to supply something here to avoid getting the
+        # default Homset of the parent FiniteDimensionalAlgebra class,
+        # which messes up e.g. equality testing.
+        parent = Hom(domain_eja, codomain_eja, VectorSpaces(F))
 
-      2. Inputs and outputs the underlying matrix with respect to COLUMN
-         vectors, unlike the parent class.
+        # 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)
 
-      3. Allows us to add, subtract, negate, multiply (compose), and
-         invert morphisms in the obvious way.
+        # 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
 
-    If this seems a bit heavyweight, it is. I would have been happy to
-    use a the ring morphism that underlies the finite-dimensional
-    algebra morphism, but they don't seem to be callable on elements of
-    our EJA, and you can't add/multiply/etc. them.
-    """
 
-    def _add_(self, other):
+    def _call_(self, x):
         """
-        Add two EJA morphisms in the obvious way.
+        Allow this operator to be called only on elements of an EJA.
 
         EXAMPLES::
 
-            sage: J = RealSymmetricEJA(3)
-            sage: x = J.zero()
-            sage: y = J.one()
-            sage: x.operator() + y.operator()
-            Morphism from Euclidean Jordan algebra of degree 6 over Rational
-            Field to Euclidean Jordan algebra of degree 6 over Rational Field
-            given by matrix
-            [1 0 0 0 0 0]
-            [0 1 0 0 0 0]
-            [0 0 1 0 0 0]
-            [0 0 0 1 0 0]
-            [0 0 0 0 1 0]
-            [0 0 0 0 0 1]
-
-        TESTS::
-
-            sage: set_random_seed()
-            sage: J = random_eja()
-            sage: x = J.random_element()
-            sage: y = J.random_element()
-            sage: (x.operator() + y.operator()) in J.Hom(J)
+            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
 
         """
-        P = self.parent()
-        if not other in P:
-            raise ValueError("summands must live in the same space")
+        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())
 
-        return FiniteDimensionalEuclideanJordanAlgebraMorphism(
-                  P,
-                  self.matrix() + other.matrix() )
 
+    def _composition_(self, other, homset):
+        """
+        Compose two EJA operators to get another one (and NOT a formal
+        composite object) back.
 
-    def __init__(self, parent, f):
-        FiniteDimensionalAlgebraMorphism.__init__(self,
-                                                  parent,
-                                                  f.transpose(),
-                                                  unitary=False,
-                                                  check=False)
+        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
 
-    def _invert_(self):
         """
+        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: x = J.linear_combination(zip(range(len(J.gens())), J.gens()))
-            sage: x.is_invertible()
-            True
-            sage: ~x.operator()
-            Morphism from Euclidean Jordan algebra of degree 3 over Rational
-            Field to Euclidean Jordan algebra of degree 3 over Rational Field
-            given by matrix
-            [-3/2    2 -1/2]
-            [   1    0    0]
-            [-1/2    0  1/2]
-            sage: x.operator_matrix().inverse()
-            [-3/2    2 -1/2]
-            [   1    0    0]
-            [-1/2    0  1/2]
-
-        TESTS::
-
-            sage: set_random_seed()
-            sage: J = random_eja()
-            sage: x = J.random_element()
-            sage: not x.is_invertible() or (
-            ....:   (~x.operator()).matrix() == x.operator_matrix().inverse() )
-            True
+            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
 
         """
-        A = self.matrix()
-        if not A.is_invertible():
-            raise ValueError("morphism is not invertible")
+        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+                self.codomain(),
+                self.domain(),
+                ~self.matrix())
 
-        P = self.parent()
-        return FiniteDimensionalEuclideanJordanAlgebraMorphism(self.parent(),
-                                                                A.inverse())
 
-    def _lmul_(self, other):
+    def __mul__(self, other):
         """
-        Compose two EJA morphisms using multiplicative notation.
+        Compose two EJA operators, or scale myself by an element of the
+        ambient vector space.
 
-        EXAMPLES::
+        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.
 
-            sage: J = RealSymmetricEJA(3)
-            sage: x = J.zero()
-            sage: y = J.one()
-            sage: x.operator() * y.operator()
-            Morphism from Euclidean Jordan algebra of degree 6 over Rational
-            Field to Euclidean Jordan algebra of degree 6 over Rational Field
-            given by matrix
-            [0 0 0 0 0 0]
-            [0 0 0 0 0 0]
-            [0 0 0 0 0 0]
-            [0 0 0 0 0 0]
-            [0 0 0 0 0 0]
-            [0 0 0 0 0 0]
-
-        TESTS::
+        EXAMPLES:
 
-            sage: set_random_seed()
-            sage: J = random_eja()
-            sage: x = J.random_element()
-            sage: y = J.random_element()
-            sage: (x.operator() * y.operator()) in J.Hom(J)
-            True
+        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 not other.codomain() is self.domain():
-            raise ValueError("(co)domains must agree for composition")
+        if other in self.codomain().base_ring():
+            return FiniteDimensionalEuclideanJordanAlgebraOperator(
+                self.domain(),
+                self.codomain(),
+                self.matrix()*other)
 
-        return FiniteDimensionalEuclideanJordanAlgebraMorphism(
-                  self.parent(),
-                  self.matrix()*other.matrix() )
+        # 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 morphism.
+        Negate this EJA operator.
 
         EXAMPLES::
 
             sage: J = RealSymmetricEJA(2)
-            sage: x = J.one()
-            sage: -x.operator()
-            Morphism from Euclidean Jordan algebra of degree 3 over Rational
-            Field to Euclidean Jordan algebra of degree 3 over Rational Field
-            given by matrix
+            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
 
-        TESTS::
+        """
+        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+                self.domain(),
+                self.codomain(),
+                -self.matrix())
 
-            sage: set_random_seed()
-            sage: J = random_eja()
-            sage: x = J.random_element()
-            sage: -x.operator() in J.Hom(J)
-            True
 
+    def __pow__(self, n):
         """
-        return FiniteDimensionalEuclideanJordanAlgebraMorphism(
-                  self.parent(),
-                  -self.matrix() )
+        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
 
-    def _repr_(self):
         """
-        We override only the representation that is shown to the user,
-        because we want the matrix to be with respect to COLUMN vectors.
+        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
 
-        TESTS:
+        return FiniteDimensionalEuclideanJordanAlgebraOperator(
+                 self.domain(),
+                 self.codomain(),
+                 mat)
 
-        Ensure that we see the transpose of the underlying matrix object:
 
-            sage: J = RealSymmetricEJA(3)
-            sage: x = J.linear_combination(zip(range(len(J.gens())), J.gens()))
-            sage: L = x.operator()
-            sage: L
-            Morphism from Euclidean Jordan algebra of degree 6 over Rational
-            Field to Euclidean Jordan algebra of degree 6 over Rational Field
-            given by matrix
-            [  0   1   2   0   0   0]
-            [1/2 3/2   2 1/2   1   0]
-            [  1   2 5/2   0 1/2   1]
-            [  0   1   0   3   4   0]
-            [  0   1 1/2   2   4   2]
-            [  0   0   2   0   4   5]
-            sage: L._matrix
-            [  0 1/2   1   0   0   0]
-            [  1 3/2   2   1   1   0]
-            [  2   2 5/2   0 1/2   2]
-            [  0 1/2   0   3   2   0]
-            [  0   1 1/2   4   4   4]
-            [  0   0   1   0   2   5]
+    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
 
         """
-        return "Morphism from {} to {} given by matrix\n{}".format(
-            self.domain(), self.codomain(), self.matrix())
+        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):
+    def _sub_(self, other):
         """
-        Subtract one morphism from another using addition and negation.
+        Subtract ``other`` from this EJA operator.
 
         EXAMPLES::
 
             sage: J = RealSymmetricEJA(2)
-            sage: L1 = J.one().operator()
-            sage: L1 - L1
-            Morphism from Euclidean Jordan algebra of degree 3 over Rational
-            Field to Euclidean Jordan algebra of degree 3 over Rational
-            Field given by matrix
-            [0 0 0]
-            [0 0 0]
-            [0 0 0]
-
-        TESTS::
-
-            sage: set_random_seed()
-            sage: J = random_eja()
-            sage: x = J.random_element()
-            sage: y = J.random_element()
-            sage: x.operator() - y.operator() in J.Hom(J)
-            True
+            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)
+        return (self + (-other))
 
 
     def matrix(self):
         """
-        Return the matrix of this morphism with respect to a left-action
-        on column vectors.
+        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 FiniteDimensionalAlgebraMorphism.matrix(self).transpose()
+        return self._matrix
 
 
 class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
@@ -361,7 +445,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
         determinant).
         """
         z = self._a_regular_element()
-        V = z.vector().parent().ambient_vector_space()
+        V = self.vector_space()
         V1 = V.span_of_basis( (z**k).vector() for k in range(self.rank()) )
         b =  (V1.basis() + V1.complement().basis())
         return V.span_of_basis(b)
@@ -586,6 +670,19 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
         else:
             return self._rank
 
+    def vector_space(self):
+        """
+        Return the vector space that underlies this algebra.
+
+        EXAMPLES::
+
+            sage: J = RealSymmetricEJA(2)
+            sage: J.vector_space()
+            Vector space of dimension 3 over Rational Field
+
+        """
+        return self.zero().vector().parent().ambient_vector_space()
+
 
     class Element(FiniteDimensionalAlgebraElement):
         """
@@ -664,7 +761,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
 
                 sage: set_random_seed()
                 sage: x = random_eja().random_element()
-                sage: x.operator_matrix()*x.vector() == (x^2).vector()
+                sage: x.operator()(x) == (x^2)
                 True
 
             A few examples of power-associativity::
@@ -683,19 +780,18 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
                 sage: x = random_eja().random_element()
                 sage: m = ZZ.random_element(0,10)
                 sage: n = ZZ.random_element(0,10)
-                sage: Lxm = (x^m).operator_matrix()
-                sage: Lxn = (x^n).operator_matrix()
+                sage: Lxm = (x^m).operator()
+                sage: Lxn = (x^n).operator()
                 sage: Lxm*Lxn == Lxn*Lxm
                 True
 
             """
-            A = self.parent()
             if n == 0:
-                return A.one()
+                return self.parent().one()
             elif n == 1:
                 return self
             else:
-                return A( (self.operator_matrix()**(n-1))*self.vector() )
+                return (self.operator()**(n-1))(self)
 
 
         def apply_univariate_polynomial(self, p):
@@ -866,12 +962,63 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
                 sage: lhs == rhs
                 True
 
+            Test the first polarization identity from my notes, Koecher Chapter
+            III, or from Baes (2.3)::
+
+                sage: set_random_seed()
+                sage: J = random_eja()
+                sage: x = J.random_element()
+                sage: y = J.random_element()
+                sage: Lx = x.operator()
+                sage: Ly = y.operator()
+                sage: Lxx = (x*x).operator()
+                sage: Lxy = (x*y).operator()
+                sage: bool(2*Lx*Lxy + Ly*Lxx == 2*Lxy*Lx + Lxx*Ly)
+                True
+
+            Test the second polarization identity from my notes or from
+            Baes (2.4)::
+
+                sage: set_random_seed()
+                sage: J = random_eja()
+                sage: x = J.random_element()
+                sage: y = J.random_element()
+                sage: z = J.random_element()
+                sage: Lx = x.operator()
+                sage: Ly = y.operator()
+                sage: Lz = z.operator()
+                sage: Lzy = (z*y).operator()
+                sage: Lxy = (x*y).operator()
+                sage: Lxz = (x*z).operator()
+                sage: bool(Lx*Lzy + Lz*Lxy + Ly*Lxz == Lzy*Lx + Lxy*Lz + Lxz*Ly)
+                True
+
+            Test the third polarization identity from my notes or from
+            Baes (2.5)::
+
+                sage: set_random_seed()
+                sage: J = random_eja()
+                sage: u = J.random_element()
+                sage: y = J.random_element()
+                sage: z = J.random_element()
+                sage: Lu = u.operator()
+                sage: Ly = y.operator()
+                sage: Lz = z.operator()
+                sage: Lzy = (z*y).operator()
+                sage: Luy = (u*y).operator()
+                sage: Luz = (u*z).operator()
+                sage: Luyz = (u*(y*z)).operator()
+                sage: lhs = Lu*Lzy + Lz*Luy + Ly*Luz
+                sage: rhs = Luyz + Ly*Lu*Lz + Lz*Lu*Ly
+                sage: bool(lhs == rhs)
+                True
+
             """
             if not other in self.parent():
                 raise TypeError("'other' must live in the same algebra")
 
-            A = self.operator_matrix()
-            B = other.operator_matrix()
+            A = self.operator()
+            B = other.operator()
             return (A*B == B*A)
 
 
@@ -934,12 +1081,12 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
                 sage: n = ZZ.random_element(1,10)
                 sage: J = JordanSpinEJA(n)
                 sage: x = J.random_element()
-                sage: while x.is_zero():
+                sage: while not x.is_invertible():
                 ....:     x = J.random_element()
                 sage: x_vec = x.vector()
                 sage: x0 = x_vec[0]
                 sage: x_bar = x_vec[1:]
-                sage: coeff = 1/(x0^2 - x_bar.inner_product(x_bar))
+                sage: coeff = ~(x0^2 - x_bar.inner_product(x_bar))
                 sage: inv_vec = x_vec.parent()([x0] + (-x_bar).list())
                 sage: x_inverse = coeff*inv_vec
                 sage: x.inverse() == J(x_inverse)
@@ -982,8 +1129,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             if not self.is_invertible():
                 raise ValueError("element is not invertible")
 
-            P = self.parent()
-            return P(self.quadratic_representation().inverse()*self.vector())
+            return (~self.quadratic_representation())(self)
 
 
         def is_invertible(self):
@@ -1273,8 +1419,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
 
             """
             P = self.parent()
-            return FiniteDimensionalEuclideanJordanAlgebraMorphism(
-                     Hom(P,P),
+            return FiniteDimensionalEuclideanJordanAlgebraOperator(
+                     P,P,
                      self.operator_matrix() )
 
 
@@ -1289,55 +1435,13 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
 
             EXAMPLES:
 
-            Test the first polarization identity from my notes, Koecher Chapter
-            III, or from Baes (2.3)::
+            Ensure that our operator's ``matrix`` method agrees with
+            this implementation::
 
                 sage: set_random_seed()
                 sage: J = random_eja()
                 sage: x = J.random_element()
-                sage: y = J.random_element()
-                sage: Lx = x.operator_matrix()
-                sage: Ly = y.operator_matrix()
-                sage: Lxx = (x*x).operator_matrix()
-                sage: Lxy = (x*y).operator_matrix()
-                sage: bool(2*Lx*Lxy + Ly*Lxx == 2*Lxy*Lx + Lxx*Ly)
-                True
-
-            Test the second polarization identity from my notes or from
-            Baes (2.4)::
-
-                sage: set_random_seed()
-                sage: J = random_eja()
-                sage: x = J.random_element()
-                sage: y = J.random_element()
-                sage: z = J.random_element()
-                sage: Lx = x.operator_matrix()
-                sage: Ly = y.operator_matrix()
-                sage: Lz = z.operator_matrix()
-                sage: Lzy = (z*y).operator_matrix()
-                sage: Lxy = (x*y).operator_matrix()
-                sage: Lxz = (x*z).operator_matrix()
-                sage: bool(Lx*Lzy + Lz*Lxy + Ly*Lxz == Lzy*Lx + Lxy*Lz + Lxz*Ly)
-                True
-
-            Test the third polarization identity from my notes or from
-            Baes (2.5)::
-
-                sage: set_random_seed()
-                sage: J = random_eja()
-                sage: u = J.random_element()
-                sage: y = J.random_element()
-                sage: z = J.random_element()
-                sage: Lu = u.operator_matrix()
-                sage: Ly = y.operator_matrix()
-                sage: Lz = z.operator_matrix()
-                sage: Lzy = (z*y).operator_matrix()
-                sage: Luy = (u*y).operator_matrix()
-                sage: Luz = (u*z).operator_matrix()
-                sage: Luyz = (u*(y*z)).operator_matrix()
-                sage: lhs = Lu*Lzy + Lz*Luy + Ly*Luz
-                sage: rhs = Luyz + Ly*Lu*Lz + Lz*Lu*Ly
-                sage: bool(lhs == rhs)
+                sage: x.operator().matrix() == x.operator_matrix()
                 True
 
             """
@@ -1368,7 +1472,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
                 sage: D = (x0^2 - x_bar.inner_product(x_bar))*D
                 sage: D = D + 2*x_bar.tensor_product(x_bar)
                 sage: Q = block_matrix(2,2,[A,B,C,D])
-                sage: Q == x.quadratic_representation().operator_matrix()
+                sage: Q == x.quadratic_representation().matrix()
                 True
 
             Test all of the properties from Theorem 11.2 in Alizadeh::
@@ -1391,10 +1495,10 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
                 sage: 2*Qxy == (x+y).quadratic_representation() - Qx - Qy
                 True
 
-            Property 2:
+            Property 2 (multiply on the right for :trac:`28272`):
 
                 sage: alpha = QQ.random_element()
-                sage: (alpha*x).quadratic_representation() == (alpha^2)*Qx
+                sage: (alpha*x).quadratic_representation() == Qx*(alpha^2)
                 True
 
             Property 3:
@@ -1471,7 +1575,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
             #
             # We do the extra ambient_vector_space() in case we're messing
             # with polynomials and the direct parent is a module.
-            V = self.vector().parent().ambient_vector_space()
+            V = self.parent().vector_space()
             return V.span( (self**d).vector() for d in xrange(V.dimension()) )