]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_element.py
eja: use from_vector() instead of call magic in two more places.
[sage.d.git] / mjo / eja / eja_element.py
index 1b5e3149e8e804f410403c066cc7e483eaa42a61..4ed0a59216e7d07eaba9a6aec1b43e91902d3513 100644 (file)
@@ -1,14 +1,16 @@
-from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_element import FiniteDimensionalAlgebraElement
 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_subalgebra',
+            'FiniteDimensionalEuclideanJordanElementSubalgebra')
 from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator
 from mjo.eja.eja_utils import _mat2vec
 
-class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraElement):
+class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement):
     """
     An element of a Euclidean Jordan algebra.
     """
@@ -23,7 +25,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
                       dir(self.__class__) )
 
 
-    def __init__(self, A, elt=None):
+    def __init__(self, A, elt):
         """
 
         SETUP::
@@ -58,7 +60,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
             sage: set_random_seed()
             sage: J = random_eja()
             sage: v = J.vector_space().random_element()
-            sage: J(v).vector() == v
+            sage: J(v).to_vector() == v
             True
 
         """
@@ -73,8 +75,9 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
         # already fits into the algebra, but also happens to live
         # in the parent's "natural ambient space" (this happens with
         # vectors in R^n).
+        ifme = super(FiniteDimensionalEuclideanJordanAlgebraElement, self)
         try:
-            FiniteDimensionalAlgebraElement.__init__(self, A, elt)
+            ifme.__init__(A, elt)
         except ValueError:
             natural_basis = A.natural_basis()
             if elt in natural_basis[0].matrix_space():
@@ -83,8 +86,9 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
                 # natural-basis coordinates ourselves.
                 V = VectorSpace(elt.base_ring(), elt.nrows()**2)
                 W = V.span( _mat2vec(s) for s in natural_basis )
-                coords =  W.coordinates(_mat2vec(elt))
-                FiniteDimensionalAlgebraElement.__init__(self, A, coords)
+                coords =  W.coordinate_vector(_mat2vec(elt))
+                ifme.__init__(A, coords)
+
 
     def __pow__(self, n):
         """
@@ -226,7 +230,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
 
         """
         p = self.parent().characteristic_polynomial()
-        return p(*self.vector())
+        return p(*self.to_vector())
 
 
     def inner_product(self, other):
@@ -253,7 +257,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
             sage: y = vector(QQ,[4,5,6])
             sage: x.inner_product(y)
             32
-            sage: J(x).inner_product(J(y))
+            sage: J.from_vector(x).inner_product(J.from_vector(y))
             32
 
         The inner product on `S^n` is `<X,Y> = trace(X*Y)`, where
@@ -435,7 +439,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
         # -1 to ensure that _charpoly_coeff(0) is really what
         # appears in front of t^{0} in the charpoly. However,
         # we want (-1)^r times THAT for the determinant.
-        return ((-1)**r)*p(*self.vector())
+        return ((-1)**r)*p(*self.to_vector())
 
 
     def inverse(self):
@@ -463,7 +467,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
             sage: x = J.random_element()
             sage: while not x.is_invertible():
             ....:     x = J.random_element()
-            sage: x_vec = x.vector()
+            sage: x_vec = x.to_vector()
             sage: x0 = x_vec[0]
             sage: x_bar = x_vec[1:]
             sage: coeff = ~(x0^2 - x_bar.inner_product(x_bar))
@@ -627,12 +631,13 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
 
         TESTS:
 
-        The zero element should never be regular::
+        The zero element should never be regular, unless the parent
+        algebra has dimension one::
 
             sage: set_random_seed()
             sage: J = random_eja()
-            sage: J.zero().is_regular()
-            False
+            sage: J.dimension() == 1 or not J.zero().is_regular()
+            True
 
         The unit element isn't regular unless the algebra happens to
         consist of only its scalar multiples::
@@ -701,7 +706,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
             True
 
         """
-        return self.span_of_powers().dimension()
+        return self.subalgebra_generated_by().dimension()
 
 
     def left_matrix(self):
@@ -762,8 +767,8 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
             sage: y = J.random_element()
             sage: while y == y.coefficient(0)*J.one():
             ....:     y = J.random_element()
-            sage: y0 = y.vector()[0]
-            sage: y_bar = y.vector()[1:]
+            sage: y0 = y.to_vector()[0]
+            sage: y_bar = y.to_vector()[1:]
             sage: actual = y.minimal_polynomial()
             sage: t = PolynomialRing(J.base_ring(),'t').gen(0)
             sage: expected = t^2 - 2*y0*t + (y0^2 - norm(y_bar)^2)
@@ -779,13 +784,8 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
             0
 
         """
-        V = self.span_of_powers()
-        assoc_subalg = self.subalgebra_generated_by()
-        # Mis-design warning: the basis used for span_of_powers()
-        # and subalgebra_generated_by() must be the same, and in
-        # the same order!
-        elt = assoc_subalg(V.coordinates(self.vector()))
-        return elt.operator().minimal_polynomial()
+        A = self.subalgebra_generated_by()
+        return A.element_class(A,self).operator().minimal_polynomial()
 
 
 
@@ -839,7 +839,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
         """
         B = self.parent().natural_basis()
         W = B[0].matrix_space()
-        return W.linear_combination(zip(self.vector(), B))
+        return W.linear_combination(zip(B,self.to_vector()))
 
 
     def operator(self):
@@ -864,11 +864,10 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
 
         """
         P = self.parent()
