X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feja_algebra.py;h=2c689d79d3c85d5d6f4d0daca39ca3f0e649540d;hb=e9845713afb8ed88273d2b8dfe170ca8f11a5290;hp=e24b34890b48a5605184215af7675624e229d7d8;hpb=a0fea53fa276670d9a4c6a44ae9023df58592b88;p=sage.d.git diff --git a/mjo/eja/eja_algebra.py b/mjo/eja/eja_algebra.py index e24b348..2c689d7 100644 --- a/mjo/eja/eja_algebra.py +++ b/mjo/eja/eja_algebra.py @@ -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 @@ -838,7 +852,7 @@ class RealCartesianProductEJA(FiniteDimensionalEuclideanJordanAlgebra, return x.to_vector().inner_product(y.to_vector()) -def random_eja(): +def random_eja(field=QQ): """ Return a "random" finite-dimensional Euclidean Jordan Algebra. @@ -875,7 +889,7 @@ def random_eja(): """ classname = choice(KnownRankEJA.__subclasses__()) - return classname.random_instance() + return classname.random_instance(field=field) @@ -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):