]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_element.py
eja: fix one more positional "field" argument.
[sage.d.git] / mjo / eja / eja_element.py
index de12bb10604094e9b90ffb89a335514c4811d2aa..9fa8176d112668d6fed446ba5c174c7ebf618fbc 100644 (file)
@@ -1,14 +1,7 @@
-# -*- coding: utf-8 -*-
-
 from sage.matrix.constructor import matrix
 from sage.modules.free_module import VectorSpace
 from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement
 
 from sage.matrix.constructor import matrix
 from sage.modules.free_module import VectorSpace
 from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement
 
-# TODO: make this unnecessary somehow.
-from sage.misc.lazy_import import lazy_import
-lazy_import('mjo.eja.eja_algebra', 'FiniteDimensionalEuclideanJordanAlgebra')
-lazy_import('mjo.eja.eja_element_subalgebra',
-            'FiniteDimensionalEuclideanJordanElementSubalgebra')
 from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
 from mjo.eja.eja_utils import _mat2vec
 
 from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
 from mjo.eja.eja_utils import _mat2vec
 
@@ -183,7 +176,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             True
 
         """
             True
 
         """
-        p = self.parent().characteristic_polynomial()
+        p = self.parent().characteristic_polynomial_of()
         return p(*self.to_vector())
 
 
         return p(*self.to_vector())
 
 
@@ -347,6 +340,8 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
             sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
             ....:                                  TrivialEJA,
 
             sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
             ....:                                  TrivialEJA,
+            ....:                                  RealSymmetricEJA,
+            ....:                                  ComplexHermitianEJA,
             ....:                                  random_eja)
 
         EXAMPLES::
             ....:                                  random_eja)
 
         EXAMPLES::
@@ -394,6 +389,37 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: x,y = J.random_elements(2)
             sage: (x*y).det() == x.det()*y.det()
             True
             sage: x,y = J.random_elements(2)
             sage: (x*y).det() == x.det()*y.det()
             True
