]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_algebra.py
eja: refactor the matrix EJA hierarchy (mainly constructors) a bit.
[sage.d.git] / mjo / eja / eja_algebra.py
index 2a5e624cf4730e8296373d5fe542bbc78d31666e..02cf32c7d27ff93728ad548a964ff6bee5f277d4 100644 (file)
@@ -5,7 +5,7 @@ are used in optimization, and have some additional nice methods beyond
 what can be supported in a general Jordan Algebra.
 """
 
-from itertools import repeat
+from itertools import izip, repeat
 
 from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra
 from sage.categories.magmatic_algebras import MagmaticAlgebras
@@ -409,7 +409,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             # assign a[r] goes out-of-bounds.
             a.append(1) # corresponds to x^r
 
-        return sum( a[k]*(t**k) for k in range(len(a)) )
+        return sum( a[k]*(t**k) for k in xrange(len(a)) )
 
 
     def inner_product(self, x, y):
@@ -491,7 +491,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
 
         """
         M = list(self._multiplication_table) # copy
-        for i in range(len(M)):
+        for i in xrange(len(M)):
             # M had better be "square"
             M[i] = [self.monomial(i)] + M[i]
         M = [["*"] + list(self.gens())] + M
@@ -799,8 +799,8 @@ class RealCartesianProductEJA(FiniteDimensionalEuclideanJordanAlgebra):
     """
     def __init__(self, n, field=QQ, **kwargs):
         V = VectorSpace(field, n)
-        mult_table = [ [ V.gen(i)*(i == j) for j in range(n) ]
-                       for i in range(n) ]
+        mult_table = [ [ V.gen(i)*(i == j) for j in xrange(n) ]
+                       for i in xrange(n) ]
 
         fdeja = super(RealCartesianProductEJA, self)
         return fdeja.__init__(field, mult_table, rank=n, **kwargs)
@@ -885,17 +885,20 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
         # field can have dimension 4 (quaternions) too.
         return 2
 
-    @classmethod
-    def _denormalized_basis(cls, n, field):
-        raise NotImplementedError
-
-    def __init__(self, n, field=QQ, normalize_basis=True, **kwargs):
-        S = self._denormalized_basis(n, field)
-
+    def __init__(self, field, basis, rank, normalize_basis=True, **kwargs):
+        """
+        Compared to the superclass constructor, we take a basis instead of
+        a multiplication table because the latter can be computed in terms
+        of the former when the product is known (like it is here).
+        """
         # Used in this class's fast _charpoly_coeff() override.
         self._basis_normalizers = None
 
-        if n > 1 and normalize_basis:
+        # We're going to loop through this a few times, so now's a good
+        # time to ensure that it isn't a generator expression.
+        basis = tuple(basis)
+
+        if rank > 1 and normalize_basis:
             # We'll need sqrt(2) to normalize the basis, and this
             # winds up in the multiplication table, so the whole
             # algebra needs to be over the field extension.
@@ -904,18 +907,18 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
             p = z**2 - 2
             if p.is_irreducible():
                 field = NumberField(p, 'sqrt2', embedding=RLF(2).sqrt())
-                S = [ s.change_ring(field) for s in S ]
+                basis = tuple( s.change_ring(field) for s in basis )
             self._basis_normalizers = tuple(
-                ~(self.natural_inner_product(s,s).sqrt()) for s in S )
-            S = tuple( s*c for (s,c) in zip(S,self._basis_normalizers) )
+                ~(self.natural_inner_product(s,s).sqrt()) for s in basis )
+            basis = tuple(s*c for (s,c) in izip(basis,self._basis_normalizers))
 
-        Qs = self.multiplication_table_from_matrix_basis(S)
+        Qs = self.multiplication_table_from_matrix_basis(basis)
 
         fdeja = super(MatrixEuclideanJordanAlgebra, self)
         return fdeja.__init__(field,
                               Qs,
-                              rank=n,
-                              natural_basis=S,
+                              rank=rank,
+                              natural_basis=basis,
                               **kwargs)
 
 
@@ -930,13 +933,17 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
             # with had entries in a nice field.
             return super(MatrixEuclideanJordanAlgebra, self)._charpoly_coeff(i)
         else:
-            n = self.natural_basis_space().nrows()
-            field = self.base_ring().base_ring() # yeeeeaaaahhh
-            J = self.__class__(n, field, False)
+            basis = ( (b/n) for (b,n) in izip(self.natural_basis(),
+                                              self._basis_normalizers) )
+            field = self.base_ring().base_ring() # yeeeaahhhhhhh
+            J = MatrixEuclideanJordanAlgebra(field,
+                                             basis,
+                                             self.rank(),
+                                             normalize_basis=False)
             (_,x,_,_) = J._charpoly_matrix_system()
             p = J._charpoly_coeff(i)
             # p might be missing some vars, have to substitute "optionally"
-            pairs = zip(x.base_ring().gens(), self._basis_normalizers)
+            pairs = izip(x.base_ring().gens(), self._basis_normalizers)
             substitutions = { v: v*c for (v,c) in pairs }
             return p.subs(substitutions)
 
@@ -962,9 +969,9 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
         V = VectorSpace(field, dimension**2)
         W = V.span_of_basis( _mat2vec(s) for s in basis )
         n = len(basis)
-        mult_table = [[W.zero() for j in range(n)] for i in range(n)]
-        for i in range(n):
-            for j in range(n):
+        mult_table = [[W.zero() for j in xrange(n)] for i in xrange(n)]
+        for i in xrange(n):
+            for j in xrange(n):
                 mat_entry = (basis[i]*basis[j] + basis[j]*basis[i])/2
                 mult_table[i][j] = W.coordinate_vector(_mat2vec(mat_entry))
 
@@ -1020,24 +1027,16 @@ class RealMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
     @staticmethod
     def real_embed(M):
         """
