]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_algebra.py
eja: add "check" parameter to check if our field is real.
[sage.d.git] / mjo / eja / eja_algebra.py
index e24b34890b48a5605184215af7675624e229d7d8..7a65fabdcfcd4adf9c2369dd7d64da50e17b1bd3 100644 (file)
@@ -16,12 +16,9 @@ from sage.misc.cachefunc import cached_method
 from sage.misc.prandom import choice
 from sage.misc.table import table
 from sage.modules.free_module import FreeModule, VectorSpace
-from sage.rings.integer_ring import ZZ
-from sage.rings.number_field.number_field import NumberField, QuadraticField
-from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
-from sage.rings.rational_field import QQ
-from sage.rings.real_lazy import CLF, RLF
-
+from sage.rings.all import (ZZ, QQ, RR, RLF, CLF,
+                            PolynomialRing,
+                            QuadraticField)
 from mjo.eja.eja_element import FiniteDimensionalEuclideanJordanAlgebraElement
 from mjo.eja.eja_utils import _mat2vec
 
@@ -40,11 +37,12 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
                  rank,
                  prefix='e',
                  category=None,
-                 natural_basis=None):
+                 natural_basis=None,
+                 check=True):
         """
         SETUP::
 
-            sage: from mjo.eja.eja_algebra import random_eja
+            sage: from mjo.eja.eja_algebra import (JordanSpinEJA, random_eja)
 
         EXAMPLES:
 
@@ -56,7 +54,23 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
             sage: x*y == y*x
             True
 
+        TESTS:
+
+        The ``field`` we're given must be real::
+
+            sage: JordanSpinEJA(2,QQbar)
+            Traceback (most recent call last):
+            ...
+            ValueError: field is not real
+
         """
+        if check:
+            if not field.is_subring(RR):
+                # Note: this does return true for the real algebraic
+                # field, and any quadratic field where we've specified
+                # a real embedding.
+                raise ValueError('field is not real')
+
         self._rank = rank
         self._natural_basis = natural_basis
 
@@ -910,7 +924,7 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
             z = R.gen()
             p = z**2 - 2
             if p.is_irreducible():
-                field = NumberField(p, 'sqrt2', embedding=RLF(2).sqrt())
+                field = field.extension(p, 'sqrt2', embedding=RLF(2).sqrt())
                 basis = tuple( s.change_ring(field) for s in basis )
             self._basis_normalizers = tuple(
                 ~(self.natural_inner_product(s,s).sqrt()) for s in basis )
@@ -939,8 +953,9 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
         else:
             basis = ( (b/n) for (b,n) in izip(self.natural_basis(),
                                               self._basis_normalizers) )
-            field = self.base_ring().base_ring() # yeeeaahhhhhhh
-            J = MatrixEuclideanJordanAlgebra(field,
+
+            # Do this over the rationals and convert back at the end.
+            J = MatrixEuclideanJordanAlgebra(QQ,
                                              basis,
                                              self.rank(),
                                              normalize_basis=False)
@@ -949,7 +964,14 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
             # p might be missing some vars, have to substitute "optionally"
             pairs = izip(x.base_ring().gens(), self._basis_normalizers)
             substitutions = { v: v*c for (v,c) in pairs }
-            return p.subs(substitutions)
+            result = p.subs(substitutions)
+
+            # The result of "subs" can be either a coefficient-ring
+            # element or a polynomial. Gotta handle both cases.
+            if result in QQ:
+                return self.base_ring()(result)
+            else:
+                return result.change_ring(self.base_ring())
 
 
     @staticmethod
@@ -1012,6 +1034,7 @@ class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
         Xu = cls.real_unembed(X)
         Yu = cls.real_unembed(Y)
         tr = (Xu*Yu).trace()
+
         if tr in RLF:
             # It's real already.
             return tr
@@ -1066,6 +1089,14 @@ class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra, KnownRankEJA):
         sage: e2*e2
         e2
 
+    In theory, our "field" can be any subfield of the reals::
+
+        sage: RealSymmetricEJA(2, AA)
+        Euclidean Jordan algebra of dimension 3 over Algebraic Real Field
+        sage: RealSymmetricEJA(2, RR)
+        Euclidean Jordan algebra of dimension 3 over Real Field with
+        53 bits of precision
+
     TESTS:
 
     The dimension of this algebra is `(n^2 + n) / 2`::
