+
+class FiniteDimensionalEuclideanJordanAlgebraOperator(VectorSpaceMorphism):
+ def __init__(self, domain_eja, codomain_eja, mat):
+ # We save these so that we can output them as part of our
+ # text representation. Overriding the domain/codomain methods
+ # doesn't work because the EJAs aren't (directly) vector spaces.
+ self._domain_eja = domain_eja
+ self._codomain_eja = codomain_eja
+
+ # Otherwise, we just feed everything to the vector space morphism
+ # constructor.
+ V = domain_eja.vector_space()
+ W = codomain_eja.vector_space()
+ homspace = V.Hom(W)
+ VectorSpaceMorphism.__init__(self, homspace, 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
+
+ """
+ # Overriding the single-underscore _call_ didn't work?
+ if x not in self._domain_eja:
+ raise ValueError("argument does not live in the operator's domain")
+ return self._codomain_eja(self.matrix()*x.vector())
+
+
+ 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_eja,
+ self._codomain_eja)
+
+
+ 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):
+ ...
+ ValueError: operator (co)domains must match
+
+ """
+ if not (self._domain_eja == other._domain_eja and
+ self._codomain_eja == other._codomain_eja):
+ raise ValueError("operator (co)domains must match")
+ return FiniteDimensionalEuclideanJordanAlgebraOperator(
+ self._domain_eja,
+ self._codomain_eja,
+ VectorSpaceMorphism.__add__(self,other))
+
+
+ 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_eja,
+ self._domain_eja,
+ VectorSpaceMorphism.__invert__(self))
+
+ def __mul__(self, other):
+ """
+ Compose this EJA operator with the ``other`` one, or scale it by
+ an element of its base ring.
+ """
+ if other in self._codomain_eja.base_ring():
+ return FiniteDimensionalEuclideanJordanAlgebraOperator(
+ self._domain_eja,
+ self._codomain_eja,
+ self._matrix*other)
+
+ if not (self._domain_eja == other._codomain_eja):
+ raise ValueError("operator (co)domains must be compatible")
+
+ return FiniteDimensionalEuclideanJordanAlgebraOperator(
+ other._domain_eja,
+ self._codomain_eja,
+ VectorSpaceMorphism.__mul__(self,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_eja,
+ self._codomain_eja,
+ VectorSpaceMorphism.__neg__(self))
+
+
+ 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 = VectorSpaceMorphism.__pow__(self,n)
+
+ return FiniteDimensionalEuclideanJordanAlgebraOperator(
+ self._domain_eja,
+ self._codomain_eja,
+ mat)
+
+ def __sub__(self, other):
+ """
+ Subtract ``other`` from this EJA operator.
+ """
+ return (self + (-other))
+
+