-        fda_elt = FiniteDimensionalAlgebraElement(P, self)
         return FiniteDimensionalEuclideanJordanAlgebraOperator(
                  P,
                  P,
-                 fda_elt.matrix().transpose() )
+                 self.to_matrix() )
 
 
     def quadratic_representation(self, other=None):
@@ -889,7 +888,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
             sage: n = ZZ.random_element(1,10)
             sage: J = JordanSpinEJA(n)
             sage: x = J.random_element()
-            sage: x_vec = x.vector()
+            sage: x_vec = x.to_vector()
             sage: x0 = x_vec[0]
             sage: x_bar = x_vec[1:]
             sage: A = matrix(QQ, 1, [x_vec.inner_product(x_vec)])
@@ -991,19 +990,6 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
         return ( L*M + M*L - (self*other).operator() )
 
 
-    def span_of_powers(self):
-        """
-        Return the vector space spanned by successive powers of
-        this element.
-        """
-        # The dimension of the subalgebra can't be greater than
-        # the big algebra, so just put everything into a list
-        # and let span() get rid of the excess.
-        #
-        # We do the extra ambient_vector_space() in case we're messing
-        # with polynomials and the direct parent is a module.
-        V = self.parent().vector_space()
-        return V.span( (self**d).vector() for d in xrange(V.dimension()) )
 
 
     def subalgebra_generated_by(self):
@@ -1027,54 +1013,12 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
 
             sage: set_random_seed()
             sage: x = random_eja().random_element()
-            sage: u = x.subalgebra_generated_by().random_element()
-            sage: u.operator()(u) == u^2
+            sage: A = x.subalgebra_generated_by()
+            sage: A(x^2) == A(x)*A(x)
             True
 
         """
-        # First get the subspace spanned by the powers of myself...
-        V = self.span_of_powers()
-        F = self.base_ring()
-
-        # Now figure out the entries of the right-multiplication
-        # matrix for the successive basis elements b0, b1,... of
-        # that subspace.
-        mats = []
-        for b_right in V.basis():
-            eja_b_right = self.parent()(b_right)
-            b_right_rows = []
-            # The first row of the right-multiplication matrix by
-            # b1 is what we get if we apply that matrix to b1. The
-            # second row of the right multiplication matrix by b1
-            # is what we get when we apply that matrix to b2...
-            #
-            # IMPORTANT: this assumes that all vectors are COLUMN
-            # vectors, unlike our superclass (which uses row vectors).
-            for b_left in V.basis():
-                eja_b_left = self.parent()(b_left)
-                # Multiply in the original EJA, but then get the
-                # coordinates from the subalgebra in terms of its
-                # basis.
-                this_row = V.coordinates((eja_b_left*eja_b_right).vector())
-                b_right_rows.append(this_row)
-            b_right_matrix = matrix(F, b_right_rows)
-            mats.append(b_right_matrix)
-
-        # It's an algebra of polynomials in one element, and EJAs
-        # are power-associative.
-        #
-        # TODO: choose generator names intelligently.
-        #
-        # The rank is the highest possible degree of a minimal polynomial,
-        # and is bounded above by the dimension. We know in this case that
-        # there's an element whose minimal polynomial has the same degree
-        # as the space's dimension, so that must be its rank too.
-        return FiniteDimensionalEuclideanJordanAlgebra(
-                 F,
-                 mats,
-                 V.dimension(),
-                 assume_associative=True,
-                 names='f')
+        return FiniteDimensionalEuclideanJordanElementSubalgebra(self)
 
 
     def subalgebra_idempotent(self):
@@ -1101,18 +1045,14 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
         if self.is_nilpotent():
             raise ValueError("this only works with non-nilpotent elements!")
 
-        V = self.span_of_powers()
         J = self.subalgebra_generated_by()
-        # Mis-design warning: the basis used for span_of_powers()
-        # and subalgebra_generated_by() must be the same, and in
-        # the same order!
-        u = J(V.coordinates(self.vector()))
+        u = J.from_vector(self.to_vector())
 
         # The image of the matrix of left-u^m-multiplication
         # will be minimal for some natural number s...
         s = 0
-        minimal_dim = V.dimension()
-        for i in xrange(1, V.dimension()):
+        minimal_dim = J.dimension()
+        for i in xrange(1, minimal_dim):
             this_dim = (u**i).operator().matrix().image().dimension()
             if this_dim < minimal_dim:
                 minimal_dim = this_dim
@@ -1131,15 +1071,10 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
         # Our FiniteDimensionalAlgebraElement superclass uses rows.
         u_next = u**(s+1)
         A = u_next.operator().matrix()
-        c_coordinates = A.solve_right(u_next.vector())
+        c = J(A.solve_right(u_next.to_vector()))
 
-        # Now c_coordinates is the idempotent we want, but it's in
-        # the coordinate system of the subalgebra.
-        #
-        # We need the basis for J, but as elements of the parent algebra.
-        #
-        basis = [self.parent(v) for v in V.basis()]
-        return self.parent().linear_combination(zip(c_coordinates, basis))
+        # Now c is the idempotent we want, but it still lives in the subalgebra.
+        return c.superalgebra_element()
 
 
     def trace(self):
@@ -1182,7 +1117,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(FiniteDimensionalAlgebraEle
         # -1 to ensure that _charpoly_coeff(r-1) is really what
         # appears in front of t^{r-1} in the charpoly. However,
         # we want the negative of THAT for the trace.
-        return -p(*self.vector())
+        return -p(*self.to_vector())
 
 
     def trace_inner_product(self, other):