X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feja_element.py;h=d9b6eb12fe27363721763fc1e6ccb60c7f98aabd;hb=9528af011cbb4d5e6a38ef972e0d14e7928d5eef;hp=97c048dceb3e299e7a36ac1a15767ebb33af8fad;hpb=16dfa403c6eb709d3a5188a0f19919652b6a225d;p=sage.d.git diff --git a/mjo/eja/eja_element.py b/mjo/eja/eja_element.py index 97c048d..d9b6eb1 100644 --- a/mjo/eja/eja_element.py +++ b/mjo/eja/eja_element.py @@ -1,3 +1,5 @@ +from itertools import izip + from sage.matrix.constructor import matrix from sage.modules.free_module import VectorSpace from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement @@ -78,7 +80,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): elif n == 1: return self else: - return (self.operator()**(n-1))(self) + return (self**(n-1))*self def apply_univariate_polynomial(self, p): @@ -165,6 +167,21 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: x.apply_univariate_polynomial(p) 0 + The characteristic polynomials of the zero and unit elements + should be what we think they are in a subalgebra, too:: + + sage: J = RealCartesianProductEJA(3) + sage: p1 = J.one().characteristic_polynomial() + sage: q1 = J.zero().characteristic_polynomial() + sage: e0,e1,e2 = J.gens() + sage: A = (e0 + 2*e1 + 3*e2).subalgebra_generated_by() # dim 3 + sage: p2 = A.one().characteristic_polynomial() + sage: q2 = A.zero().characteristic_polynomial() + sage: p1 == p2 + True + sage: q1 == q2 + True + """ p = self.parent().characteristic_polynomial() return p(*self.to_vector()) @@ -228,9 +245,8 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: set_random_seed() sage: J = random_eja() - sage: x = J.random_element() - sage: y = J.random_element() - sage: x.inner_product(y) in RR + sage: x,y = J.random_elements(2) + sage: x.inner_product(y) in RLF True """ @@ -265,9 +281,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): Test Lemma 1 from Chapter III of Koecher:: sage: set_random_seed() - sage: J = random_eja() - sage: u = J.random_element() - sage: v = J.random_element() + sage: u,v = random_eja().random_elements(2) sage: lhs = u.operator_commutes_with(u*v) sage: rhs = v.operator_commutes_with(u^2) sage: lhs == rhs @@ -277,9 +291,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): Chapter III, or from Baes (2.3):: sage: set_random_seed() - sage: J = random_eja() - sage: x = J.random_element() - sage: y = J.random_element() + sage: x,y = random_eja().random_elements(2) sage: Lx = x.operator() sage: Ly = y.operator() sage: Lxx = (x*x).operator() @@ -291,10 +303,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): Baes (2.4):: sage: set_random_seed() - sage: J = random_eja() - sage: x = J.random_element() - sage: y = J.random_element() - sage: z = J.random_element() + sage: x,y,z = random_eja().random_elements(3) sage: Lx = x.operator() sage: Ly = y.operator() sage: Lz = z.operator() @@ -308,10 +317,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): Baes (2.5):: sage: set_random_seed() - sage: J = random_eja() - sage: u = J.random_element() - sage: y = J.random_element() - sage: z = J.random_element() + sage: u,y,z = random_eja().random_elements(3) sage: Lu = u.operator() sage: Ly = y.operator() sage: Lz = z.operator() @@ -368,6 +374,15 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: x.is_invertible() == (x.det() != 0) True + Ensure that the determinant is multiplicative on an associative + subalgebra as in Faraut and Koranyi's Proposition II.2.2:: + + sage: set_random_seed() + sage: J = random_eja().random_element().subalgebra_generated_by() + sage: x,y = J.random_elements(2) + sage: (x*y).det() == x.det()*y.det() + True + """ P = self.parent() r = P.rank() @@ -399,8 +414,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): Example 11.11:: sage: set_random_seed() - sage: n = ZZ.random_element(1,10) - sage: J = JordanSpinEJA(n) + sage: J = JordanSpinEJA.random_instance() sage: x = J.random_element() sage: while not x.is_invertible(): ....: x = J.random_element() @@ -482,14 +496,20 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: J.one().is_invertible() True - The zero element is never invertible:: + The zero element is never invertible in a non-trivial algebra:: sage: set_random_seed() sage: J = random_eja() - sage: J.zero().is_invertible() + sage: (not J.is_trivial()) and J.zero().is_invertible() False """ + if self.is_zero(): + if self.parent().is_trivial(): + return True + else: + return False + # In fact, we only need to know if the constant term is non-zero, # so we can pass in the field's zero element instead. zero = self.base_ring().zero() @@ -620,8 +640,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): aren't multiples of the identity are regular:: sage: set_random_seed() - sage: n = ZZ.random_element(1,10) - sage: J = JordanSpinEJA(n) + sage: J = JordanSpinEJA.random_instance() sage: x = J.random_element() sage: x == x.coefficient(0)*J.one() or x.degree() == 2 True @@ -645,6 +664,11 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): True """ + if self.is_zero() and not self.parent().is_trivial(): + # The minimal polynomial of zero in a nontrivial algebra + # is "t"; in a trivial algebra it's "1" by convention + # (it's an empty product). + return 1 return self.subalgebra_generated_by().dimension() @@ -673,6 +697,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): SETUP:: sage: from mjo.eja.eja_algebra import (JordanSpinEJA, + ....: RealSymmetricEJA, ....: random_eja) TESTS: @@ -698,10 +723,12 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): The minimal polynomial and the characteristic polynomial coincide and are known (see Alizadeh, Example 11.11) for all elements of the spin factor algebra that aren't scalar multiples of the - identity:: + identity. We require the dimension of the algebra to be at least + two here so that said elements actually exist:: sage: set_random_seed() - sage: n = ZZ.random_element(2,10) + sage: n_max = max(2, JordanSpinEJA._max_test_case_size()) + sage: n = ZZ.random_element(2, n_max) sage: J = JordanSpinEJA(n) sage: y = J.random_element() sage: while y == y.coefficient(0)*J.one(): @@ -722,7 +749,34 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: x.apply_univariate_polynomial(p) 0 + The minimal polynomial is invariant under a change of basis, + and in particular, a re-scaling of the basis:: + + sage: set_random_seed() + sage: n_max = RealSymmetricEJA._max_test_case_size() + sage: n = ZZ.random_element(1, n_max) + sage: J1 = RealSymmetricEJA(n,QQ) + sage: J2 = RealSymmetricEJA(n,QQ,normalize_basis=False) + sage: X = random_matrix(QQ,n) + sage: X = X*X.transpose() + sage: x1 = J1(X) + sage: x2 = J2(X) + sage: x1.minimal_polynomial() == x2.minimal_polynomial() + True + """ + if self.is_zero(): + # We would generate a zero-dimensional subalgebra + # where the minimal polynomial would be constant. + # That might be correct, but only if *this* algebra + # is trivial too. + if not self.parent().is_trivial(): + # Pretty sure we know what the minimal polynomial of + # the zero operator is going to be. This ensures + # consistency of e.g. the polynomial variable returned + # in the "normal" case without us having to think about it. + return self.operator().minimal_polynomial() + A = self.subalgebra_generated_by() return A(self).operator().minimal_polynomial() @@ -777,8 +831,35 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): """ B = self.parent().natural_basis() - W = B[0].matrix_space() - return W.linear_combination(zip(B,self.to_vector())) + W = self.parent().natural_basis_space() + return W.linear_combination(izip(B,self.to_vector())) + + + def norm(self): + """ + The norm of this element with respect to :meth:`inner_product`. + + SETUP:: + + sage: from mjo.eja.eja_algebra import (JordanSpinEJA, + ....: RealCartesianProductEJA) + + EXAMPLES:: + + sage: J = RealCartesianProductEJA(2) + sage: x = sum(J.gens()) + sage: x.norm() + sqrt(2) + + :: + + sage: J = JordanSpinEJA(4) + sage: x = sum(J.gens()) + sage: x.norm() + 2 + + """ + return self.inner_product(self).sqrt() def operator(self): @@ -794,8 +875,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: set_random_seed() sage: J = random_eja() - sage: x = J.random_element() - sage: y = J.random_element() + sage: x,y = J.random_elements(2) sage: x.operator()(y) == x*y True sage: y.operator()(x) == x*y @@ -826,10 +906,9 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): Alizadeh's Example 11.12:: sage: set_random_seed() - sage: n = ZZ.random_element(1,10) - sage: J = JordanSpinEJA(n) - sage: x = J.random_element() + sage: x = JordanSpinEJA.random_instance().random_element() sage: x_vec = x.to_vector() + sage: n = x_vec.degree() sage: x0 = x_vec[0] sage: x_bar = x_vec[1:] sage: A = matrix(QQ, 1, [x_vec.inner_product(x_vec)]) @@ -846,8 +925,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: set_random_seed() sage: J = random_eja() - sage: x = J.random_element() - sage: y = J.random_element() + sage: x,y = J.random_elements(2) sage: Lx = x.operator() sage: Lxx = (x*x).operator() sage: Qx = x.quadratic_representation() @@ -864,7 +942,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): Property 2 (multiply on the right for :trac:`28272`): - sage: alpha = QQ.random_element() + sage: alpha = J.base_ring().random_element() sage: (alpha*x).quadratic_representation() == Qx*(alpha^2) True @@ -892,10 +970,10 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: not x.is_invertible() or ( ....: x.quadratic_representation(x.inverse())*Qx ....: == - ....: 2*x.operator()*Qex - Qx ) + ....: 2*Lx*Qex - Qx ) True - sage: 2*x.operator()*Qex - Qx == Lxx + sage: 2*Lx*Qex - Qx == Lxx True Property 5: @@ -949,9 +1027,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: set_random_seed() sage: x0 = random_eja().random_element() sage: A = x0.subalgebra_generated_by() - sage: x = A.random_element() - sage: y = A.random_element() - sage: z = A.random_element() + sage: x,y,z = A.random_elements(3) sage: (x*y)*z == x*(y*z) True @@ -969,7 +1045,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: set_random_seed() sage: A = random_eja().zero().subalgebra_generated_by() sage: A - Euclidean Jordan algebra of dimension 0 over Rational Field + Euclidean Jordan algebra of dimension 0 over... sage: A.one() 0 @@ -1062,7 +1138,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: set_random_seed() sage: J = random_eja() - sage: J.random_element().trace() in J.base_ring() + sage: J.random_element().trace() in RLF True """ @@ -1086,22 +1162,17 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): TESTS: - The trace inner product is commutative:: + The trace inner product is commutative, bilinear, and satisfies + the Jordan axiom: sage: set_random_seed() sage: J = random_eja() - sage: x = J.random_element(); y = J.random_element() + sage: x,y,z = J.random_elements(3) + sage: # commutative sage: x.trace_inner_product(y) == y.trace_inner_product(x) True - - The trace inner product is bilinear:: - - sage: set_random_seed() - sage: J = random_eja() - sage: x = J.random_element() - sage: y = J.random_element() - sage: z = J.random_element() - sage: a = QQ.random_element(); + sage: # bilinear + sage: a = J.base_ring().random_element(); sage: actual = (a*(x+z)).trace_inner_product(y) sage: expected = ( a*x.trace_inner_product(y) + ....: a*z.trace_inner_product(y) ) @@ -1112,15 +1183,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): ....: a*x.trace_inner_product(z) ) sage: actual == expected True - - The trace inner product satisfies the compatibility - condition in the definition of a Euclidean Jordan algebra:: - - sage: set_random_seed() - sage: J = random_eja() - sage: x = J.random_element() - sage: y = J.random_element() - sage: z = J.random_element() + sage: # jordan axiom sage: (x*y).trace_inner_product(z) == y.trace_inner_product(x*z) True @@ -1129,3 +1192,30 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): raise TypeError("'other' must live in the same algebra") return (self*other).trace() + + + def trace_norm(self): + """ + The norm of this element with respect to :meth:`trace_inner_product`. + + SETUP:: + + sage: from mjo.eja.eja_algebra import (JordanSpinEJA, + ....: RealCartesianProductEJA) + + EXAMPLES:: + + sage: J = RealCartesianProductEJA(2) + sage: x = sum(J.gens()) + sage: x.trace_norm() + sqrt(2) + + :: + + sage: J = JordanSpinEJA(4) + sage: x = sum(J.gens()) + sage: x.trace_norm() + 2*sqrt(2) + + """ + return self.trace_inner_product(self).sqrt()