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.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):
rank=None,
natural_basis=None):
"""
+ SETUP::
+
+ sage: from mjo.eja.eja_algebra import random_eja
+
EXAMPLES:
By definition, Jordan multiplication commutes::
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
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
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)
else:
return self._rank
+
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)
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::
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()
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')
"""
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
"""
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
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
"""
Return my determinant, the product of my eigenvalues.
+ SETUP::
+
+ sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+ ....: random_eja)
+
EXAMPLES::
sage: J = JordanSpinEJA(2)
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
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::
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::
"""
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
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)
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
"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)
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()
"""
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
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()
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()
"""
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)
"""
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::
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::
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()
"""
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()
"""
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()
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')
"""
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],
``[[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)
"""
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],
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)
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`::
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`::
(<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::
--- /dev/null
+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')