]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_element.py
eja: define the trace of an element in a trivial algebra.
[sage.d.git] / mjo / eja / eja_element.py
index ee33e4ba89fcc3c47be1f9467042dae5e678c859..bd45b179541487bd82e3b06768a902a77cd0899d 100644 (file)
@@ -430,6 +430,13 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             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::
@@ -455,14 +462,6 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             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::
@@ -574,10 +573,11 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
         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::
@@ -621,11 +621,11 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
         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
@@ -633,7 +633,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
             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
 
         """
@@ -677,14 +677,17 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
         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::
 
@@ -1040,6 +1043,69 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
 
 
+    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):
         """
@@ -1077,13 +1143,15 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: A(x^2) == A(x)*A(x)
             True
 
-        By definition, the subalgebra generated by the zero element is the
-        one-dimensional algebra generated by the identity element::
+        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.dimension()
-            1
+            sage: (A.is_trivial() and A.dimension() == 0) or A.dimension() == 1
+            True
 
         """
         return FiniteDimensionalEuclideanJordanElementSubalgebra(self, orthonormalize_basis)
@@ -1180,6 +1248,12 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
         """
         P = self.parent()
         r = P.rank()
+
+        if r == 0:
+            # Special case for the trivial algebra where
+            # the trace is an empty sum.
+            return P.base_ring().zero()
+
         p = P._charpoly_coeff(r-1)
         # The _charpoly_coeff function already adds the factor of
         # -1 to ensure that _charpoly_coeff(r-1) is really what