X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feuclidean_jordan_algebra.py;h=8d9b27e974fff75f769579853d7ac60716d26298;hb=1ba0ab4b33fe1a38d748a0fbbcdd2a63893a9ee8;hp=e2d644a903d8eca09a585064f96e31278197e4d6;hpb=2a3d7383e72864ac42a532c6c4250cdc45b4c363;p=sage.d.git diff --git a/mjo/eja/euclidean_jordan_algebra.py b/mjo/eja/euclidean_jordan_algebra.py index e2d644a..8d9b27e 100644 --- a/mjo/eja/euclidean_jordan_algebra.py +++ b/mjo/eja/euclidean_jordan_algebra.py @@ -20,7 +20,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): names='e', assume_associative=False, category=None, - rank=None): + rank=None, + natural_basis=None): n = len(mult_table) mult_table = [b.base_extend(field) for b in mult_table] for b in mult_table: @@ -43,7 +44,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): assume_associative=assume_associative, names=names, category=cat, - rank=rank) + rank=rank, + natural_basis=natural_basis) def __init__(self, field, @@ -51,7 +53,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): names='e', assume_associative=False, category=None, - rank=None): + rank=None, + natural_basis=None): """ EXAMPLES: @@ -66,6 +69,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): """ self._rank = rank + self._natural_basis = natural_basis fda = super(FiniteDimensionalEuclideanJordanAlgebra, self) fda.__init__(field, mult_table, @@ -80,6 +84,49 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): fmt = "Euclidean Jordan algebra of degree {} over {}" return fmt.format(self.degree(), self.base_ring()) + + def natural_basis(self): + """ + Return a more-natural representation of this algebra's basis. + + 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" basis + for our underlying vector space. (Typically, the natural basis + is used to construct the multiplication table in the first place.) + + Note that this will always return a matrix. The standard basis + in `R^n` will be returned as `n`-by-`1` column matrices. + + EXAMPLES:: + + sage: J = RealSymmetricSimpleEJA(2) + sage: J.basis() + Family (e0, e1, e2) + sage: J.natural_basis() + ( + [1 0] [0 1] [0 0] + [0 0], [1 0], [0 1] + ) + + :: + + sage: J = JordanSpinSimpleEJA(2) + sage: J.basis() + Family (e0, e1) + sage: J.natural_basis() + ( + [1] [0] + [0], [1] + ) + + """ + if self._natural_basis is None: + return tuple( b.vector().column() for b in self.basis() ) + else: + return self._natural_basis + + def rank(self): """ Return the rank of this EJA. @@ -414,6 +461,92 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): return self.span_of_powers().dimension() + def minimal_polynomial(self): + """ + EXAMPLES:: + + sage: set_random_seed() + sage: x = random_eja().random_element() + sage: x.degree() == x.minimal_polynomial().degree() + True + + :: + + sage: set_random_seed() + sage: x = random_eja().random_element() + sage: x.degree() == x.minimal_polynomial().degree() + True + + 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:: + + sage: set_random_seed() + sage: n = ZZ.random_element(2,10) + sage: J = JordanSpinSimpleEJA(n) + sage: y = J.random_element() + sage: while y == y.coefficient(0)*J.one(): + ....: y = J.random_element() + sage: y0 = y.vector()[0] + sage: y_bar = y.vector()[1:] + sage: actual = y.minimal_polynomial() + sage: x = SR.symbol('x', domain='real') + sage: expected = x^2 - 2*y0*x + (y0^2 - norm(y_bar)^2) + sage: bool(actual == expected) + True + + """ + # The element we're going to call "minimal_polynomial()" on. + # Either myself, interpreted as an element of a finite- + # dimensional algebra, or an element of an associative + # subalgebra. + elt = None + + if self.parent().is_associative(): + elt = FiniteDimensionalAlgebraElement(self.parent(), self) + else: + V = self.span_of_powers() + assoc_subalg = self.subalgebra_generated_by() + # Mis-design warning: the basis used for span_of_powers() + # and subalgebra_generated_by() must be the same, and in + # the same order! + elt = assoc_subalg(V.coordinates(self.vector())) + + # Recursive call, but should work since elt lives in an + # associative algebra. + return elt.minimal_polynomial() + + + def natural_representation(self): + """ + Return a more-natural representation of this element. + + 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. + + EXAMPLES:: + + sage: J = ComplexHermitianSimpleEJA(3) + sage: J.one() + e0 + e5 + e8 + sage: J.one().natural_representation() + [1 0 0 0 0 0] + [0 1 0 0 0 0] + [0 0 1 0 0 0] + [0 0 0 1 0 0] + [0 0 0 0 1 0] + [0 0 0 0 0 1] + + """ + B = self.parent().natural_basis() + W = B[0].matrix_space() + return W.linear_combination(zip(self.vector(), B)) + + def operator_matrix(self): """ Return the matrix that represents left- (or right-) @@ -481,64 +614,6 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): return fda_elt.matrix().transpose() - - def minimal_polynomial(self): - """ - EXAMPLES:: - - sage: set_random_seed() - sage: x = random_eja().random_element() - sage: x.degree() == x.minimal_polynomial().degree() - True - - :: - - sage: set_random_seed() - sage: x = random_eja().random_element() - sage: x.degree() == x.minimal_polynomial().degree() - True - - 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:: - - sage: set_random_seed() - sage: n = ZZ.random_element(2,10) - sage: J = JordanSpinSimpleEJA(n) - sage: y = J.random_element() - sage: while y == y.coefficient(0)*J.one(): - ....: y = J.random_element() - sage: y0 = y.vector()[0] - sage: y_bar = y.vector()[1:] - sage: actual = y.minimal_polynomial() - sage: x = SR.symbol('x', domain='real') - sage: expected = x^2 - 2*y0*x + (y0^2 - norm(y_bar)^2) - sage: bool(actual == expected) - True - - """ - # The element we're going to call "minimal_polynomial()" on. - # Either myself, interpreted as an element of a finite- - # dimensional algebra, or an element of an associative - # subalgebra. - elt = None - - if self.parent().is_associative(): - elt = FiniteDimensionalAlgebraElement(self.parent(), self) - else: - V = self.span_of_powers() - assoc_subalg = self.subalgebra_generated_by() - # Mis-design warning: the basis used for span_of_powers() - # and subalgebra_generated_by() must be the same, and in - # the same order! - elt = assoc_subalg(V.coordinates(self.vector())) - - # Recursive call, but should work since elt lives in an - # associative algebra. - return elt.minimal_polynomial() - - def quadratic_representation(self, other=None): """ Return the quadratic representation of this element. @@ -865,7 +940,7 @@ def _real_symmetric_basis(n, field=QQ): # Beware, orthogonal but not normalized! Sij = Eij + Eij.transpose() S.append(Sij) - return S + return tuple(S) def _complex_hermitian_basis(n, field=QQ): @@ -902,7 +977,7 @@ def _complex_hermitian_basis(n, field=QQ): S.append(Sij_real) Sij_imag = _embed_complex_matrix(I*Eij - I*Eij.transpose()) S.append(Sij_imag) - return S + return tuple(S) def _multiplication_table_from_matrix_basis(basis): @@ -912,7 +987,10 @@ def _multiplication_table_from_matrix_basis(basis): multiplication on the right is matrix multiplication. Given a basis for the underlying matrix space, this function returns a multiplication table (obtained by looping through the basis - elements) for an algebra of those matrices. + elements) for an algebra of those matrices. A reordered copy + of the basis is also returned to work around the fact that + the ``span()`` in this function will change the order of the basis + from what we think it is, to... something else. """ # In S^2, for example, we nominally have four coordinates even # though the space is of dimension three only. The vector space V @@ -934,7 +1012,7 @@ def _multiplication_table_from_matrix_basis(basis): # Taking the span above reorders our basis (thanks, jerk!) so we # need to put our "matrix basis" in the same order as the # (reordered) vector basis. - S = [ vec2mat(b) for b in W.basis() ] + S = tuple( vec2mat(b) for b in W.basis() ) Qs = [] for s in S: @@ -952,7 +1030,7 @@ def _multiplication_table_from_matrix_basis(basis): Q = matrix(field, W.dimension(), Q_rows) Qs.append(Q) - return Qs + return (Qs, S) def _embed_complex_matrix(M): @@ -1059,9 +1137,12 @@ def RealSymmetricSimpleEJA(n, field=QQ): """ S = _real_symmetric_basis(n, field=field) - Qs = _multiplication_table_from_matrix_basis(S) + (Qs, T) = _multiplication_table_from_matrix_basis(S) - return FiniteDimensionalEuclideanJordanAlgebra(field,Qs,rank=n) + return FiniteDimensionalEuclideanJordanAlgebra(field, + Qs, + rank=n, + natural_basis=T) def ComplexHermitianSimpleEJA(n, field=QQ): @@ -1083,8 +1164,11 @@ def ComplexHermitianSimpleEJA(n, field=QQ): """ S = _complex_hermitian_basis(n) - Qs = _multiplication_table_from_matrix_basis(S) - return FiniteDimensionalEuclideanJordanAlgebra(field, Qs, rank=n) + (Qs, T) = _multiplication_table_from_matrix_basis(S) + return FiniteDimensionalEuclideanJordanAlgebra(field, + Qs, + rank=n, + natural_basis=T) def QuaternionHermitianSimpleEJA(n):