]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_algebra.py
eja: propagate check_axioms to some other "check" variables.
[sage.d.git] / mjo / eja / eja_algebra.py
index bab1002ae7d0e2bc1e0fe1332f28871f55efadf2..56d91bdef13bd76dc7e48f8f1237b02c18ef59a3 100644 (file)
@@ -119,10 +119,12 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
 
         The ``field`` we're given must be real with ``check_field=True``::
 
-            sage: JordanSpinEJA(2,QQbar)
+            sage: JordanSpinEJA(2, QQbar)
             Traceback (most recent call last):
             ...
             ValueError: scalar field is not real
+            sage: JordanSpinEJA(2, QQbar, check_field=False)
+            Euclidean Jordan algebra of dimension 2 over Algebraic Field
 
         The multiplication table must be square with ``check_axioms=True``::
 
@@ -313,8 +315,12 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         # element's ring because the basis space might be an algebraic
         # closure whereas the base ring of the 3-by-3 identity matrix
         # could be QQ instead of QQbar.
+        #
+        # We pass check=False because the matrix basis is "guaranteed"
+        # to be linearly independent... right? Ha ha.
         V = VectorSpace(self.base_ring(), elt.nrows()*elt.ncols())
-        W = V.span_of_basis( _mat2vec(s) for s in self.matrix_basis() )
+        W = V.span_of_basis( (_mat2vec(s) for s in self.matrix_basis()),
+                             check=False)
 
         try:
             coords =  W.coordinate_vector(_mat2vec(elt))
@@ -1165,6 +1171,12 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
                  check_field=True,
                  check_axioms=True):
 
+        if check_field:
+            # Abuse the check_field parameter to check that the entries of
+            # out basis (in ambient coordinates) are in the field QQ.
+            if not all( all(b_i in QQ for b_i in b.list()) for b in basis ):
+                raise TypeError("basis not rational")
+
         n = len(basis)
         vector_basis = basis
 
@@ -1189,27 +1201,34 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
         # deorthonormalized basis. These can be used later to
         # construct a deorthonormalized copy of this algebra over QQ
         # in which several operations are much faster.
-        self._deortho_multiplication_table = None
-        self._deortho_inner_product_table = None
+        self._rational_algebra = None
 
         if orthonormalize:
+            if self.base_ring() is not QQ:
+                # There's no point in constructing the extra algebra if this
+                # one is already rational. If the original basis is rational
+                # but normalization would make it irrational, then this whole
+                # constructor will just fail anyway as it tries to stick an
+                # irrational number into a rational algebra.
+                #
+                # Note: the same Jordan and inner-products work here,
+                # because they are necessarily defined with respect to
+                # ambient coordinates and not any particular basis.
+                self._rational_algebra = RationalBasisEuclideanJordanAlgebra(
+                                          QQ,
+                                          basis,
+                                          jordan_product,
+                                          inner_product,
+                                          orthonormalize=False,
+                                          prefix=prefix,
+                                          category=category,
+                                          check_field=False,
+                                          check_axioms=False)
+
             # Compute the deorthonormalized tables before we orthonormalize
-            # the given basis.
-            W = V.span_of_basis( vector_basis )
-
-            if check_axioms:
-                # If the superclass constructor is going to verify the
-                # symmetry of this table, it has better at least be
-                # square...
-                self._deortho_multiplication_table = [ [0 for j in range(n)]
-                                                       for i in range(n) ]
-                self._deortho_inner_product_table = [ [0 for j in range(n)]
-                                                      for i in range(n) ]
-            else:
-                self._deortho_multiplication_table = [ [0 for j in range(i+1)]
-                                                       for i in range(n) ]
-                self._deortho_inner_product_table = [ [0 for j in range(i+1)]
-                                                      for i in range(n) ]
+            # the given basis. The "check" parameter here guarantees that
+            # the basis is linearly-independent.
+            W = V.span_of_basis( vector_basis, check=check_axioms)
 
             # Note: the Jordan and inner-products are defined in terms
             # of the ambient basis. It's important that their arguments
@@ -1232,20 +1251,6 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
                         # table is in terms of vectors
                         elt = _mat2vec(elt)
 
