]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_algebra.py
eja: fix inclusions/projections with trivial algebras.
[sage.d.git] / mjo / eja / eja_algebra.py
index d9a3abc7508e69424d4432ed64875cf17c01cac8..6252cc29a729472ef7f182cd3393ab3db98b6b58 100644 (file)
@@ -33,6 +33,7 @@ from sage.rings.all import (ZZ, QQ, AA, QQbar, RR, RLF, CLF,
 from mjo.eja.eja_element import FiniteDimensionalEuclideanJordanAlgebraElement
 lazy_import('mjo.eja.eja_subalgebra',
             'FiniteDimensionalEuclideanJordanSubalgebra')
+from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
 from mjo.eja.eja_utils import _mat2vec
 
 class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
@@ -1061,6 +1062,33 @@ class ConcreteEuclideanJordanAlgebra:
     rank, and so on are known a priori. More to the point, they are
     the Euclidean Jordan algebras for which we are able to conjure up
     a "random instance."
+
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import ConcreteEuclideanJordanAlgebra
+
+    TESTS:
+
+    Our natural basis is normalized with respect to the natural inner
+    product unless we specify otherwise::
+
+        sage: set_random_seed()
+        sage: J = ConcreteEuclideanJordanAlgebra.random_instance()
+        sage: all( b.norm() == 1 for b in J.gens() )
+        True
+
+    Since our natural basis is normalized with respect to the natural
+    inner product, and since we know that this algebra is an EJA, any
+    left-multiplication operator's matrix will be symmetric because
+    natural->EJA basis representation is an isometry and within the EJA
+    the operator is self-adjoint by the Jordan axiom::
+
+        sage: set_random_seed()
+        sage: J = ConcreteEuclideanJordanAlgebra.random_instance()
+        sage: x = J.random_element()
+        sage: x.operator().matrix().is_symmetric()
+        True
+
     """
 
     @staticmethod
@@ -1335,25 +1363,6 @@ class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra,
         sage: RealSymmetricEJA(3, prefix='q').gens()
         (q0, q1, q2, q3, q4, q5)
 
-    Our natural basis is normalized with respect to the natural inner
-    product unless we specify otherwise::
-
-        sage: set_random_seed()
-        sage: J = RealSymmetricEJA.random_instance()
-        sage: all( b.norm() == 1 for b in J.gens() )
-        True
-
-    Since our natural basis is normalized with respect to the natural
-    inner product, and since we know that this algebra is an EJA, any
-    left-multiplication operator's matrix will be symmetric because
-    natural->EJA basis representation is an isometry and within the EJA
-    the operator is self-adjoint by the Jordan axiom::
-
-        sage: set_random_seed()
-        sage: x = RealSymmetricEJA.random_instance().random_element()
-        sage: x.operator().matrix().is_symmetric()
-        True
-
     We can construct the (trivial) algebra of rank zero::
 
         sage: RealSymmetricEJA(0)
@@ -1623,25 +1632,6 @@ class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra,
         sage: ComplexHermitianEJA(2, prefix='z').gens()
         (z0, z1, z2, z3)
 
-    Our natural basis is normalized with respect to the natural inner
-    product unless we specify otherwise::
-
-        sage: set_random_seed()
-        sage: J = ComplexHermitianEJA.random_instance()
-        sage: all( b.norm() == 1 for b in J.gens() )
-        True
-
-    Since our natural basis is normalized with respect to the natural
-    inner product, and since we know that this algebra is an EJA, any
-    left-multiplication operator's matrix will be symmetric because
-    natural->EJA basis representation is an isometry and within the EJA
-    the operator is self-adjoint by the Jordan axiom::
-
-        sage: set_random_seed()
-        sage: x = ComplexHermitianEJA.random_instance().random_element()
-        sage: x.operator().matrix().is_symmetric()
-        True
-
     We can construct the (trivial) algebra of rank zero::
 
         sage: ComplexHermitianEJA(0)
@@ -1937,25 +1927,6 @@ class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra,
         sage: QuaternionHermitianEJA(2, prefix='a').gens()
         (a0, a1, a2, a3, a4, a5)
 
-    Our natural basis is normalized with respect to the natural inner
-    product unless we specify otherwise::
-
-        sage: set_random_seed()
-        sage: J = QuaternionHermitianEJA.random_instance()
-        sage: all( b.norm() == 1 for b in J.gens() )
-        True
-
-    Since our natural basis is normalized with respect to the natural
-    inner product, and since we know that this algebra is an EJA, any
-    left-multiplication operator's matrix will be symmetric because
-    natural->EJA basis representation is an isometry and within the EJA
-    the operator is self-adjoint by the Jordan axiom::
-
-        sage: set_random_seed()
-        sage: x = QuaternionHermitianEJA.random_instance().random_element()
-        sage: x.operator().matrix().is_symmetric()
-        True
-
     We can construct the (trivial) algebra of rank zero::
 
         sage: QuaternionHermitianEJA(0)
@@ -2448,7 +2419,8 @@ class DirectSumEJA(FiniteDimensionalEuclideanJordanAlgebra):
 
     SETUP::
 
-        sage: from mjo.eja.eja_algebra import (HadamardEJA,
+        sage: from mjo.eja.eja_algebra import (random_eja,
+        ....:                                  HadamardEJA,
         ....:                                  RealSymmetricEJA,
         ....:                                  DirectSumEJA)
 
@@ -2462,8 +2434,25 @@ class DirectSumEJA(FiniteDimensionalEuclideanJordanAlgebra):
         sage: J.rank()
         5
 
+    TESTS:
+
+    The external direct sum construction is only valid when the two factors
+    have the same base ring; an error is raised otherwise::
+
+        sage: set_random_seed()
+        sage: J1 = random_eja(AA)
+        sage: J2 = random_eja(QQ)
+        sage: J = DirectSumEJA(J1,J2)
+        Traceback (most recent call last):
+        ...
+        ValueError: algebras must share the same base field
+
     """
-    def __init__(self, J1, J2, field=AA, **kwargs):
+    def __init__(self, J1, J2, **kwargs):
+        if J1.base_ring() != J2.base_ring():
+            raise ValueError("algebras must share the same base field")
+        field = J1.base_ring()
+
         self._factors = (J1, J2)
         n1 = J1.dimension()
         n2 = J2.dimension()
@@ -2535,9 +2524,16 @@ class DirectSumEJA(FiniteDimensionalEuclideanJordanAlgebra):
 
         """
         (J1,J2) = self.factors()
-        n = J1.dimension()
-        pi_left  = lambda x: J1.from_vector(x.to_vector()[:n])
-        pi_right = lambda x: J2.from_vector(x.to_vector()[n:])
+        m = J1.dimension()
+        n = J2.dimension()
+        V_basis = self.vector_space().basis()
+        # Need to specify the dimensions explicitly so that we don't
+        # wind up with a zero-by-zero matrix when we want e.g. a
+        # zero-by-two matrix (important for composing things).
+        P1 = matrix(self.base_ring(), m, m+n, V_basis[:m])
+        P2 = matrix(self.base_ring(), n, m+n, V_basis[m:])
+        pi_left = FiniteDimensionalEuclideanJordanAlgebraOperator(self,J1,P1)
+        pi_right = FiniteDimensionalEuclideanJordanAlgebraOperator(self,J2,P2)
         return (pi_left, pi_right)
 
     def inclusions(self):
@@ -2546,7 +2542,8 @@ class DirectSumEJA(FiniteDimensionalEuclideanJordanAlgebra):
 
         SETUP::
 
-            sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+            sage: from mjo.eja.eja_algebra import (random_eja,
+            ....:                                  JordanSpinEJA,
             ....:                                  RealSymmetricEJA,
             ....:                                  DirectSumEJA)
 
@@ -2571,14 +2568,39 @@ class DirectSumEJA(FiniteDimensionalEuclideanJordanAlgebra):
             sage: J.one().to_vector()
             (1, 0, 0, 1, 0, 1)
 
+        TESTS:
+
+        Composing a projection with the corresponding inclusion should
+        produce the identity map, and mismatching them should produce
+        the zero map::
+
+            sage: set_random_seed()
+            sage: J1 = random_eja()
+            sage: J2 = random_eja()
+            sage: J = DirectSumEJA(J1,J2)
+            sage: (iota_left, iota_right) = J.inclusions()
+            sage: (pi_left, pi_right) = J.projections()
+            sage: pi_left*iota_left == J1.one().operator()
+            True
+            sage: pi_right*iota_right == J2.one().operator()
+            True
+            sage: (pi_left*iota_right).is_zero()
+            True
+            sage: (pi_right*iota_left).is_zero()
+            True
+
         """
         (J1,J2) = self.factors()
-        n = J1.dimension()
+        m = J1.dimension()
+        n = J2.dimension()
         V_basis = self.vector_space().basis()
-        I1 = matrix.column(self.base_ring(), V_basis[:n])
-        I2 = matrix.column(self.base_ring(), V_basis[n:])
-        iota_left = lambda x: self.from_vector(I1*x.to_vector())
-        iota_right = lambda x: self.from_vector(I2*+x.to_vector())
+        # Need to specify the dimensions explicitly so that we don't
+        # wind up with a zero-by-zero matrix when we want e.g. a
+        # two-by-zero matrix (important for composing things).
+        I1 = matrix.column(self.base_ring(), m, m+n, V_basis[:m])
+        I2 = matrix.column(self.base_ring(), n, m+n, V_basis[m:])
+        iota_left = FiniteDimensionalEuclideanJordanAlgebraOperator(J1,self,I1)
+        iota_right = FiniteDimensionalEuclideanJordanAlgebraOperator(J2,self,I2)
         return (iota_left, iota_right)
 
     def inner_product(self, x, y):
@@ -2597,7 +2619,7 @@ class DirectSumEJA(FiniteDimensionalEuclideanJordanAlgebra):
 
         EXAMPLE::
 
-            sage: J1 = HadamardEJA(3)
+            sage: J1 = HadamardEJA(3,QQ)
             sage: J2 = QuaternionHermitianEJA(2,QQ,normalize_basis=False)
             sage: J = DirectSumEJA(J1,J2)
             sage: x1 = J1.one()