+
+        The determinant in matrix algebras is just the usual determinant::
+
+            sage: set_random_seed()
+            sage: X = matrix.random(QQ,3)
+            sage: X = X + X.T
+            sage: J1 = RealSymmetricEJA(3)
+            sage: J2 = RealSymmetricEJA(3,field=QQ,orthonormalize=False)
+            sage: expected = X.det()
+            sage: actual1 = J1(X).det()
+            sage: actual2 = J2(X).det()
+            sage: actual1 == expected
+            True
+            sage: actual2 == expected
+            True
+
+        ::
+
+            sage: set_random_seed()
+            sage: J1 = ComplexHermitianEJA(3)
+            sage: J2 = ComplexHermitianEJA(3,field=QQ,orthonormalize=False)
+            sage: X = matrix.random(GaussianIntegers(),3)
+            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()
         """
         P = self.parent()
         r = P.rank()
@@ -509,6 +535,14 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
         if not self.is_invertible():
             raise ValueError("element is not invertible")
 
         if not self.is_invertible():
             raise ValueError("element is not invertible")
 
+        if self.parent()._charpoly_coefficients.is_in_cache():
+            # We can invert using our charpoly if it will be fast to
+            # compute. If the coefficients are cached, our rank had
+            # better be too!
+            r = self.parent().rank()
+            a = self.characteristic_polynomial().coefficients(sparse=False)
+            return (-1)**(r+1)*sum(a[i+1]*self**i for i in range(r))/self.det()
+
         return (~self.quadratic_representation())(self)
 
 
         return (~self.quadratic_representation())(self)
 
 
@@ -522,9 +556,14 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
         zero, but we need the characteristic polynomial for the
         determinant. The minimal polynomial is a lot easier to get,
         so we use Corollary 2 in Chapter V of Koecher to check
         zero, but we need the characteristic polynomial for the
         determinant. The minimal polynomial is a lot easier to get,
         so we use Corollary 2 in Chapter V of Koecher to check
-        whether or not the paren't algebra's zero element is a root
+        whether or not the parent algebra's zero element is a root
         of this element's minimal polynomial.
 
         of this element's minimal polynomial.
 
+        That is... unless the coefficients of our algebra's
+        "characteristic polynomial of" function are already cached!
+        In that case, we just use the determinant (which will be fast
+        as a result).
+
         Beware that we can't use the superclass method, because it
         relies on the algebra being associative.
 
         Beware that we can't use the superclass method, because it
         relies on the algebra being associative.
 
@@ -555,6 +594,11 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             else:
                 return False
 
             else:
                 return False
 
+        if self.parent()._charpoly_coefficients.is_in_cache():
+            # The determinant will be quicker than computing the minimal
+            # polynomial from scratch, most likely.
+            return (not self.det().is_zero())
+
         # In fact, we only need to know if the constant term is non-zero,
         # so we can pass in the field's zero element instead.
         zero = self.base_ring().zero()
         # In fact, we only need to know if the constant term is non-zero,
         # so we can pass in the field's zero element instead.
         zero = self.base_ring().zero()
@@ -796,8 +840,9 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
             sage: set_random_seed()
             sage: J = JordanSpinEJA.random_instance()
 
             sage: set_random_seed()
             sage: J = JordanSpinEJA.random_instance()
+            sage: n = J.dimension()
             sage: x = J.random_element()
             sage: x = J.random_element()
-            sage: x == x.coefficient(0)*J.one() or x.degree() == 2
+            sage: x.degree() == min(n,2) or (x == x.coefficient(0)*J.one())
             True
 
         TESTS:
             True
 
         TESTS:
@@ -904,7 +949,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
         two here so that said elements actually exist::
 
             sage: set_random_seed()
         two here so that said elements actually exist::
 
             sage: set_random_seed()
-            sage: n_max = max(2, JordanSpinEJA._max_test_case_size())
+            sage: n_max = max(2, JordanSpinEJA._max_random_instance_size())
             sage: n = ZZ.random_element(2, n_max)
             sage: J = JordanSpinEJA(n)
             sage: y = J.random_element()
             sage: n = ZZ.random_element(2, n_max)
             sage: J = JordanSpinEJA(n)
             sage: y = J.random_element()
@@ -930,10 +975,10 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
         and in particular, a re-scaling of the basis::
 
             sage: set_random_seed()
         and in particular, a re-scaling of the basis::
 
             sage: set_random_seed()
-            sage: n_max = RealSymmetricEJA._max_test_case_size()
+            sage: n_max = RealSymmetricEJA._max_random_instance_size()
             sage: n = ZZ.random_element(1, n_max)
             sage: J1 = RealSymmetricEJA(n)
             sage: n = ZZ.random_element(1, n_max)
             sage: J1 = RealSymmetricEJA(n)
-            sage: J2 = RealSymmetricEJA(n,normalize_basis=False)
+            sage: J2 = RealSymmetricEJA(n,orthonormalize=False)
             sage: X = random_matrix(AA,n)
             sage: X = X*X.transpose()
             sage: x1 = J1(X)
             sage: X = random_matrix(AA,n)
             sage: X = X*X.transpose()
             sage: x1 = J1(X)
@@ -954,20 +999,21 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
                 # in the "normal" case without us having to think about it.
                 return self.operator().minimal_polynomial()
 
                 # in the "normal" case without us having to think about it.
                 return self.operator().minimal_polynomial()
 
-        A = self.subalgebra_generated_by()
+        A = self.subalgebra_generated_by(orthonormalize_basis=False)
         return A(self).operator().minimal_polynomial()
 
 
 
         return A(self).operator().minimal_polynomial()
 
 
 
-    def natural_representation(self):
+    def to_matrix(self):
         """
         """
-        Return a more-natural representation of this element.
+        Return an (often more natural) representation of this element as a
+        matrix.
 
 
-        Every finite-dimensional Euclidean Jordan Algebra is a
-        direct sum of five simple algebras, four of which comprise
-        Hermitian matrices. This method returns the original
-        "natural" representation of this element as a Hermitian
-        matrix, if it has one. If not, you get the usual representation.
+        Every finite-dimensional Euclidean Jordan Algebra is a direct
+        sum of five simple algebras, four of which comprise Hermitian
+        matrices. This method returns a "natural" matrix
+        representation of this element as either a Hermitian matrix or
+        column vector.
 
         SETUP::
 
 
         SETUP::
 
@@ -979,7 +1025,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: J = ComplexHermitianEJA(3)
             sage: J.one()
             e0 + e3 + e8
             sage: J = ComplexHermitianEJA(3)
             sage: J.one()
             e0 + e3 + e8
-            sage: J.one().natural_representation()
+            sage: J.one().to_matrix()
             [1 0 0 0 0 0]
             [0 1 0 0 0 0]
             [0 0 1 0 0 0]
             [1 0 0 0 0 0]
             [0 1 0 0 0 0]
             [0 0 1 0 0 0]
@@ -992,7 +1038,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: J = QuaternionHermitianEJA(3)
             sage: J.one()
             e0 + e5 + e14
             sage: J = QuaternionHermitianEJA(3)
             sage: J.one()
             e0 + e5 + e14
-            sage: J.one().natural_representation()
+            sage: J.one().to_matrix()
             [1 0 0 0 0 0 0 0 0 0 0 0]
             [0 1 0 0 0 0 0 0 0 0 0 0]
             [0 0 1 0 0 0 0 0 0 0 0 0]
             [1 0 0 0 0 0 0 0 0 0 0 0]
             [0 1 0 0 0 0 0 0 0 0 0 0]
             [0 0 1 0 0 0 0 0 0 0 0 0]
@@ -1005,11 +1051,14 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             [0 0 0 0 0 0 0 0 0 1 0 0]
             [0 0 0 0 0 0 0 0 0 0 1 0]
             [0 0 0 0 0 0 0 0 0 0 0 1]
             [0 0 0 0 0 0 0 0 0 1 0 0]
             [0 0 0 0 0 0 0 0 0 0 1 0]
             [0 0 0 0 0 0 0 0 0 0 0 1]
-
         """
         """
-        B = self.parent().natural_basis()
-        W = self.parent().natural_basis_space()
-        return W.linear_combination(zip(B,self.to_vector()))
+        B = self.parent().matrix_basis()
+        W = self.parent().matrix_space()
+
+        # 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()) )
 
 
     def norm(self):
 
 
     def norm(self):
@@ -1085,16 +1134,18 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: set_random_seed()
             sage: x = JordanSpinEJA.random_instance().random_element()
             sage: x_vec = x.to_vector()
             sage: set_random_seed()
             sage: x = JordanSpinEJA.random_instance().random_element()
             sage: x_vec = x.to_vector()
+            sage: Q = matrix.identity(x.base_ring(), 0)
             sage: n = x_vec.degree()
             sage: n = x_vec.degree()
-            sage: x0 = x_vec[0]
-            sage: x_bar = x_vec[1:]
-            sage: A = matrix(AA, 1, [x_vec.inner_product(x_vec)])
-            sage: B = 2*x0*x_bar.row()
-            sage: C = 2*x0*x_bar.column()
-            sage: D = matrix.identity(AA, n-1)
-            sage: D = (x0^2 - x_bar.inner_product(x_bar))*D
-            sage: D = D + 2*x_bar.tensor_product(x_bar)
-            sage: Q = matrix.block(2,2,[A,B,C,D])
+            sage: if n > 0:
+            ....:     x0 = x_vec[0]
+            ....:     x_bar = x_vec[1:]
+            ....:     A = matrix(x.base_ring(), 1, [x_vec.inner_product(x_vec)])
+            ....:     B = 2*x0*x_bar.row()
+            ....:     C = 2*x0*x_bar.column()
+            ....:     D = matrix.identity(x.base_ring(), n-1)
+            ....:     D = (x0^2 - x_bar.inner_product(x_bar))*D
+            ....:     D = D + 2*x_bar.tensor_product(x_bar)
+            ....:     Q = matrix.block(2,2,[A,B,C,D])
             sage: Q == x.quadratic_representation().matrix()
             True
 
             sage: Q == x.quadratic_representation().matrix()
             True
 
@@ -1252,7 +1303,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: (J0, J5, J1) = J.peirce_decomposition(c1)
             sage: (f0, f1, f2) = J1.gens()
             sage: f0.spectral_decomposition()
             sage: (J0, J5, J1) = J.peirce_decomposition(c1)
             sage: (f0, f1, f2) = J1.gens()
             sage: f0.spectral_decomposition()
-            [(0, 1.000000000000000?*f2), (1, 1.000000000000000?*f0)]
+            [(0, f2), (1, f0)]
 
         """
         A = self.subalgebra_generated_by(orthonormalize_basis=True)
 
         """
         A = self.subalgebra_generated_by(orthonormalize_basis=True)
@@ -1308,6 +1359,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             True
 
         """
             True
 
         """
+        from mjo.eja.eja_element_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra
         return FiniteDimensionalEuclideanJordanElementSubalgebra(self, orthonormalize_basis)
 
 
         return FiniteDimensionalEuclideanJordanElementSubalgebra(self, orthonormalize_basis)