X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feja_algebra.py;h=0a260653a7c5480acea6ffc00a9158169e4e7a18;hb=7a4d25a9e4be093d2452ffb1e5a9834abcb33553;hp=4b8d466c3456f9ec1daf6ca2d701f3078a3524d1;hpb=ef4a0674cdc17613ce65103fc679506e7c7008de;p=sage.d.git diff --git a/mjo/eja/eja_algebra.py b/mjo/eja/eja_algebra.py index 4b8d466..0a26065 100644 --- a/mjo/eja/eja_algebra.py +++ b/mjo/eja/eja_algebra.py @@ -17,7 +17,7 @@ from sage.misc.lazy_import import lazy_import from sage.misc.prandom import choice from sage.misc.table import table from sage.modules.free_module import FreeModule, VectorSpace -from sage.rings.all import (ZZ, QQ, RR, RLF, CLF, +from sage.rings.all import (ZZ, QQ, AA, QQbar, RR, RLF, CLF, PolynomialRing, QuadraticField) from mjo.eja.eja_element import FiniteDimensionalEuclideanJordanAlgebraElement @@ -207,8 +207,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule): Ensure that it says what we think it says:: - sage: JordanSpinEJA(2, field=QQ) - Euclidean Jordan algebra of dimension 2 over Rational Field + sage: JordanSpinEJA(2, field=AA) + Euclidean Jordan algebra of dimension 2 over Algebraic Real Field sage: JordanSpinEJA(3, field=RDF) Euclidean Jordan algebra of dimension 3 over Real Double Field @@ -551,8 +551,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule): Finite family {0: e0, 1: e1, 2: e2} sage: J.natural_basis() ( - [1 0] [ 0 1/2*sqrt2] [0 0] - [0 0], [1/2*sqrt2 0], [0 1] + [1 0] [ 0 0.7071067811865475?] [0 0] + [0 0], [0.7071067811865475? 0], [0 1] ) :: @@ -757,7 +757,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule): J5 = VectorSpace(self.base_ring(), 0) # eigenvalue one-half J1 = trivial # eigenvalue one - for (eigval, eigspace) in c.operator().matrix().left_eigenspaces(): + for (eigval, eigspace) in c.operator().matrix().right_eigenspaces(): if eigval == ~(self.base_ring()(2)): J5 = eigspace else: @@ -773,10 +773,9 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule): return (J0, J5, J1) - def orthogonal_idempotents(self): + def a_jordan_frame(self): r""" - Generate a set of `r` orthogonal idempotents for this algebra, - where `r` is its rank. + Generate a Jordan frame for this algebra. This implementation is based on the so-called "central orthogonal idempotents" implemented for (semisimple) centers @@ -798,9 +797,50 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule): Beware that Koecher defines the "center" of a Jordan algebra to be something else, because the usual definition is stupid in a (necessarily commutative) Jordan algebra. + + SETUP:: + + sage: from mjo.eja.eja_algebra import (random_eja, + ....: JordanSpinEJA, + ....: TrivialEJA) + + EXAMPLES: + + A Jordan frame for the trivial algebra has to be empty + (zero-length) since its rank is zero. More to the point, there + are no non-zero idempotents in the trivial EJA. This does not + cause any problems so long as we adopt the convention that the + empty sum is zero, since then the sole element of the trivial + EJA has an (empty) spectral decomposition:: + + sage: J = TrivialEJA() + sage: J.a_jordan_frame() + () + + A one-dimensional algebra has rank one (equal to its dimension), + and only one primitive idempotent, namely the algebra's unit + element:: + + sage: J = JordanSpinEJA(1) + sage: J.a_jordan_frame() + (e0,) + + TESTS:: + + sage: J = random_eja() + sage: c = J.a_jordan_frame() + sage: all( x^2 == x for x in c ) + True + sage: r = len(c) + sage: all( c[i]*c[j] == c[i]*(i==j) for i in range(r) + ....: for j in range(r) ) + True + """ + if self.dimension() == 0: + return () if self.dimension() == 1: - return [self.one()] + return (self.one(),) for g in self.gens(): eigenpairs = g.operator().matrix().right_eigenspaces() @@ -817,13 +857,16 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule): # two dimensional). s = FiniteDimensionalEuclideanJordanSubalgebra(self, sb) subalgebras.append(s) - except: - pass + except ArithmeticError as e: + if str(e) == "vector is not in free module": + # Ignore only the "not a sub-EJA" error + pass + if len(subalgebras) >= 2: # apply this method recursively. return tuple( c.superalgebra_element() for subalgebra in subalgebras - for c in subalgebra.orthogonal_idempotents() ) + for c in subalgebra.a_jordan_frame() ) # If we got here, the algebra didn't decompose, at least not when we looked at # the eigenspaces corresponding only to basis elements of the algebra. The @@ -970,7 +1013,7 @@ class KnownRankEJA(object): return 5 @classmethod - def random_instance(cls, field=QQ, **kwargs): + def random_instance(cls, field=AA, **kwargs): """ Return a random instance of this type of algebra. @@ -1026,7 +1069,7 @@ class HadamardEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA): (r0, r1, r2) """ - def __init__(self, n, field=QQ, **kwargs): + def __init__(self, n, field=AA, **kwargs): V = VectorSpace(field, n) mult_table = [ [ V.gen(i)*(i == j) for j in range(n) ] for i in range(n) ] @@ -1059,7 +1102,7 @@ class HadamardEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA): return x.to_vector().inner_product(y.to_vector()) -def random_eja(field=QQ, nontrivial=False): +def random_eja(field=AA, nontrivial=False): """ Return a "random" finite-dimensional Euclidean Jordan Algebra. @@ -1279,8 +1322,8 @@ class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra, KnownRankEJA): 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, RDF) + Euclidean Jordan algebra of dimension 3 over Real Double Field sage: RealSymmetricEJA(2, RR) Euclidean Jordan algebra of dimension 3 over Real Field with 53 bits of precision @@ -1372,7 +1415,7 @@ class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra, KnownRankEJA): return 4 # Dimension 10 - def __init__(self, n, field=QQ, **kwargs): + def __init__(self, n, field=AA, **kwargs): basis = self._denormalized_basis(n, field) super(RealSymmetricEJA, self).__init__(field, basis, n, **kwargs) @@ -1392,7 +1435,7 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra): EXAMPLES:: - sage: F = QuadraticField(-1, 'i') + sage: F = QuadraticField(-1, 'I') sage: x1 = F(4 - 2*i) sage: x2 = F(1 + 2*i) sage: x3 = F(-i) @@ -1412,7 +1455,7 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra): sage: set_random_seed() sage: n_max = ComplexMatrixEuclideanJordanAlgebra._max_test_case_size() sage: n = ZZ.random_element(n_max) - sage: F = QuadraticField(-1, 'i') + sage: F = QuadraticField(-1, 'I') sage: X = random_matrix(F, n) sage: Y = random_matrix(F, n) sage: Xe = ComplexMatrixEuclideanJordanAlgebra.real_embed(X) @@ -1455,15 +1498,15 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra): ....: [ 9, 10, 11, 12], ....: [-10, 9, -12, 11] ]) sage: ComplexMatrixEuclideanJordanAlgebra.real_unembed(A) - [ 2*i + 1 4*i + 3] - [ 10*i + 9 12*i + 11] + [ 2*I + 1 4*I + 3] + [ 10*I + 9 12*I + 11] TESTS: Unembedding is the inverse of embedding:: sage: set_random_seed() - sage: F = QuadraticField(-1, 'i') + sage: F = QuadraticField(-1, 'I') sage: M = random_matrix(F, 3) sage: Me = ComplexMatrixEuclideanJordanAlgebra.real_embed(M) sage: ComplexMatrixEuclideanJordanAlgebra.real_unembed(Me) == M @@ -1481,7 +1524,12 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra): field = M.base_ring() R = PolynomialRing(field, 'z') z = R.gen() - F = field.extension(z**2 + 1, 'i', embedding=CLF(-1).sqrt()) + 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 + else: + F = field.extension(z**2 + 1, 'I', embedding=CLF(-1).sqrt()) i = F.gen() # Go top-left to bottom-right (reading order), converting every @@ -1522,7 +1570,7 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra): sage: Ye = y.natural_representation() sage: X = ComplexHermitianEJA.real_unembed(Xe) sage: Y = ComplexHermitianEJA.real_unembed(Ye) - sage: expected = (X*Y).trace().vector()[0] + sage: expected = (X*Y).trace().real() sage: actual = ComplexHermitianEJA.natural_inner_product(Xe,Ye) sage: actual == expected True @@ -1546,8 +1594,8 @@ class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra, KnownRankEJA): 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, RDF) + Euclidean Jordan algebra of dimension 4 over Real Double Field sage: ComplexHermitianEJA(2, RR) Euclidean Jordan algebra of dimension 4 over Real Field with 53 bits of precision @@ -1657,7 +1705,7 @@ class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra, KnownRankEJA): return ( s.change_ring(field) for s in S ) - def __init__(self, n, field=QQ, **kwargs): + def __init__(self, n, field=AA, **kwargs): basis = self._denormalized_basis(n,field) super(ComplexHermitianEJA,self).__init__(field, basis, n, **kwargs) @@ -1709,7 +1757,7 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra): if M.ncols() != n: raise ValueError("the matrix 'M' must be square") - F = QuadraticField(-1, 'i') + F = QuadraticField(-1, 'I') i = F.gen() blocks = [] @@ -1785,10 +1833,10 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra): raise ValueError('bad on-diagonal submatrix') if submat[0,1] != -submat[1,0].conjugate(): raise ValueError('bad off-diagonal submatrix') - z = submat[0,0].vector()[0] # real part - z += submat[0,0].vector()[1]*i # imag part - z += submat[0,1].vector()[0]*j # real part - z += submat[0,1].vector()[1]*k # imag part + z = submat[0,0].real() + z += submat[0,0].imag()*i + z += submat[0,1].real()*j + z += submat[0,1].imag()*k elements.append(z) return matrix(Q, n/4, elements) @@ -1841,8 +1889,8 @@ class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra, 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, RDF) + Euclidean Jordan algebra of dimension 6 over Real Double Field sage: QuaternionHermitianEJA(2, RR) Euclidean Jordan algebra of dimension 6 over Real Field with 53 bits of precision @@ -1953,7 +2001,7 @@ class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra, return ( s.change_ring(field) for s in S ) - def __init__(self, n, field=QQ, **kwargs): + def __init__(self, n, field=AA, **kwargs): basis = self._denormalized_basis(n,field) super(QuaternionHermitianEJA,self).__init__(field, basis, n, **kwargs) @@ -2013,7 +2061,7 @@ class BilinearFormEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA): sage: actual == expected True """ - def __init__(self, n, field=QQ, B=None, **kwargs): + def __init__(self, n, field=AA, B=None, **kwargs): if B is None: self._B = matrix.identity(field, max(0,n-1)) else: @@ -2126,7 +2174,7 @@ class JordanSpinEJA(BilinearFormEJA): True """ - def __init__(self, n, field=QQ, **kwargs): + def __init__(self, n, field=AA, **kwargs): # This is a special case of the BilinearFormEJA with the identity # matrix as its bilinear form. return super(JordanSpinEJA, self).__init__(n, field, **kwargs) @@ -2156,12 +2204,12 @@ class TrivialEJA(FiniteDimensionalEuclideanJordanAlgebra, KnownRankEJA): sage: J.one().norm() 0 sage: J.one().subalgebra_generated_by() - Euclidean Jordan algebra of dimension 0 over Rational Field + Euclidean Jordan algebra of dimension 0 over Algebraic Real Field sage: J.rank() 0 """ - def __init__(self, field=QQ, **kwargs): + def __init__(self, field=AA, **kwargs): mult_table = [] fdeja = super(TrivialEJA, self) # The rank is zero using my definition, namely the dimension of the