X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feja_element.py;h=9fa8176d112668d6fed446ba5c174c7ebf618fbc;hb=9d365c6cf3b52024817cd2e97b1061216094e3df;hp=de12bb10604094e9b90ffb89a335514c4811d2aa;hpb=a6e62436370d29479f5158d49599ba12e46a437f;p=sage.d.git diff --git a/mjo/eja/eja_element.py b/mjo/eja/eja_element.py index de12bb1..9fa8176 100644 --- a/mjo/eja/eja_element.py +++ b/mjo/eja/eja_element.py @@ -1,14 +1,7 @@ -# -*- coding: utf-8 -*- - from sage.matrix.constructor import matrix from sage.modules.free_module import VectorSpace from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement -# TODO: make this unnecessary somehow. -from sage.misc.lazy_import import lazy_import -lazy_import('mjo.eja.eja_algebra', 'FiniteDimensionalEuclideanJordanAlgebra') -lazy_import('mjo.eja.eja_element_subalgebra', - 'FiniteDimensionalEuclideanJordanElementSubalgebra') from mjo.eja.eja_operator import FiniteDimensionalEuclideanJordanAlgebraOperator from mjo.eja.eja_utils import _mat2vec @@ -183,7 +176,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): True """ - p = self.parent().characteristic_polynomial() + p = self.parent().characteristic_polynomial_of() return p(*self.to_vector()) @@ -347,6 +340,8 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: from mjo.eja.eja_algebra import (JordanSpinEJA, ....: TrivialEJA, + ....: RealSymmetricEJA, + ....: ComplexHermitianEJA, ....: random_eja) EXAMPLES:: @@ -394,6 +389,37 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: x,y = J.random_elements(2) sage: (x*y).det() == x.det()*y.det() True + + The determinant in matrix algebras is just the usual determinant:: + + sage: set_random_seed() + sage: X = matrix.random(QQ,3) + sage: X = X + X.T + sage: J1 = RealSymmetricEJA(3) + sage: J2 = RealSymmetricEJA(3,field=QQ,orthonormalize=False) + sage: expected = X.det() + sage: actual1 = J1(X).det() + sage: actual2 = J2(X).det() + sage: actual1 == expected + True + sage: actual2 == expected + True + + :: + + sage: set_random_seed() + sage: J1 = ComplexHermitianEJA(3) + sage: J2 = ComplexHermitianEJA(3,field=QQ,orthonormalize=False) + sage: X = matrix.random(GaussianIntegers(),3) + sage: X = X + X.H + sage: expected = AA(X.det()) + sage: actual1 = J1(J1.real_embed(X)).det() + sage: actual2 = J2(J2.real_embed(X)).det() + sage: expected == actual1 + True + sage: expected == actual2 + True + """ P = self.parent() r = P.rank() @@ -509,6 +535,14 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): if not self.is_invertible(): raise ValueError("element is not invertible") + if self.parent()._charpoly_coefficients.is_in_cache(): + # We can invert using our charpoly if it will be fast to + # compute. If the coefficients are cached, our rank had + # better be too! + r = self.parent().rank() + a = self.characteristic_polynomial().coefficients(sparse=False) + return (-1)**(r+1)*sum(a[i+1]*self**i for i in range(r))/self.det() + return (~self.quadratic_representation())(self) @@ -522,9 +556,14 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): zero, but we need the characteristic polynomial for the determinant. The minimal polynomial is a lot easier to get, so we use Corollary 2 in Chapter V of Koecher to check - whether or not the paren't algebra's zero element is a root + whether or not the parent algebra's zero element is a root of this element's minimal polynomial. + That is... unless the coefficients of our algebra's + "characteristic polynomial of" function are already cached! + In that case, we just use the determinant (which will be fast + as a result). + Beware that we can't use the superclass method, because it relies on the algebra being associative. @@ -555,6 +594,11 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): else: return False + if self.parent()._charpoly_coefficients.is_in_cache(): + # The determinant will be quicker than computing the minimal + # polynomial from scratch, most likely. + return (not self.det().is_zero()) + # 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() @@ -796,8 +840,9 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: set_random_seed() sage: J = JordanSpinEJA.random_instance() + sage: n = J.dimension() sage: x = J.random_element() - sage: x == x.coefficient(0)*J.one() or x.degree() == 2 + sage: x.degree() == min(n,2) or (x == x.coefficient(0)*J.one()) True TESTS: @@ -904,7 +949,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): two here so that said elements actually exist:: sage: set_random_seed() - sage: n_max = max(2, JordanSpinEJA._max_test_case_size()) + sage: n_max = max(2, JordanSpinEJA._max_random_instance_size()) sage: n = ZZ.random_element(2, n_max) sage: J = JordanSpinEJA(n) sage: y = J.random_element() @@ -930,10 +975,10 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): and in particular, a re-scaling of the basis:: sage: set_random_seed() - sage: n_max = RealSymmetricEJA._max_test_case_size() + sage: n_max = RealSymmetricEJA._max_random_instance_size() sage: n = ZZ.random_element(1, n_max) sage: J1 = RealSymmetricEJA(n) - sage: J2 = RealSymmetricEJA(n,normalize_basis=False) + sage: J2 = RealSymmetricEJA(n,orthonormalize=False) sage: X = random_matrix(AA,n) sage: X = X*X.transpose() sage: x1 = J1(X) @@ -954,20 +999,21 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): # in the "normal" case without us having to think about it. return self.operator().minimal_polynomial() - A = self.subalgebra_generated_by() + A = self.subalgebra_generated_by(orthonormalize_basis=False) return A(self).operator().minimal_polynomial() - def natural_representation(self): + def to_matrix(self): """ - Return a more-natural representation of this element. + Return an (often more natural) representation of this element as a + matrix. - Every finite-dimensional Euclidean Jordan Algebra is a - direct sum of five simple algebras, four of which comprise - Hermitian matrices. This method returns the original - "natural" representation of this element as a Hermitian - matrix, if it has one. If not, you get the usual representation. + Every finite-dimensional Euclidean Jordan Algebra is a direct + sum of five simple algebras, four of which comprise Hermitian + matrices. This method returns a "natural" matrix + representation of this element as either a Hermitian matrix or + column vector. SETUP:: @@ -979,7 +1025,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: J = ComplexHermitianEJA(3) sage: J.one() e0 + e3 + e8 - sage: J.one().natural_representation() + sage: J.one().to_matrix() [1 0 0 0 0 0] [0 1 0 0 0 0] [0 0 1 0 0 0] @@ -992,7 +1038,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: J = QuaternionHermitianEJA(3) sage: J.one() e0 + e5 + e14 - sage: J.one().natural_representation() + sage: J.one().to_matrix() [1 0 0 0 0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0 0 0 0 0] @@ -1005,11 +1051,14 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): [0 0 0 0 0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 0 0 0 0 1] - """ - B = self.parent().natural_basis() - W = self.parent().natural_basis_space() - return W.linear_combination(zip(B,self.to_vector())) + B = self.parent().matrix_basis() + W = self.parent().matrix_space() + + # This is just a manual "from_vector()", but of course + # matrix spaces aren't vector spaces in sage, so they + # don't have a from_vector() method. + return W.linear_combination( zip(B, self.to_vector()) ) def norm(self): @@ -1085,16 +1134,18 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: set_random_seed() sage: x = JordanSpinEJA.random_instance().random_element() sage: x_vec = x.to_vector() + sage: Q = matrix.identity(x.base_ring(), 0) sage: n = x_vec.degree() - sage: x0 = x_vec[0] - sage: x_bar = x_vec[1:] - sage: A = matrix(AA, 1, [x_vec.inner_product(x_vec)]) - sage: B = 2*x0*x_bar.row() - sage: C = 2*x0*x_bar.column() - sage: D = matrix.identity(AA, n-1) - sage: D = (x0^2 - x_bar.inner_product(x_bar))*D - sage: D = D + 2*x_bar.tensor_product(x_bar) - sage: Q = matrix.block(2,2,[A,B,C,D]) + sage: if n > 0: + ....: x0 = x_vec[0] + ....: x_bar = x_vec[1:] + ....: A = matrix(x.base_ring(), 1, [x_vec.inner_product(x_vec)]) + ....: B = 2*x0*x_bar.row() + ....: C = 2*x0*x_bar.column() + ....: D = matrix.identity(x.base_ring(), n-1) + ....: D = (x0^2 - x_bar.inner_product(x_bar))*D + ....: D = D + 2*x_bar.tensor_product(x_bar) + ....: Q = matrix.block(2,2,[A,B,C,D]) sage: Q == x.quadratic_representation().matrix() True @@ -1252,7 +1303,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): sage: (J0, J5, J1) = J.peirce_decomposition(c1) sage: (f0, f1, f2) = J1.gens() sage: f0.spectral_decomposition() - [(0, 1.000000000000000?*f2), (1, 1.000000000000000?*f0)] + [(0, f2), (1, f0)] """ A = self.subalgebra_generated_by(orthonormalize_basis=True) @@ -1308,6 +1359,7 @@ class FiniteDimensionalEuclideanJordanAlgebraElement(IndexedFreeModuleElement): True """ + from mjo.eja.eja_element_subalgebra import FiniteDimensionalEuclideanJordanElementSubalgebra return FiniteDimensionalEuclideanJordanElementSubalgebra(self, orthonormalize_basis)