]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_element.py
eja: factor out MatrixEJA initialization.
[sage.d.git] / mjo / eja / eja_element.py
index 9044860b8b8674c4110bde49edc2d46e9c999bfa..c98d9a2b64651562928a6489ef88e03fdd2b0dc9 100644 (file)
@@ -4,7 +4,7 @@ from sage.modules.free_module import VectorSpace
 from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement
 
 from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
-from mjo.eja.eja_utils import _mat2vec
+from mjo.eja.eja_utils import _mat2vec, _scale
 
 class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
     """
@@ -167,8 +167,8 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
             sage: J = HadamardEJA(3)
             sage: p1 = J.one().characteristic_polynomial()
             sage: q1 = J.zero().characteristic_polynomial()
-            sage: e0,e1,e2 = J.gens()
-            sage: A = (e0 + 2*e1 + 3*e2).subalgebra_generated_by() # dim 3
+            sage: b0,b1,b2 = J.gens()
+            sage: A = (b0 + 2*b1 + 3*b2).subalgebra_generated_by() # dim 3
             sage: p2 = A.one().characteristic_polynomial()
             sage: q2 = A.zero().characteristic_polynomial()
             sage: p1 == p2
@@ -348,7 +348,6 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         EXAMPLES::
 
             sage: J = JordanSpinEJA(2)
-            sage: e0,e1 = J.gens()
             sage: x = sum( J.gens() )
             sage: x.det()
             0
@@ -356,7 +355,6 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         ::
 
             sage: J = JordanSpinEJA(3)
-            sage: e0,e1,e2 = J.gens()
             sage: x = sum( J.gens() )
             sage: x.det()
             -1
@@ -391,7 +389,7 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
             sage: (x*y).det() == x.det()*y.det()
             True
 
-        The determinant in matrix algebras is just the usual determinant::
+        The determinant in real matrix algebras is the usual determinant::
 
             sage: set_random_seed()
             sage: X = matrix.random(QQ,3)
@@ -406,21 +404,6 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
             sage: actual2 == expected
             True
 
-        ::
-
-            sage: set_random_seed()
-            sage: J1 = ComplexHermitianEJA(2)
-            sage: J2 = ComplexHermitianEJA(2,field=QQ,orthonormalize=False)
-            sage: X = matrix.random(GaussianIntegers(), 2)
-            sage: X = X + X.H
-            sage: expected = AA(X.det())
-            sage: actual1 = J1(J1.real_embed(X)).det()
-            sage: actual2 = J2(J2.real_embed(X)).det()
-            sage: expected == actual1
-            True
-            sage: expected == actual2
-            True
-
         """
         P = self.parent()
         r = P.rank()
@@ -664,7 +647,7 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         element should always be in terms of minimal idempotents::
 
             sage: J = JordanSpinEJA(4)
