]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_algebra.py
eja: reimplement multiplication_table() without member variables.
[sage.d.git] / mjo / eja / eja_algebra.py
index 5dee5d012d6c19d6fc5d79f804ad8aff2757c3d0..3b13ce10bbf864ceb667f3ba4fc1f8b520327292 100644 (file)
@@ -614,20 +614,15 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
 
         """
         n = self.dimension()
-        M = [ [ self.zero() for j in range(n) ]
-              for i in range(n) ]
-        for i in range(n):
-            for j in range(i+1):
-                M[i][j] = self._multiplication_table[i][j]
-                M[j][i] = M[i][j]
+        # Prepend the header row.
+        M = [["*"] + list(self.gens())]
 
-        for i in range(n):
-            # Prepend the left "header" column entry Can't do this in
-            # the loop because it messes up the symmetry.
-            M[i] = [self.monomial(i)] + M[i]
+        # And to each subsequent row, prepend an entry that belongs to
+        # the left-side "header column."
+        M += [ [self.monomial(i)] + [ self.product_on_basis(i,j)
+                                      for j in range(n) ]
+               for i in range(n) ]
 
-        # Prepend the header row.
-        M = [["*"] + list(self.gens())] + M
         return table(M, header_row=True, header_column=True, frame=True)
 
 
@@ -1200,36 +1195,29 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
 
         V = VectorSpace(field, degree)
 
-        # If we were asked to orthonormalize, and if the orthonormal
-        # basis is different from the given one, then we also want to
-        # compute multiplication and inner-product tables for the
-        # deorthonormalized basis. These can be used later to
-        # construct a deorthonormalized copy of this algebra over QQ
-        # in which several operations are much faster.
+        # Save a copy of an algebra with the original, rational basis
+        # and over QQ where computations are fast.
         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(
-                                          basis,
-                                          jordan_product,
-                                          inner_product,
-                                          field=QQ,
-                                          orthonormalize=False,
-                                          prefix=prefix,
-                                          category=category,
-                                          check_field=False,
-                                          check_axioms=False)
+        if field is not QQ:
+            # There's no point in constructing the extra algebra if this
+            # one is already rational.
+            #
+            # 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(
+                                       basis,
+                                       jordan_product,
+                                       inner_product,
+                                       field=QQ,
+                                       orthonormalize=False,
+                                       prefix=prefix,
+                                       category=category,
+                                       check_field=False,
+                                       check_axioms=False)
 
+        if orthonormalize:
             # Compute the deorthonormalized tables before we orthonormalize
             # the given basis. The "check" parameter here guarantees that
             # the basis is linearly-independent.
@@ -1365,7 +1353,7 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
             Algebraic Real Field
 
         """
-        if self.base_ring() is QQ or self._rational_algebra is None:
+        if self._rational_algebra is None:
             # There's no need to construct *another* algebra over the
             # rationals if this one is already over the
             # rationals. Likewise, if we never orthonormalized our
@@ -1523,15 +1511,29 @@ class MatrixEuclideanJordanAlgebra:
         This gives the same answer as it would if we computed the trace
         from the unembedded (original) matrices::
 
+            sage: set_random_seed()
+            sage: J = RealSymmetricEJA.random_instance()
+            sage: x,y = J.random_elements(2)
+            sage: Xe = x.to_matrix()
+            sage: Ye = y.to_matrix()
+            sage: X = J.real_unembed(Xe)
+            sage: Y = J.real_unembed(Ye)
+            sage: expected = (X*Y).trace()
+            sage: actual = J.trace_inner_product(Xe,Ye)
+            sage: actual == expected
+            True
+
+        ::
+
             sage: set_random_seed()
             sage: J = ComplexHermitianEJA.random_instance()
             sage: x,y = J.random_elements(2)
             sage: Xe = x.to_matrix()
             sage: Ye = y.to_matrix()
-            sage: X = ComplexHermitianEJA.real_unembed(Xe)
-            sage: Y = ComplexHermitianEJA.real_unembed(Ye)
+            sage: X = J.real_unembed(Xe)
+            sage: Y = J.real_unembed(Ye)
             sage: expected = (X*Y).trace().real()
-            sage: actual = ComplexHermitianEJA.trace_inner_product(Xe,Ye)
+            sage: actual = J.trace_inner_product(Xe,Ye)
             sage: actual == expected
             True
 
@@ -1542,10 +1544,10 @@ class MatrixEuclideanJordanAlgebra:
             sage: x,y = J.random_elements(2)
             sage: Xe = x.to_matrix()
             sage: Ye = y.to_matrix()
-            sage: X = QuaternionHermitianEJA.real_unembed(Xe)
-            sage: Y = QuaternionHermitianEJA.real_unembed(Ye)
+            sage: X = J.real_unembed(Xe)
+            sage: Y = J.real_unembed(Ye)
             sage: expected = (X*Y).trace().coefficient_tuple()[0]
-            sage: actual = QuaternionHermitianEJA.trace_inner_product(Xe,Ye)
+            sage: actual = J.trace_inner_product(Xe,Ye)
             sage: actual == expected
             True
 
@@ -1556,12 +1558,12 @@ class MatrixEuclideanJordanAlgebra:
 
         try:
             # Works in QQ, AA, RDF, et cetera.
-            return tr.real() / cls.dimension_over_reals()
+            return tr.real()
         except AttributeError:
             # A quaternion doesn't have a real() method, but does
             # have coefficient_tuple() method that returns the
             # coefficients of 1, i, j, and k -- in that order.
-            return tr.coefficient_tuple()[0] / cls.dimension_over_reals()
+            return tr.coefficient_tuple()[0]
 
 
 class RealMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
@@ -1803,11 +1805,19 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         field = M.base_ring()
         R = PolynomialRing(field, 'z')
         z = R.gen()
+
+        # Sage doesn't know how to adjoin the complex "i" (the root of
+        # x^2 + 1) to a field in a general way. Here, we just enumerate
+        # all of the cases that I have cared to support so far.
         if field is AA:
             # Sage doesn't know how to embed AA into QQbar, i.e. how
             # to adjoin sqrt(-1) to AA.
             F = QQbar
+        elif not field.is_exact():
+            # RDF or RR
+            F = field.complex_field()
         else:
+            # Works for QQ and... maybe some other fields.
             F = field.extension(z**2 + 1, 'I', embedding=CLF(-1).sqrt())
         i = F.gen()