X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feuclidean_jordan_algebra.py;h=32481621975ab3aabc217eae5ef72d9abf191980;hb=2cfb1e2864c14542d101334bac962000f85e017d;hp=b8c7a912b1ded8149f7aefdf14b90b99d1056b2b;hpb=2a0cca4f62e8335db7069e04f0837a96b331614a;p=sage.d.git diff --git a/mjo/eja/euclidean_jordan_algebra.py b/mjo/eja/euclidean_jordan_algebra.py index b8c7a91..3248162 100644 --- a/mjo/eja/euclidean_jordan_algebra.py +++ b/mjo/eja/euclidean_jordan_algebra.py @@ -50,7 +50,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): inner_product=inner_product) - def __init__(self, field, + def __init__(self, + field, mult_table, names='e', assume_associative=False, @@ -132,7 +133,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): EXAMPLES:: - sage: J = RealSymmetricSimpleEJA(2) + sage: J = RealSymmetricEJA(2) sage: J.basis() Family (e0, e1, e2) sage: J.natural_basis() @@ -143,7 +144,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): :: - sage: J = JordanSpinSimpleEJA(2) + sage: J = JordanSpinEJA(2) sage: J.basis() Family (e0, e1) sage: J.natural_basis() @@ -180,14 +181,14 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): The identity in `S^n` is converted to the identity in the EJA:: - sage: J = RealSymmetricSimpleEJA(3) + sage: J = RealSymmetricEJA(3) sage: I = identity_matrix(QQ,3) sage: J(I) == J.one() True This skew-symmetric matrix can't be represented in the EJA:: - sage: J = RealSymmetricSimpleEJA(3) + sage: J = RealSymmetricEJA(3) sage: A = matrix(QQ,3, lambda i,j: i-j) sage: J(A) Traceback (most recent call last): @@ -295,7 +296,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): inner product on `R^n` (this example only works because the basis for the Jordan algebra is the standard basis in `R^n`):: - sage: J = JordanSpinSimpleEJA(3) + sage: J = JordanSpinEJA(3) sage: x = vector(QQ,[1,2,3]) sage: y = vector(QQ,[4,5,6]) sage: x.inner_product(y) @@ -308,7 +309,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): so the inner product of the identity matrix with itself should be the `n`:: - sage: J = RealSymmetricSimpleEJA(3) + sage: J = RealSymmetricEJA(3) sage: J.one().inner_product(J.one()) 3 @@ -317,13 +318,13 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): part because the product of Hermitian matrices may not be Hermitian:: - sage: J = ComplexHermitianSimpleEJA(3) + sage: J = ComplexHermitianEJA(3) sage: J.one().inner_product(J.one()) 3 Ditto for the quaternions:: - sage: J = QuaternionHermitianSimpleEJA(3) + sage: J = QuaternionHermitianEJA(3) sage: J.one().inner_product(J.one()) 3 @@ -390,12 +391,12 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): EXAMPLES:: - sage: J = JordanSpinSimpleEJA(2) + sage: J = JordanSpinEJA(2) sage: e0,e1 = J.gens() sage: x = e0 + e1 sage: x.det() 0 - sage: J = JordanSpinSimpleEJA(3) + sage: J = JordanSpinEJA(3) sage: e0,e1,e2 = J.gens() sage: x = e0 + e1 + e2 sage: x.det() @@ -424,7 +425,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): sage: set_random_seed() sage: n = ZZ.random_element(1,10) - sage: J = JordanSpinSimpleEJA(n) + sage: J = JordanSpinEJA(n) sage: x = J.random_element() sage: while x.is_zero(): ....: x = J.random_element() @@ -554,7 +555,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): The identity element always has degree one, but any element linearly-independent from it is regular:: - sage: J = JordanSpinSimpleEJA(5) + sage: J = JordanSpinEJA(5) sage: J.one().is_regular() False sage: e0, e1, e2, e3, e4 = J.gens() # e0 is the identity @@ -579,7 +580,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): EXAMPLES:: - sage: J = JordanSpinSimpleEJA(4) + sage: J = JordanSpinEJA(4) sage: J.one().degree() 1 sage: e0,e1,e2,e3 = J.gens() @@ -591,7 +592,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): sage: set_random_seed() sage: n = ZZ.random_element(1,10) - sage: J = JordanSpinSimpleEJA(n) + sage: J = JordanSpinEJA(n) sage: x = J.random_element() sage: x == x.coefficient(0)*J.one() or x.degree() == 2 True @@ -623,7 +624,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): sage: set_random_seed() sage: n = ZZ.random_element(2,10) - sage: J = JordanSpinSimpleEJA(n) + sage: J = JordanSpinEJA(n) sage: y = J.random_element() sage: while y == y.coefficient(0)*J.one(): ....: y = J.random_element() @@ -669,7 +670,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): EXAMPLES:: - sage: J = ComplexHermitianSimpleEJA(3) + sage: J = ComplexHermitianEJA(3) sage: J.one() e0 + e5 + e8 sage: J.one().natural_representation() @@ -682,7 +683,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): :: - sage: J = QuaternionHermitianSimpleEJA(3) + sage: J = QuaternionHermitianEJA(3) sage: J.one() e0 + e9 + e14 sage: J.one().natural_representation() @@ -783,7 +784,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): sage: set_random_seed() sage: n = ZZ.random_element(1,10) - sage: J = JordanSpinSimpleEJA(n) + sage: J = JordanSpinEJA(n) sage: x = J.random_element() sage: x_vec = x.vector() sage: x0 = x_vec[0] @@ -930,7 +931,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): sage: c = J.random_element().subalgebra_idempotent() sage: c^2 == c True - sage: J = JordanSpinSimpleEJA(5) + sage: J = JordanSpinEJA(5) sage: c = J.random_element().subalgebra_idempotent() sage: c^2 == c True @@ -986,7 +987,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): EXAMPLES:: - sage: J = JordanSpinSimpleEJA(3) + sage: J = JordanSpinEJA(3) sage: e0,e1,e2 = J.gens() sage: x = e0 + e1 + e2 sage: x.trace() @@ -1084,10 +1085,10 @@ def random_eja(): """ n = ZZ.random_element(1,5) constructor = choice([eja_rn, - JordanSpinSimpleEJA, - RealSymmetricSimpleEJA, - ComplexHermitianSimpleEJA, - QuaternionHermitianSimpleEJA]) + JordanSpinEJA, + RealSymmetricEJA, + ComplexHermitianEJA, + QuaternionHermitianEJA]) return constructor(n, field=QQ) @@ -1264,6 +1265,20 @@ def _embed_complex_matrix(M): [ 0 -1| 6 0] [ 1 0| 0 6] + TESTS: + + Embedding is a homomorphism (isomorphism, in fact):: + + sage: set_random_seed() + sage: n = ZZ.random_element(5) + sage: F = QuadraticField(-1, 'i') + sage: X = random_matrix(F, n) + sage: Y = random_matrix(F, n) + sage: actual = _embed_complex_matrix(X) * _embed_complex_matrix(Y) + sage: expected = _embed_complex_matrix(X*Y) + sage: actual == expected + True + """ n = M.nrows() if M.ncols() != n: @@ -1293,7 +1308,9 @@ def _unembed_complex_matrix(M): [ 2*i + 1 4*i + 3] [ 10*i + 9 12*i + 11] - TESTS:: + TESTS: + + Unembedding is the inverse of embedding:: sage: set_random_seed() sage: F = QuadraticField(-1, 'i') @@ -1347,6 +1364,18 @@ def _embed_quaternion_matrix(M): [-3 4 1 -2] [-4 -3 2 1] + Embedding is a homomorphism (isomorphism, in fact):: + + sage: set_random_seed() + sage: n = ZZ.random_element(5) + sage: Q = QuaternionAlgebra(QQ,-1,-1) + sage: X = random_matrix(Q, n) + sage: Y = random_matrix(Q, n) + sage: actual = _embed_quaternion_matrix(X)*_embed_quaternion_matrix(Y) + sage: expected = _embed_quaternion_matrix(X*Y) + sage: actual == expected + True + """ quaternions = M.base_ring() n = M.nrows() @@ -1385,7 +1414,9 @@ def _unembed_quaternion_matrix(M): sage: _unembed_quaternion_matrix(M) [1 + 2*i + 3*j + 4*k] - TESTS:: + TESTS: + + Unembedding is the inverse of embedding:: sage: set_random_seed() sage: Q = QuaternionAlgebra(QQ, -1, -1) @@ -1434,7 +1465,7 @@ def _matrix_ip(X,Y): return (X_mat*Y_mat).trace() -def RealSymmetricSimpleEJA(n, field=QQ): +class RealSymmetricEJA(FiniteDimensionalEuclideanJordanAlgebra): """ The rank-n simple EJA consisting of real symmetric n-by-n matrices, the usual symmetric Jordan product, and the trace inner @@ -1442,7 +1473,7 @@ def RealSymmetricSimpleEJA(n, field=QQ): EXAMPLES:: - sage: J = RealSymmetricSimpleEJA(2) + sage: J = RealSymmetricEJA(2) sage: e0, e1, e2 = J.gens() sage: e0*e0 e0 @@ -1457,7 +1488,7 @@ def RealSymmetricSimpleEJA(n, field=QQ): sage: set_random_seed() sage: n = ZZ.random_element(1,5) - sage: J = RealSymmetricSimpleEJA(n) + sage: J = RealSymmetricEJA(n) sage: J.degree() == (n^2 + n)/2 True @@ -1465,7 +1496,7 @@ def RealSymmetricSimpleEJA(n, field=QQ): sage: set_random_seed() sage: n = ZZ.random_element(1,5) - sage: J = RealSymmetricSimpleEJA(n) + sage: J = RealSymmetricEJA(n) sage: x = J.random_element() sage: y = J.random_element() sage: actual = (x*y).natural_representation() @@ -1478,17 +1509,23 @@ def RealSymmetricSimpleEJA(n, field=QQ): True """ - S = _real_symmetric_basis(n, field=field) - (Qs, T) = _multiplication_table_from_matrix_basis(S) + @staticmethod + def __classcall_private__(cls, n, field=QQ): + S = _real_symmetric_basis(n, field=field) + (Qs, T) = _multiplication_table_from_matrix_basis(S) - return FiniteDimensionalEuclideanJordanAlgebra(field, - Qs, - rank=n, - natural_basis=T, - inner_product=_matrix_ip) + fdeja = super(RealSymmetricEJA, cls) + return fdeja.__classcall_private__(cls, + field, + Qs, + rank=n, + natural_basis=T) + + def inner_product(self, x, y): + return _matrix_ip(x,y) -def ComplexHermitianSimpleEJA(n, field=QQ): +class ComplexHermitianEJA(FiniteDimensionalEuclideanJordanAlgebra): """ The rank-n simple EJA consisting of complex Hermitian n-by-n matrices over the real numbers, the usual symmetric Jordan product, @@ -1501,7 +1538,7 @@ def ComplexHermitianSimpleEJA(n, field=QQ): sage: set_random_seed() sage: n = ZZ.random_element(1,5) - sage: J = ComplexHermitianSimpleEJA(n) + sage: J = ComplexHermitianEJA(n) sage: J.degree() == n^2 True @@ -1509,7 +1546,7 @@ def ComplexHermitianSimpleEJA(n, field=QQ): sage: set_random_seed() sage: n = ZZ.random_element(1,5) - sage: J = ComplexHermitianSimpleEJA(n) + sage: J = ComplexHermitianEJA(n) sage: x = J.random_element() sage: y = J.random_element() sage: actual = (x*y).natural_representation() @@ -1522,26 +1559,30 @@ def ComplexHermitianSimpleEJA(n, field=QQ): True """ - S = _complex_hermitian_basis(n) - (Qs, T) = _multiplication_table_from_matrix_basis(S) + @staticmethod + def __classcall_private__(cls, n, field=QQ): + S = _complex_hermitian_basis(n) + (Qs, T) = _multiplication_table_from_matrix_basis(S) - # Since a+bi on the diagonal is represented as - # - # a + bi = [ a b ] - # [ -b a ], - # - # we'll double-count the "a" entries if we take the trace of - # the embedding. - ip = lambda X,Y: _matrix_ip(X,Y)/2 + fdeja = super(ComplexHermitianEJA, cls) + return fdeja.__classcall_private__(cls, + field, + Qs, + rank=n, + natural_basis=T) - return FiniteDimensionalEuclideanJordanAlgebra(field, - Qs, - rank=n, - natural_basis=T, - inner_product=ip) + def inner_product(self, x, y): + # Since a+bi on the diagonal is represented as + # + # a + bi = [ a b ] + # [ -b a ], + # + # we'll double-count the "a" entries if we take the trace of + # the embedding. + return _matrix_ip(x,y)/2 -def QuaternionHermitianSimpleEJA(n, field=QQ): +class QuaternionHermitianEJA(FiniteDimensionalEuclideanJordanAlgebra): """ The rank-n simple EJA consisting of self-adjoint n-by-n quaternion matrices, the usual symmetric Jordan product, and the @@ -1554,7 +1595,7 @@ def QuaternionHermitianSimpleEJA(n, field=QQ): sage: set_random_seed() sage: n = ZZ.random_element(1,5) - sage: J = QuaternionHermitianSimpleEJA(n) + sage: J = QuaternionHermitianEJA(n) sage: J.degree() == 2*(n^2) - n True @@ -1562,7 +1603,7 @@ def QuaternionHermitianSimpleEJA(n, field=QQ): sage: set_random_seed() sage: n = ZZ.random_element(1,5) - sage: J = QuaternionHermitianSimpleEJA(n) + sage: J = QuaternionHermitianEJA(n) sage: x = J.random_element() sage: y = J.random_element() sage: actual = (x*y).natural_representation() @@ -1575,35 +1616,32 @@ def QuaternionHermitianSimpleEJA(n, field=QQ): True """ - S = _quaternion_hermitian_basis(n) - (Qs, T) = _multiplication_table_from_matrix_basis(S) - - # Since a+bi+cj+dk on the diagonal is represented as - # - # a + bi +cj + dk = [ a b c d] - # [ -b a -d c] - # [ -c d a -b] - # [ -d -c b a], - # - # we'll quadruple-count the "a" entries if we take the trace of - # the embedding. - ip = lambda X,Y: _matrix_ip(X,Y)/4 - - return FiniteDimensionalEuclideanJordanAlgebra(field, - Qs, - rank=n, - natural_basis=T, - inner_product=ip) + @staticmethod + def __classcall_private__(cls, n, field=QQ): + S = _quaternion_hermitian_basis(n) + (Qs, T) = _multiplication_table_from_matrix_basis(S) + fdeja = super(QuaternionHermitianEJA, cls) + return fdeja.__classcall_private__(cls, + field, + Qs, + rank=n, + natural_basis=T) -def OctonionHermitianSimpleEJA(n): - """ - This shit be crazy. It has dimension 27 over the reals. - """ - n = 3 - pass - -def JordanSpinSimpleEJA(n, field=QQ): + def inner_product(self, x, y): + # Since a+bi+cj+dk on the diagonal is represented as + # + # a + bi +cj + dk = [ a b c d] + # [ -b a -d c] + # [ -c d a -b] + # [ -d -c b a], + # + # we'll quadruple-count the "a" entries if we take the trace of + # the embedding. + return _matrix_ip(x,y)/4 + + +class JordanSpinEJA(FiniteDimensionalEuclideanJordanAlgebra): """ The rank-2 simple EJA consisting of real vectors ``x=(x0, x_bar)`` with the usual inner product and jordan product ``x*y = @@ -1614,7 +1652,7 @@ def JordanSpinSimpleEJA(n, field=QQ): This multiplication table can be verified by hand:: - sage: J = JordanSpinSimpleEJA(4) + sage: J = JordanSpinEJA(4) sage: e0,e1,e2,e3 = J.gens() sage: e0*e0 e0 @@ -1631,31 +1669,34 @@ def JordanSpinSimpleEJA(n, field=QQ): sage: e2*e3 0 - In one dimension, this is the reals under multiplication:: + """ + @staticmethod + def __classcall_private__(cls, n, field=QQ): + Qs = [] + id_matrix = identity_matrix(field, n) + for i in xrange(n): + ei = id_matrix.column(i) + Qi = zero_matrix(field, n) + Qi.set_row(0, ei) + Qi.set_column(0, ei) + Qi += diagonal_matrix(n, [ei[0]]*n) + # The addition of the diagonal matrix adds an extra ei[0] in the + # upper-left corner of the matrix. + Qi[0,0] = Qi[0,0] * ~field(2) + Qs.append(Qi) + + fdeja = super(JordanSpinEJA, cls) + return fdeja.__classcall_private__(cls, field, Qs) - sage: J1 = JordanSpinSimpleEJA(1) - sage: J2 = eja_rn(1) - sage: J1 == J2 - True + def rank(self): + """ + Return the rank of this Jordan Spin Algebra. - """ - Qs = [] - id_matrix = identity_matrix(field, n) - for i in xrange(n): - ei = id_matrix.column(i) - Qi = zero_matrix(field, n) - Qi.set_row(0, ei) - Qi.set_column(0, ei) - Qi += diagonal_matrix(n, [ei[0]]*n) - # The addition of the diagonal matrix adds an extra ei[0] in the - # upper-left corner of the matrix. - Qi[0,0] = Qi[0,0] * ~field(2) - Qs.append(Qi) - - # The rank of the spin factor algebra is two, UNLESS we're in a - # one-dimensional ambient space (the rank is bounded by the - # ambient dimension). - return FiniteDimensionalEuclideanJordanAlgebra(field, - Qs, - rank=min(n,2), - inner_product=_usual_ip) + The rank of the spin algebra is two, unless we're in a + one-dimensional ambient space (because the rank is bounded by + the ambient dimension). + """ + return min(self.dimension(),2) + + def inner_product(self, x, y): + return _usual_ip(x,y)