-            sage: x = sum( i*J.gens()[i] for i in range(len(J.gens())) )
+            sage: x = sum( i*J.monomial(i) for i in range(len(J.gens())) )
             sage: x.is_regular()
             True
             sage: [ c.is_primitive_idempotent()
@@ -793,7 +776,9 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
             sage: J = JordanSpinEJA(5)
             sage: J.one().is_regular()
             False
-            sage: e0, e1, e2, e3, e4 = J.gens() # e0 is the identity
+            sage: b0, b1, b2, b3, b4 = J.gens()
+            sage: b0 == J.one()
+            True
             sage: for x in J.gens():
             ....:     (J.one() + x).is_regular()
             False
@@ -843,8 +828,8 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
             sage: J = JordanSpinEJA(4)
             sage: J.one().degree()
             1
-            sage: e0,e1,e2,e3 = J.gens()
-            sage: (e0 - e1).degree()
+            sage: b0,b1,b2,b3 = J.gens()
+            sage: (b0 - b1).degree()
             2
 
         In the spin factor algebra (of rank two), all elements that
@@ -910,7 +895,7 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         M = matrix([(self.parent().one()).to_vector()])
         old_rank = 1
 
-        # Specifying the row-reduction algorithm can e.g.  help over
+        # Specifying the row-reduction algorithm can e.g. help over
         # AA because it avoids the RecursionError that gets thrown
         # when we have to look too hard for a root.
         #
@@ -1047,19 +1032,30 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
 
         """
         if self.is_zero():
-            # We would generate a zero-dimensional subalgebra
-            # where the minimal polynomial would be constant.
-            # That might be correct, but only if *this* algebra
-            # is trivial too.
-            if not self.parent().is_trivial():
-                # Pretty sure we know what the minimal polynomial of
-                # the zero operator is going to be. This ensures
-                # consistency of e.g. the polynomial variable returned
-                # in the "normal" case without us having to think about it.
-                return self.operator().minimal_polynomial()
-
+            # Pretty sure we know what the minimal polynomial of
+            # the zero operator is going to be. This ensures
+            # consistency of e.g. the polynomial variable returned
+            # in the "normal" case without us having to think about it.
+            return self.operator().minimal_polynomial()
+
+        # If we don't orthonormalize the subalgebra's basis, then the
+        # first two monomials in the subalgebra will be self^0 and
+        # self^1... assuming that self^1 is not a scalar multiple of
+        # self^0 (the unit element). We special case these to avoid
+        # having to solve a system to coerce self into the subalgebra.
         A = self.subalgebra_generated_by(orthonormalize=False)
-        return A(self).operator().minimal_polynomial()
+
+        if A.dimension() == 1:
+            # Does a solve to find the scalar multiple alpha such that
+            # alpha*unit = self. We have to do this because the basis
+            # for the subalgebra will be [ self^0 ], and not [ self^1 ]!
+            unit = self.parent().one()
+            alpha = self.to_vector() / unit.to_vector()
+            return (unit.operator()*alpha).minimal_polynomial()
+        else:
+            # If the dimension of the subalgebra is >= 2, then we just
+            # use the second basis element.
+            return A.monomial(1).operator().minimal_polynomial()
 
 
 
@@ -1077,35 +1073,35 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         SETUP::
 
             sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
-            ....:                                  QuaternionHermitianEJA)
+            ....:                                  HadamardEJA,
+            ....:                                  QuaternionHermitianEJA,
+            ....:                                  RealSymmetricEJA)
 
         EXAMPLES::
 
             sage: J = ComplexHermitianEJA(3)
             sage: J.one()
-            e0 + e3 + e8
+            b0 + b3 + b8
             sage: J.one().to_matrix()
-            [1 0 0 0 0 0]
-            [0 1 0 0 0 0]
-            [0 0 1 0 0 0]
-            [0 0 0 1 0 0]
-            [0 0 0 0 1 0]
-            [0 0 0 0 0 1]
+            +---+---+---+
+            | 1 | 0 | 0 |
+            +---+---+---+
+            | 0 | 1 | 0 |
+            +---+---+---+
+            | 0 | 0 | 1 |
+            +---+---+---+
 
         ::
 
             sage: J = QuaternionHermitianEJA(2)
             sage: J.one()
-            e0 + e5
+            b0 + b5
             sage: J.one().to_matrix()
-            [1 0 0 0 0 0 0 0]
-            [0 1 0 0 0 0 0 0]
-            [0 0 1 0 0 0 0 0]
-            [0 0 0 1 0 0 0 0]
-            [0 0 0 0 1 0 0 0]
-            [0 0 0 0 0 1 0 0]
-            [0 0 0 0 0 0 1 0]
-            [0 0 0 0 0 0 0 1]
+            +---+---+
+            | 1 | 0 |
+            +---+---+
+            | 0 | 1 |
+            +---+---+
 
         This also works in Cartesian product algebras::
 
@@ -1123,14 +1119,13 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         B = self.parent().matrix_basis()
         W = self.parent().matrix_space()
 
-        if self.parent()._matrix_basis_is_cartesian:
+        if hasattr(W, 'cartesian_factors'):
             # Aaaaand linear combinations don't work in Cartesian
-            # product spaces, even though they provide a method
-            # with that name.
+            # product spaces, even though they provide a method with
+            # that name. This is hidden behind an "if" because the
+            # _scale() function is slow.
             pairs = zip(B, self.to_vector())
-            return sum( ( W(tuple(alpha*b_i for b_i in b))
-                          for (b,alpha) in pairs ),
-                        W.zero())
+            return W.sum( _scale(b, alpha) for (b,alpha) in pairs )
         else:
             # This is just a manual "from_vector()", but of course
             # matrix spaces aren't vector spaces in sage, so they
@@ -1343,11 +1338,11 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
 
             sage: J = RealSymmetricEJA(3)
             sage: J.one()
-            e0 + e2 + e5
+            b0 + b2 + b5
             sage: J.one().spectral_decomposition()
-            [(1, e0 + e2 + e5)]
+            [(1, b0 + b2 + b5)]
             sage: J.zero().spectral_decomposition()
-            [(0, e0 + e2 + e5)]
+            [(0, b0 + b2 + b5)]
 
         TESTS::
 
@@ -1372,13 +1367,13 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         The spectral decomposition should work in subalgebras, too::
 
             sage: J = RealSymmetricEJA(4)
-            sage: (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9) = J.gens()
-            sage: A = 2*e5 - 2*e8
+            sage: (b0, b1, b2, b3, b4, b5, b6, b7, b8, b9) = J.gens()
+            sage: A = 2*b5 - 2*b8
             sage: (lambda1, c1) = A.spectral_decomposition()[1]
             sage: (J0, J5, J1) = J.peirce_decomposition(c1)
             sage: (f0, f1, f2) = J1.gens()
             sage: f0.spectral_decomposition()
-            [(0, f2), (1, f0)]
+            [(0, c2), (1, c0)]
 
         """
         A = self.subalgebra_generated_by(orthonormalize=True)
@@ -1401,7 +1396,20 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
 
         SETUP::
 
-            sage: from mjo.eja.eja_algebra import random_eja
+            sage: from mjo.eja.eja_algebra import (random_eja,
+            ....:                                  HadamardEJA,
+            ....:                                  RealSymmetricEJA)
+
+        EXAMPLES:
+
+        We can create subalgebras of Cartesian product EJAs that are not
+        themselves Cartesian product EJAs (they're just "regular" EJAs)::
+
+            sage: J1 = HadamardEJA(3)
+            sage: J2 = RealSymmetricEJA(2)
+            sage: J = cartesian_product([J1,J2])
+            sage: J.one().subalgebra_generated_by()
+            Euclidean Jordan algebra of dimension 1 over Algebraic Real Field
 
         TESTS:
 
@@ -1435,7 +1443,11 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
 
         """
         powers = tuple( self**k for k in range(self.degree()) )
-        A = self.parent().subalgebra(powers, associative=True, **kwargs)
+        A = self.parent().subalgebra(powers,
+                                     associative=True,
+                                     check_field=False,
+                                     check_axioms=False,
+                                     **kwargs)
         A.one.set_cache(A(self.parent().one()))
         return A