"""
from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis
-from sage.categories.morphism import SetMorphism
-from sage.modules.vector_space_morphism import VectorSpaceMorphism
+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_element import FiniteDimensionalAlgebraElement
-class FiniteDimensionalEuclideanJordanAlgebraOperator(VectorSpaceMorphism):
+class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
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):
+ 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.
+ 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.
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)
+ return self.codomain()(self.matrix()*x.vector())
- def __add__(self, other):
+ def _add_(self, other):
"""
Add the ``other`` EJA operator to this one.
sage: f + g
Traceback (most recent call last):
...
- ValueError: operator (co)domains must match
+ TypeError: unsupported operand parent(s) for +: ...
"""
- 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))
+ 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):
"""
"""
return FiniteDimensionalEuclideanJordanAlgebraOperator(
- self._codomain_eja,
- self._domain_eja,
- VectorSpaceMorphism.__invert__(self))
+ self.codomain(),
+ self.domain(),
+ ~self.matrix())
+
def __mul__(self, other):
"""
- Compose this EJA operator with the ``other`` one, or scale it by
- an element of its base ring.
+ 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_eja.base_ring():
+ if other in self.codomain().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")
+ self.domain(),
+ self.codomain(),
+ self.matrix()*other)
- return FiniteDimensionalEuclideanJordanAlgebraOperator(
- other._domain_eja,
- self._codomain_eja,
- VectorSpaceMorphism.__mul__(self,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):
+ def _neg_(self):
"""
Negate this EJA operator.
"""
return FiniteDimensionalEuclideanJordanAlgebraOperator(
- self._domain_eja,
- self._codomain_eja,
- VectorSpaceMorphism.__neg__(self))
+ self.domain(),
+ self.codomain(),
+ -self.matrix())
def __pow__(self, n):
cols = self.domain().dimension()
mat = matrix.identity(self.base_ring(), rows, cols)
else:
- mat = VectorSpaceMorphism.__pow__(self,n)
+ mat = self.matrix()**n
return FiniteDimensionalEuclideanJordanAlgebraOperator(
- self._domain_eja,
- self._codomain_eja,
+ self.domain(),
+ self.codomain(),
mat)
- def __sub__(self, other):
+
+ 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
+
+
class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra):
@staticmethod
def __classcall_private__(cls,