-        Embed the matrix ``M`` into a space of real matrices.
-
-        The matrix ``M`` can have entries in any field at the moment:
-        the real numbers, complex numbers, or quaternions. And although
-        they are not a field, we can probably support octonions at some
-        point, too. This function returns a real matrix that "acts like"
-        the original with respect to matrix multiplication; i.e.
-
-          real_embed(M*N) = real_embed(M)*real_embed(N)
-
+        The identity function, for embedding real matrices into real
+        matrices.
         """
         return M
 
-
     @staticmethod
     def real_unembed(M):
         """
-        The inverse of :meth:`real_embed`.
+        The identity function, for unembedding real matrices from real
+        matrices.
         """
         return M
 
@@ -1142,7 +1141,7 @@ class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra):
                 else:
                     Sij = Eij + Eij.transpose()
                 S.append(Sij)
-        return tuple(S)
+        return S
 
 
     @staticmethod
@@ -1150,6 +1149,10 @@ class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra):
         return 4 # Dimension 10
 
 
+    def __init__(self, n, field=QQ, **kwargs):
+        basis = self._denormalized_basis(n, field)
+        super(RealSymmetricEJA, self).__init__(field, basis, n, **kwargs)
+
 
 class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
     @staticmethod
@@ -1362,6 +1365,7 @@ class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra):
         True
 
     """
+
     @classmethod
     def _denormalized_basis(cls, n, field):
         """
@@ -1413,9 +1417,13 @@ class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra):
 
         # Since we embedded these, we can drop back to the "field" that we
         # started with instead of the complex extension "F".
-        return tuple( s.change_ring(field) for s in S )
+        return ( s.change_ring(field) for s in S )
 
 
+    def __init__(self, n, field=QQ, **kwargs):
+        basis = self._denormalized_basis(n,field)
+        super(ComplexHermitianEJA,self).__init__(field, basis, n, **kwargs)
+
 
 class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
     @staticmethod
@@ -1691,9 +1699,13 @@ class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra):
                     S.append(Sij_J)
                     Sij_K = cls.real_embed(K*Eij - K*Eij.transpose())
                     S.append(Sij_K)
-        return tuple(S)
+        return S
 
 
+    def __init__(self, n, field=QQ, **kwargs):
+        basis = self._denormalized_basis(n,field)
+        super(QuaternionHermitianEJA,self).__init__(field, basis, n, **kwargs)
+
 
 class JordanSpinEJA(FiniteDimensionalEuclideanJordanAlgebra):
     """
@@ -1735,9 +1747,9 @@ class JordanSpinEJA(FiniteDimensionalEuclideanJordanAlgebra):
     """
     def __init__(self, n, field=QQ, **kwargs):
         V = VectorSpace(field, n)
-        mult_table = [[V.zero() for j in range(n)] for i in range(n)]
-        for i in range(n):
-            for j in range(n):
+        mult_table = [[V.zero() for j in xrange(n)] for i in xrange(n)]
+        for i in xrange(n):
+            for j in xrange(n):
                 x = V.gen(i)
                 y = V.gen(j)
                 x0 = x[0]