]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_operator.py
eja: add a new TrivialEJA class and some tests for it.
[sage.d.git] / mjo / eja / eja_operator.py
index c32ff1ed7c2ba0aa87c842e5545f9bf204f43fac..2a0c9c48633cd06551c49515840680b57a5b927d 100644 (file)
@@ -383,6 +383,104 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
         return (self + (-other))
 
 
+    def inverse(self):
+        """
+        Return the inverse of this operator, if it exists.
+
+        The reason this method is not simply an alias for the built-in
+        :meth:`__invert__` is that the built-in inversion is a bit magic
+        since it's intended to be a unary operator. If we alias ``inverse``
+        to ``__invert__``, then we wind up having to call e.g. ``A.inverse``
+        without parentheses.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import RealSymmetricEJA, random_eja
+
+        EXAMPLES::
+
+            sage: J = RealSymmetricEJA(2)
+            sage: x = sum(J.gens())
+            sage: x.operator().inverse().matrix()
+            [3/2  -1 1/2]
+            [ -1   2  -1]
+            [1/2  -1 3/2]
+            sage: x.operator().matrix().inverse()
+            [3/2  -1 1/2]
+            [ -1   2  -1]
+            [1/2  -1 3/2]
+
+        TESTS:
+
+        The identity operator is its own inverse::
+
+            sage: set_random_seed()
+            sage: J = random_eja()
+            sage: idJ = J.one().operator()
+            sage: idJ.inverse() == idJ
+            True
+
+        The inverse of the inverse is the operator we started with::
+
+            sage: set_random_seed()
+            sage: x = random_eja().random_element()
+            sage: L = x.operator()
+            sage: not L.is_invertible() or (L.inverse().inverse() == L)
+            True
+
+        """
+        return ~self
+
+
+    def is_invertible(self):
+        """
+        Return whether or not this operator is invertible.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import (RealSymmetricEJA,
+            ....:                                  TrivialEJA,
+            ....:                                  random_eja)
+
+        EXAMPLES::
+
+            sage: J = RealSymmetricEJA(2)
+            sage: x = sum(J.gens())
+            sage: x.operator().matrix()
+            [  1 1/2   0]
+            [1/2   1 1/2]
+            [  0 1/2   1]
+            sage: x.operator().matrix().is_invertible()
+            True
+            sage: x.operator().is_invertible()
+            True
+
+        The zero operator is invertible in a trivial algebra::
+
+            sage: J = TrivialEJA()
+            sage: J.zero().operator().is_invertible()
+            True
+
+        TESTS:
+
+        The identity operator is always invertible::
+
+            sage: set_random_seed()
+            sage: J = random_eja()
+            sage: J.one().operator().is_invertible()
+            True
+
+        The zero operator is never invertible in a nontrivial algebra::
+
+            sage: set_random_seed()
+            sage: J = random_eja()
+            sage: not J.is_trivial() and J.zero().operator().is_invertible()
+            False
+
+        """
+        return self.matrix().is_invertible()
+
+
     def matrix(self):
         """
         Return the matrix representation of this operator with respect
@@ -433,6 +531,11 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
         Return the spectral decomposition of this operator as a list of
         (eigenvalue, orthogonal projector) pairs.
 
+        This is the unique spectral decomposition, up to the order of
+        the projection operators, with distinct eigenvalues. So, the
+        projections are generally onto subspaces of dimension greater
+        than one.
+
         SETUP::
 
             sage: from mjo.eja.eja_algebra import RealSymmetricEJA
@@ -443,8 +546,22 @@ class FiniteDimensionalEuclideanJordanAlgebraOperator(Map):
             sage: x = sum(J.gens())
             sage: A = x.subalgebra_generated_by(orthonormalize_basis=True)
             sage: L0x = A(x).operator()
-            sage: Ps = [ P*l for (l,P) in L0x.spectral_decomposition() ]
-            sage: Ps[0] + Ps[1] == L0x
+            sage: sd = L0x.spectral_decomposition()
+            sage: l0 = sd[0][0]
+            sage: l1 = sd[1][0]
+            sage: P0 = sd[0][1]
+            sage: P1 = sd[1][1]
+            sage: P0*l0 + P1*l1 == L0x
+            True
+            sage: P0 + P1 == P0^0 # the identity
+            True
+            sage: P0^2 == P0
+            True
+            sage: P1^2 == P1
+            True
+            sage: P0*P1 == A.zero().operator()
+            True
+            sage: P1*P0 == A.zero().operator()
             True
 
         """