]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_element.py
eja: speed up det() for Cartesian product elements.
[sage.d.git] / mjo / eja / eja_element.py
index ff25b82073a85f9b2f92301d69f37455f231f5ea..47f6ff080c1d48a1a32b4903991aa0ec5bd0a502 100644 (file)
@@ -4,7 +4,8 @@ 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, _scale
+from mjo.eja.eja_utils import _scale
+
 
 class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
     """
@@ -131,7 +132,8 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
 
         SETUP::
 
-            sage: from mjo.eja.eja_algebra import HadamardEJA
+            sage: from mjo.eja.eja_algebra import (random_eja,
+            ....:                                  HadamardEJA)
 
         EXAMPLES:
 
@@ -156,10 +158,10 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         to zero on that element::
 
             sage: set_random_seed()
-            sage: x = HadamardEJA(3).random_element()
+            sage: x = random_eja().random_element()
             sage: p = x.characteristic_polynomial()
-            sage: x.apply_univariate_polynomial(p)
-            0
+            sage: x.apply_univariate_polynomial(p).is_zero()
+            True
 
         The characteristic polynomials of the zero and unit elements
         should be what we think they are in a subalgebra, too::
@@ -389,7 +391,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)
@@ -404,21 +406,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()
@@ -1008,8 +995,8 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         two here so that said elements actually exist::
 
             sage: set_random_seed()
-            sage: n_max = max(2, JordanSpinEJA._max_random_instance_size())
-            sage: n = ZZ.random_element(2, n_max)
+            sage: d_max = JordanSpinEJA._max_random_instance_dimension()
+            sage: n = ZZ.random_element(2, max(2,d_max))
             sage: J = JordanSpinEJA(n)
             sage: y = J.random_element()
             sage: while y == y.coefficient(0)*J.one():
@@ -1034,8 +1021,9 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         and in particular, a re-scaling of the basis::
 
             sage: set_random_seed()
-            sage: n_max = RealSymmetricEJA._max_random_instance_size()
-            sage: n = ZZ.random_element(1, n_max)
+            sage: d_max = RealSymmetricEJA._max_random_instance_dimension()
+            sage: d = ZZ.random_element(1, d_max)
+            sage: n = RealSymmetricEJA._max_random_instance_size(d)
             sage: J1 = RealSymmetricEJA(n)
             sage: J2 = RealSymmetricEJA(n,orthonormalize=False)
             sage: X = random_matrix(AA,n)
@@ -1098,12 +1086,13 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
             sage: J.one()
             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 |
+            +---+---+---+
 
         ::
 
@@ -1111,14 +1100,11 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
             sage: J.one()
             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::
 
@@ -1136,18 +1122,10 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         B = self.parent().matrix_basis()
         W = self.parent().matrix_space()
 
-        if hasattr(W, 'cartesian_factors'):
-            # Aaaaand linear combinations don't work in Cartesian
-            # 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 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
-            # don't have a from_vector() method.
-            return W.linear_combination( zip(B, self.to_vector()) )
+        # This is just a manual "from_vector()", but of course
+        # matrix spaces aren't vector spaces in sage, so they
+        # don't have a from_vector() method.
+        return W.linear_combination( zip(B, self.to_vector()) )
 
 
 
@@ -1390,7 +1368,7 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
             sage: (J0, J5, J1) = J.peirce_decomposition(c1)
             sage: (f0, f1, f2) = J1.gens()
             sage: f0.spectral_decomposition()
-            [(0, c2), (1, c0)]
+            [(0, 1.000000000000000?*c2), (1, 1.000000000000000?*c0)]
 
         """
         A = self.subalgebra_generated_by(orthonormalize=True)
@@ -1665,3 +1643,29 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
 
         """
         return self.trace_inner_product(self).sqrt()
+
+
+class CartesianProductEJAElement(FiniteDimensionalEJAElement):
+    def det(self):
+        r"""
+        Compute the determinant of this product-element using the
+        determianants of its factors.
+
+        This result Follows from the spectral decomposition of (say)
+        the pair `(x,y)` in terms of the Jordan frame `\left\{ (c_1,
+        0),(c_2, 0),...,(0,d_1),(0,d_2),... \right\}.
+        """
+        from sage.misc.misc_c import prod
+        return prod( f.det() for f in self.cartesian_factors() )
+
+    def to_matrix(self):
+        # An override is necessary to call our custom _scale().
+        B = self.parent().matrix_basis()
+        W = self.parent().matrix_space()
+
+        # Aaaaand linear combinations don't work in Cartesian
+        # 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 W.sum( _scale(b, alpha) for (b,alpha) in pairs )