+ # 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))
+
+ # 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):