- 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
- inner product on `R^n` (this example only works because the
- basis for the Jordan algebra is the standard basis in `R^n`)::
-
- sage: J = JordanSpinEJA(3)
- sage: x = vector(QQ,[1,2,3])
- sage: y = vector(QQ,[4,5,6])
- sage: x.inner_product(y)
- 32
- sage: J(x).inner_product(J(y))
- 32
-
- The inner product on `S^n` is `<X,Y> = trace(X*Y)`, where
- multiplication is the usual matrix multiplication in `S^n`,
- so the inner product of the identity matrix with itself
- should be the `n`::
-
- sage: J = RealSymmetricEJA(3)
- sage: J.one().inner_product(J.one())
- 3
-
- Likewise, the inner product on `C^n` is `<X,Y> =
- Re(trace(X*Y))`, where we must necessarily take the real
- part because the product of Hermitian matrices may not be
- Hermitian::
-
- sage: J = ComplexHermitianEJA(3)
- sage: J.one().inner_product(J.one())
- 3
-
- Ditto for the quaternions::
-
- sage: J = QuaternionHermitianEJA(3)
- sage: J.one().inner_product(J.one())
- 3
-
- TESTS:
-
- Ensure that we can always compute an inner product, and that
- it gives us back a real number::
-
- sage: set_random_seed()
- sage: J = random_eja()
- sage: x = J.random_element()
- sage: y = J.random_element()
- sage: x.inner_product(y) in RR
- True
-
- """
- P = self.parent()
- if not other in P:
- raise TypeError("'other' must live in the same algebra")
-
- return P.inner_product(self, other)
-
-
- def operator_commutes_with(self, other):
- """
- 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
- operator-commutes with its square::
-
- sage: set_random_seed()
- sage: x = random_eja().random_element()
- sage: x.operator_commutes_with(x^2)
- True
-
- TESTS:
-
- Test Lemma 1 from Chapter III of Koecher::
-
- sage: set_random_seed()
- sage: J = random_eja()
- sage: u = J.random_element()
- sage: v = J.random_element()
- sage: lhs = u.operator_commutes_with(u*v)
- sage: rhs = v.operator_commutes_with(u^2)
- 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()
- B = other.operator()
- return (A*B == B*A)
-
-
- def det(self):
- """
- Return my determinant, the product of my eigenvalues.
-
- SETUP::
-
- sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
- ....: random_eja)
-
- EXAMPLES::
-
- sage: J = JordanSpinEJA(2)
- sage: e0,e1 = J.gens()
- sage: x = sum( J.gens() )
- sage: x.det()
- 0
-
- ::
-
- sage: J = JordanSpinEJA(3)
- sage: e0,e1,e2 = J.gens()
- sage: x = sum( J.gens() )
- sage: x.det()
- -1
-
- TESTS:
-
- An element is invertible if and only if its determinant is
- non-zero::
-
- sage: set_random_seed()
- sage: x = random_eja().random_element()
- sage: x.is_invertible() == (x.det() != 0)
- True
-
- """
- P = self.parent()
- r = P.rank()
- p = P._charpoly_coeff(0)
- # The _charpoly_coeff function already adds the factor of
- # -1 to ensure that _charpoly_coeff(0) is really what
- # appears in front of t^{0} in the charpoly. However,
- # we want (-1)^r times THAT for the determinant.
- return ((-1)**r)*p(*self.vector())
-
-
- def inverse(self):
- """
- Return the Jordan-multiplicative inverse of this element.
-
- ALGORITHM:
-
- 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
- Example 11.11::
-
- sage: set_random_seed()
- sage: n = ZZ.random_element(1,10)
- sage: J = JordanSpinEJA(n)
- sage: x = J.random_element()
- 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 = ~(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)
- True
-
- TESTS:
-
- The identity element is its own inverse::
-
- sage: set_random_seed()
- sage: J = random_eja()
- sage: J.one().inverse() == J.one()
- True
-
- If an element has an inverse, it acts like one::
-
- sage: set_random_seed()
- sage: J = random_eja()
- sage: x = J.random_element()
- sage: (not x.is_invertible()) or (x.inverse()*x == J.one())
- True
-
- The inverse of the inverse is what we started with::
-
- sage: set_random_seed()
- sage: J = random_eja()
- sage: x = J.random_element()
- sage: (not x.is_invertible()) or (x.inverse().inverse() == x)
- True
-
- The zero element is never invertible::
-
- sage: set_random_seed()
- sage: J = random_eja().zero().inverse()
- Traceback (most recent call last):
- ...
- ValueError: element is not invertible
-
- """
- if not self.is_invertible():
- raise ValueError("element is not invertible")
-
- return (~self.quadratic_representation())(self)
-
-
- def is_invertible(self):
- """
- Return whether or not this element is invertible.
-
- We can't use the superclass method because it relies on
- the algebra being associative.
-
- ALGORITHM:
-
- The usual way to do this is to check if the determinant is
- zero, but we need the characteristic polynomial for the
- determinant. The minimal polynomial is a lot easier to get,
- so we use Corollary 2 in Chapter V of Koecher to check
- 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::
-
- sage: set_random_seed()
- sage: J = random_eja()
- sage: J.one().is_invertible()
- True
-
- The zero element is never invertible::
-
- sage: set_random_seed()
- sage: J = random_eja()
- sage: J.zero().is_invertible()
- False
-
- """
- zero = self.parent().zero()
- p = self.minimal_polynomial()
- return not (p(zero) == zero)
-
-
- def is_nilpotent(self):
- """
- Return whether or not some power of this element is zero.
-
- The superclass method won't work unless we're in an
- associative algebra, and we aren't. However, we generate
- an assocoative subalgebra and we're nilpotent there if and
- only if we're nilpotent here (probably).
-
- SETUP::