SETUP::
- sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+ sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
+ ....: JordanSpinEJA,
....: random_eja)
EXAMPLES:
sage: x.inverse() == J.from_vector(x_inverse)
True
+ Trying to invert a non-invertible element throws an error:
+
+ sage: JordanSpinEJA(3).zero().inverse()
+ Traceback (most recent call last):
+ ...
+ ValueError: element is not invertible
+
TESTS:
The identity element is its own inverse::
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
-
Proposition II.2.3 in Faraut and Korányi says that the inverse
of an element is the inverse of its left-multiplication operator
applied to the algebra's identity, when that inverse exists::
....: x.operator().inverse()(J.one()) == x.inverse() )
True
+ Proposition II.2.4 in Faraut and Korányi gives a formula for
+ the inverse based on the characteristic polynomial and the
+ Cayley-Hamilton theorem for Euclidean Jordan algebras::
+
+ sage: set_random_seed()
+ sage: J = ComplexHermitianEJA(3)
+ sage: x = J.random_element()
+ sage: while not x.is_invertible():
+ ....: x = J.random_element()
+ sage: r = J.rank()
+ sage: a = x.characteristic_polynomial().coefficients(sparse=False)
+ sage: expected = (-1)^(r+1)/x.det()
+ sage: expected *= sum( a[i+1]*x^i for i in range(r) )
+ sage: x.inverse() == expected
+ True
+
"""
if not self.is_invertible():
raise ValueError("element is not invertible")
TESTS:
- The identity element is never nilpotent::
+ The identity element is never nilpotent, except in a trivial EJA::
sage: set_random_seed()
- sage: random_eja().one().is_nilpotent()
+ sage: J = random_eja()
+ sage: J.one().is_nilpotent() and not J.is_trivial()
False
The additive identity is always nilpotent::
TESTS:
The zero element should never be regular, unless the parent
- algebra has dimension one::
+ algebra has dimension less than or equal to one::
sage: set_random_seed()
sage: J = random_eja()
- sage: J.dimension() == 1 or not J.zero().is_regular()
+ sage: J.dimension() <= 1 or not J.zero().is_regular()
True
The unit element isn't regular unless the algebra happens to
sage: set_random_seed()
sage: J = random_eja()
- sage: J.dimension() == 1 or not J.one().is_regular()
+ sage: J.dimension() <= 1 or not J.one().is_regular()
True
"""
TESTS:
- The zero and unit elements are both of degree one::
+ The zero and unit elements are both of degree one in nontrivial
+ algebras::
sage: set_random_seed()
sage: J = random_eja()
- sage: J.zero().degree()
- 1
- sage: J.one().degree()
- 1
+ sage: d = J.zero().degree()
+ sage: (J.is_trivial() and d == 0) or d == 1
+ True
+ sage: d = J.one().degree()
+ sage: (J.is_trivial() and d == 0) or d == 1
+ True
Our implementation agrees with the definition::
+ def spectral_decomposition(self):
+ """
+ Return the unique spectral decomposition of this element.
+
+ ALGORITHM:
+
+ Following Faraut and Korányi's Theorem III.1.1, we restrict this
+ element's left-multiplication-by operator to the subalgebra it
+ generates. We then compute the spectral decomposition of that
+ operator, and the spectral projectors we get back must be the
+ left-multiplication-by operators for the idempotents we
+ seek. Thus applying them to the identity element gives us those
+ idempotents.
+
+ Since the eigenvalues are required to be distinct, we take
+ the spectral decomposition of the zero element to be zero
+ times the identity element of the algebra (which is idempotent,
+ obviously).
+
+ SETUP::
+
+ sage: from mjo.eja.eja_algebra import RealSymmetricEJA
+
+ EXAMPLES:
+
+ The spectral decomposition of the identity is ``1`` times itself,
+ and the spectral decomposition of zero is ``0`` times the identity::
+
+ sage: J = RealSymmetricEJA(3,AA)
+ sage: J.one()
+ e0 + e2 + e5
+ sage: J.one().spectral_decomposition()
+ [(1, e0 + e2 + e5)]
+ sage: J.zero().spectral_decomposition()
+ [(0, e0 + e2 + e5)]
+
+ TESTS::
+
+ sage: J = RealSymmetricEJA(4,AA)
+ sage: x = sum(J.gens())
+ sage: sd = x.spectral_decomposition()
+ sage: l0 = sd[0][0]
+ sage: l1 = sd[1][0]
+ sage: c0 = sd[0][1]
+ sage: c1 = sd[1][1]
+ sage: c0.inner_product(c1) == 0
+ True
+ sage: c0.is_idempotent()
+ True
+ sage: c1.is_idempotent()
+ True
+ sage: c0 + c1 == J.one()
+ True
+ sage: l0*c0 + l1*c1 == x
+ True
+
+ """
+ P = self.parent()
+ A = self.subalgebra_generated_by(orthonormalize_basis=True)
+ result = []
+ for (evalue, proj) in A(self).operator().spectral_decomposition():
+ result.append( (evalue, proj(A.one()).superalgebra_element()) )
+ return result
def subalgebra_generated_by(self, orthonormalize_basis=False):
"""
Return the associative subalgebra of the parent EJA generated
by this element.
+ Since our parent algebra is unital, we want "subalgebra" to mean
+ "unital subalgebra" as well; thus the subalgebra that an element
+ generates will itself be a Euclidean Jordan algebra after
+ restricting the algebra operations appropriately. This is the
+ subalgebra that Faraut and Korányi work with in section II.2, for
+ example.
+
SETUP::
sage: from mjo.eja.eja_algebra import random_eja
sage: A(x^2) == A(x)*A(x)
True
- The subalgebra generated by the zero element is trivial::
+ By definition, the subalgebra generated by the zero element is
+ the one-dimensional algebra generated by the identity
+ element... unless the original algebra was trivial, in which
+ case the subalgebra is trivial too::
sage: set_random_seed()
sage: A = random_eja().zero().subalgebra_generated_by()
- sage: A
- Euclidean Jordan algebra of dimension 0 over...
- sage: A.one()
- 0
+ sage: (A.is_trivial() and A.dimension() == 0) or A.dimension() == 1
+ True
"""
return FiniteDimensionalEuclideanJordanElementSubalgebra(self, orthonormalize_basis)