@@ -1206,15 +1237,17 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         n = M.nrows()
         if M.ncols() != n:
             raise ValueError("the matrix 'M' must be square")
-        field = M.base_ring()
+
+        # We don't need any adjoined elements...
+        field = M.base_ring().base_ring()
+
         blocks = []
         for z in M.list():
-            a = z.vector()[0] # real part, I guess
-            b = z.vector()[1] # imag part, I guess
+            a = z.list()[0] # real part, I guess
+            b = z.list()[1] # imag part, I guess
             blocks.append(matrix(field, 2, [[a,b],[-b,a]]))
 
-        # We can drop the imaginaries here.
-        return matrix.block(field.base_ring(), n, blocks)
+        return matrix.block(field, n, blocks)
 
 
     @staticmethod
@@ -1255,10 +1288,12 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         if not n.mod(2).is_zero():
             raise ValueError("the matrix 'M' must be a complex embedding")
 
-        field = M.base_ring() # This should already have sqrt2
+        # If "M" was normalized, its base ring might have roots
+        # adjoined and they can stick around after unembedding.
+        field = M.base_ring()
         R = PolynomialRing(field, 'z')
         z = R.gen()
-        F = NumberField(z**2 + 1,'i', embedding=CLF(-1).sqrt())
+        F = field.extension(z**2 + 1, 'i', embedding=CLF(-1).sqrt())
         i = F.gen()
 
         # Go top-left to bottom-right (reading order), converting every
@@ -1319,6 +1354,16 @@ class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra, KnownRankEJA):
 
         sage: from mjo.eja.eja_algebra import ComplexHermitianEJA
 
+    EXAMPLES:
+
+    In theory, our "field" can be any subfield of the reals::
+
+        sage: ComplexHermitianEJA(2, AA)
+        Euclidean Jordan algebra of dimension 4 over Algebraic Real Field
+        sage: ComplexHermitianEJA(2, RR)
+        Euclidean Jordan algebra of dimension 4 over Real Field with
+        53 bits of precision
+
     TESTS:
 
     The dimension of this algebra is `n^2`::
@@ -1397,7 +1442,7 @@ class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra, KnownRankEJA):
         """
         R = PolynomialRing(field, 'z')
         z = R.gen()
-        F = NumberField(z**2 + 1, 'I', embedding=CLF(-1).sqrt())
+        F = field.extension(z**2 + 1, 'I')
         I = F.gen()
 
         # This is like the symmetric case, but we need to be careful:
@@ -1532,7 +1577,7 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         if M.ncols() != n:
             raise ValueError("the matrix 'M' must be square")
         if not n.mod(4).is_zero():
-            raise ValueError("the matrix 'M' must be a complex embedding")
+            raise ValueError("the matrix 'M' must be a quaternion embedding")
 
         # Use the base ring of the matrix to ensure that its entries can be
         # multiplied by elements of the quaternion algebra.
@@ -1604,6 +1649,16 @@ class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra,
 
         sage: from mjo.eja.eja_algebra import QuaternionHermitianEJA
 
+    EXAMPLES:
+
+    In theory, our "field" can be any subfield of the reals::
+
+        sage: QuaternionHermitianEJA(2, AA)
+        Euclidean Jordan algebra of dimension 6 over Algebraic Real Field
+        sage: QuaternionHermitianEJA(2, RR)
+        Euclidean Jordan algebra of dimension 6 over Real Field with
+        53 bits of precision
+
     TESTS:
 
     The dimension of this algebra is `2*n^2 - n`::
@@ -1704,7 +1759,10 @@ class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra,
                     S.append(Sij_J)
                     Sij_K = cls.real_embed(K*Eij - K*Eij.transpose())
                     S.append(Sij_K)
-        return S
+
+        # Since we embedded these, we can drop back to the "field" that we
+        # started with instead of the quaternion algebra "Q".
+        return ( s.change_ring(field) for s in S )
 
 
     def __init__(self, n, field=QQ, **kwargs):