-                    elt = W.coordinate_vector(elt)
-                    self._deortho_multiplication_table[i][j] = elt
-                    self._deortho_inner_product_table[i][j] = ip
-                    if check_axioms:
-                        # The tables are square if we're verifying that they
-                        # are commutative.
-                        self._deortho_multiplication_table[j][i] = elt
-                        self._deortho_inner_product_table[j][i] = ip
-
-        if self._deortho_multiplication_table is not None:
-            self._deortho_multiplication_table = tuple(map(tuple, self._deortho_multiplication_table))
-        if self._deortho_inner_product_table is not None:
-            self._deortho_inner_product_table = tuple(map(tuple, self._deortho_inner_product_table))
-
         # We overwrite the name "vector_basis" in a second, but never modify it
         # in place, to this effectively makes a copy of it.
         deortho_vector_basis = vector_basis
@@ -1259,22 +1264,20 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
             else:
                 vector_basis = gram_schmidt(vector_basis, inner_product)
 
-            W = V.span_of_basis( vector_basis )
-
             # Normalize the "matrix" basis, too!
             basis = vector_basis
 
             if basis_is_matrices:
                 basis = tuple( map(_vec2mat,basis) )
 
-        W = V.span_of_basis( vector_basis )
+        W = V.span_of_basis( vector_basis, check=check_axioms)
 
         # Now "W" is the vector space of our algebra coordinates. The
         # variables "X1", "X2",...  refer to the entries of vectors in
         # W. Thus to convert back and forth between the orthonormal
         # coordinates and the given ones, we need to stick the original
         # basis in W.
-        U = V.span_of_basis( deortho_vector_basis )
+        U = V.span_of_basis( deortho_vector_basis, check=check_axioms)
         self._deortho_matrix = matrix( U.coordinate_vector(q)
                                        for q in vector_basis )
 
@@ -1357,21 +1360,19 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
             Algebraic Real Field
 
         """
-        if self.base_ring() is QQ:
+        if self.base_ring() is QQ or self._rational_algebra is None:
             # There's no need to construct *another* algebra over the
-            # rationals if this one is already over the rationals.
+            # rationals if this one is already over the
+            # rationals. Likewise, if we never orthonormalized our
+            # basis, we might as well just use the given one.
             superclass = super(RationalBasisEuclideanJordanAlgebra, self)
             return superclass._charpoly_coefficients()
 
         # Do the computation over the rationals. The answer will be
         # the same, because all we've done is a change of basis.
-        J = FiniteDimensionalEuclideanJordanAlgebra(QQ,
-                                                    self._deortho_multiplication_table,
-                                                    self._deortho_inner_product_table)
-
-        # Change back from QQ to our real base ring
+        # Then, change back from QQ to our real base ring
         a = ( a_i.change_ring(self.base_ring())
-              for a_i in J._charpoly_coefficients() )
+              for a_i in self._rational_algebra._charpoly_coefficients() )
 
         # Now convert the coordinate variables back to the
         # deorthonormalized ones.
@@ -1609,7 +1610,7 @@ class RealSymmetricEJA(ConcreteEuclideanJordanAlgebra,
                 else:
                     Sij = Eij + Eij.transpose()
                 S.append(Sij)
-        return S
+        return tuple(S)
 
 
     @staticmethod
@@ -2279,10 +2280,16 @@ class HadamardEJA(ConcreteEuclideanJordanAlgebra):
         def inner_product(x,y):
             return x.inner_product(y)
 
+        # Don't orthonormalize because our basis is already
+        # orthonormal with respect to our inner-product. But also
+        # don't pass check_field=False here, because the user can pass
+        # in a field!
         super(HadamardEJA, self).__init__(field,
                                           basis,
                                           jordan_product,
                                           inner_product,
+                                          orthonormalize=False,
+                                          check_axioms=False,
                                           **kwargs)
         self.rank.set_cache(n)
 
@@ -2506,10 +2513,19 @@ class JordanSpinEJA(BilinearFormEJA):
 
     """
     def __init__(self, n, field=AA, **kwargs):
-        # This is a special case of the BilinearFormEJA with the identity
-        # matrix as its bilinear form.
+        # This is a special case of the BilinearFormEJA with the
+        # identity matrix as its bilinear form.
         B = matrix.identity(field, n)
-        super(JordanSpinEJA, self).__init__(B, field, **kwargs)
+
+        # Don't orthonormalize because our basis is already
+        # orthonormal with respect to our inner-product. But
+        # also don't pass check_field=False here, because the
+        # user can pass in a field!
+        super(JordanSpinEJA, self).__init__(B,
+                                            field,
+                                            orthonormalize=False,
+                                            check_axioms=False,
+                                            **kwargs)
 
     @staticmethod
     def _max_random_instance_size():