]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_element.py
eja: normalize the real symmetric matrix basis.
[sage.d.git] / mjo / eja / eja_element.py
index 5b9142496f434be0a7c4dc014816302262eb33a5..90c236af8ef4dd46784007cb4927d00ba6b4e33e 100644 (file)
@@ -165,6 +165,21 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: x.apply_univariate_polynomial(p)
             0
 
+        The characteristic polynomials of the zero and unit elements
+        should be what we think they are in a subalgebra, too::
+
+            sage: J = RealCartesianProductEJA(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: p2 = A.one().characteristic_polynomial()
+            sage: q2 = A.zero().characteristic_polynomial()
+            sage: p1 == p2
+            True
+            sage: q1 == q2
+            True
+
         """
         p = self.parent().characteristic_polynomial()
         return p(*self.to_vector())
@@ -368,6 +383,16 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: x.is_invertible() == (x.det() != 0)
             True
 
+        Ensure that the determinant is multiplicative on an associative
+        subalgebra as in Faraut and Koranyi's Proposition II.2.2::
+
+            sage: set_random_seed()
+            sage: J = random_eja().random_element().subalgebra_generated_by()
+            sage: x = J.random_element()
+            sage: y = J.random_element()
+            sage: (x*y).det() == x.det()*y.det()
+            True
+
         """
         P = self.parent()
         r = P.rank()
@@ -410,7 +435,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: coeff = ~(x0^2 - x_bar.inner_product(x_bar))
             sage: inv_vec = x_vec.parent()([x0] + (-x_bar).list())
             sage: x_inverse = coeff*inv_vec
-            sage: x.inverse() == J(x_inverse)
+            sage: x.inverse() == J.from_vector(x_inverse)
             True
 
         TESTS:
@@ -482,15 +507,23 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: J.one().is_invertible()
             True
 
-        The zero element is never invertible::
+        The zero element is never invertible in a non-trivial algebra::
 
             sage: set_random_seed()
             sage: J = random_eja()
-            sage: J.zero().is_invertible()
+            sage: (not J.is_trivial()) and J.zero().is_invertible()
             False
 
         """
-        zero = self.parent().zero()
+        if self.is_zero():
+            if self.parent().is_trivial():
+                return True
+            else:
+                return False
+
+        # 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()
         p = self.minimal_polynomial()
         return not (p(zero) == zero)
 
@@ -643,6 +676,11 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             True
 
         """
+        if self.is_zero() and not self.parent().is_trivial():
+            # The minimal polynomial of zero in a nontrivial algebra
+            # is "t"; in a trivial algebra it's "1" by convention
+            # (it's an empty product).
+            return 1
         return self.subalgebra_generated_by().dimension()
 
 
@@ -721,8 +759,20 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             0
 
         """
+        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()
+
         A = self.subalgebra_generated_by()
-        return A.element_class(A,self).operator().minimal_polynomial()
+        return A(self).operator().minimal_polynomial()
 
 
 
@@ -775,10 +825,37 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
         """
         B = self.parent().natural_basis()
-        W = B[0].matrix_space()
+        W = self.parent().natural_basis_space()
         return W.linear_combination(zip(B,self.to_vector()))
 
 
+    def norm(self):
+        """
+        The norm of this element with respect to :meth:`inner_product`.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+            ....:                                  RealCartesianProductEJA)
+
+        EXAMPLES::
+
+            sage: J = RealCartesianProductEJA(2)
+            sage: x = sum(J.gens())
+            sage: x.norm()
+            sqrt(2)
+
+        ::
+
+            sage: J = JordanSpinEJA(4)
+            sage: x = sum(J.gens())
+            sage: x.norm()
+            2
+
+        """
+        return self.inner_product(self).sqrt()
+
+
     def operator(self):
         """
         Return the left-multiplication-by-this-element
@@ -801,10 +878,12 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
         """
         P = self.parent()
+        left_mult_by_self = lambda y: self*y
+        L = P.module_morphism(function=left_mult_by_self, codomain=P)
         return FiniteDimensionalEuclideanJordanAlgebraOperator(
                  P,
                  P,
-                 self.to_matrix() )
+                 L.matrix() )
 
 
     def quadratic_representation(self, other=None):
@@ -860,7 +939,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
         Property 2 (multiply on the right for :trac:`28272`):
 
-            sage: alpha = QQ.random_element()
+            sage: alpha = J.base_ring().random_element()
             sage: (alpha*x).quadratic_representation() == Qx*(alpha^2)
             True
 
@@ -938,11 +1017,17 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
 
             sage: from mjo.eja.eja_algebra import random_eja
 
-        TESTS::
+        TESTS:
+
+        This subalgebra, being composed of only powers, is associative::
 
             sage: set_random_seed()
-            sage: x = random_eja().random_element()
-            sage: x.subalgebra_generated_by().is_associative()
+            sage: x0 = random_eja().random_element()
+            sage: A = x0.subalgebra_generated_by()
+            sage: x = A.random_element()
+            sage: y = A.random_element()
+            sage: z = A.random_element()
+            sage: (x*y)*z == x*(y*z)
             True
 
         Squaring in the subalgebra should work the same as in
@@ -954,6 +1039,15 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: A(x^2) == A(x)*A(x)
             True
 
+        The subalgebra generated by the zero element is trivial::
+
+            sage: set_random_seed()
+            sage: A = random_eja().zero().subalgebra_generated_by()
+            sage: A
+            Euclidean Jordan algebra of dimension 0 over...
+            sage: A.one()
+            0
+
         """
         return FiniteDimensionalEuclideanJordanElementSubalgebra(self)
 
@@ -983,7 +1077,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             raise ValueError("this only works with non-nilpotent elements!")
 
         J = self.subalgebra_generated_by()
-        u = J.from_vector(self.to_vector())
+        u = J(self)
 
         # The image of the matrix of left-u^m-multiplication
         # will be minimal for some natural number s...
@@ -1008,7 +1102,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
         # Our FiniteDimensionalAlgebraElement superclass uses rows.
         u_next = u**(s+1)
         A = u_next.operator().matrix()
-        c = J(A.solve_right(u_next.to_vector()))
+        c = J.from_vector(A.solve_right(u_next.to_vector()))
 
         # Now c is the idempotent we want, but it still lives in the subalgebra.
         return c.superalgebra_element()
@@ -1082,7 +1176,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             sage: x = J.random_element()
             sage: y = J.random_element()
             sage: z = J.random_element()
-            sage: a = QQ.random_element();
+            sage: a = J.base_ring().random_element();
             sage: actual = (a*(x+z)).trace_inner_product(y)
             sage: expected = ( a*x.trace_inner_product(y) +
             ....:              a*z.trace_inner_product(y) )
@@ -1110,3 +1204,30 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
             raise TypeError("'other' must live in the same algebra")
 
         return (self*other).trace()
+
+
+    def trace_norm(self):
+        """
+        The norm of this element with respect to :meth:`trace_inner_product`.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+            ....:                                  RealCartesianProductEJA)
+
+        EXAMPLES::
+
+            sage: J = RealCartesianProductEJA(2)
+            sage: x = sum(J.gens())
+            sage: x.trace_norm()
+            sqrt(2)
+
+        ::
+
+            sage: J = JordanSpinEJA(4)
+            sage: x = sum(J.gens())
+            sage: x.trace_norm()
+            2*sqrt(2)
+
+        """
+        return self.trace_inner_product(self).sqrt()