X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feuclidean_jordan_algebra.py;h=ca344edc709352dea2d1940a7646e058066d4b8d;hb=388d1430380c72c14da47bfab73f7365fa0977f7;hp=59e1537854a09f7058498cdd0959bbc82ccbde8d;hpb=3a5ca72aad3917ad670f5b2e918275a50a00e67c;p=sage.d.git diff --git a/mjo/eja/euclidean_jordan_algebra.py b/mjo/eja/euclidean_jordan_algebra.py index 59e1537..ca344ed 100644 --- a/mjo/eja/euclidean_jordan_algebra.py +++ b/mjo/eja/euclidean_jordan_algebra.py @@ -21,7 +21,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): assume_associative=False, category=None, rank=None, - natural_basis=None): + natural_basis=None, + inner_product=None): n = len(mult_table) mult_table = [b.base_extend(field) for b in mult_table] for b in mult_table: @@ -45,7 +46,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): names=names, category=cat, rank=rank, - natural_basis=natural_basis) + natural_basis=natural_basis, + inner_product=inner_product) def __init__(self, field, @@ -54,7 +56,8 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): assume_associative=False, category=None, rank=None, - natural_basis=None): + natural_basis=None, + inner_product=None): """ EXAMPLES: @@ -70,6 +73,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): """ self._rank = rank self._natural_basis = natural_basis + self._inner_product = inner_product fda = super(FiniteDimensionalEuclideanJordanAlgebra, self) fda.__init__(field, mult_table, @@ -85,6 +89,20 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): return fmt.format(self.degree(), self.base_ring()) + def inner_product(self, x, y): + """ + The inner product associated with this Euclidean Jordan algebra. + + Will default to the trace inner product if nothing else. + """ + if (not x in self) or (not y in self): + raise TypeError("arguments must live in this algebra") + if self._inner_product is None: + return x.trace_inner_product(y) + else: + return self._inner_product(x,y) + + def natural_basis(self): """ Return a more-natural representation of this algebra's basis. @@ -208,6 +226,44 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): raise NotImplementedError('irregular element') + def inner_product(self, other): + """ + Return the parent algebra's inner product of myself and ``other``. + + EXAMPLES: + + The inner product in the Jordan spin algebra is the usual + 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: x = vector(QQ,[1,2,3]) + sage: y = vector(QQ,[4,5,6]) + sage: x.inner_product(y) + 32 + sage: J(x).inner_product(J(y)) + 32 + + TESTS: + + Ensure that we can always compute an inner product, and that + it gives us back a real number:: + + 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 + True + + """ + P = self.parent() + if not other in P: + raise TypeError("'other' must live in the same algebra") + + return P.inner_product(self, other) + + def operator_commutes_with(self, other): """ Return whether or not this element operator-commutes @@ -238,7 +294,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): """ if not other in self.parent(): - raise ArgumentError("'other' must live in the same algebra") + raise TypeError("'other' must live in the same algebra") A = self.operator_matrix() B = other.operator_matrix() @@ -328,7 +384,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): # TODO: we can do better once the call to is_invertible() # doesn't crash on irregular elements. #if not self.is_invertible(): - # raise ArgumentError('element is not invertible') + # raise ValueError('element is not invertible') # We do this a little different than the usual recursive # call to a finite-dimensional algebra element, because we @@ -461,6 +517,91 @@ 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): """ @@ -529,92 +670,6 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): return fda_elt.matrix().transpose() - 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 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. @@ -685,7 +740,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): if other is None: other=self elif not other in self.parent(): - raise ArgumentError("'other' must live in the same algebra") + raise TypeError("'other' must live in the same algebra") L = self.operator_matrix() M = other.operator_matrix() @@ -848,7 +903,7 @@ class FiniteDimensionalEuclideanJordanAlgebra(FiniteDimensionalAlgebra): Return the trace inner product of myself and ``other``. """ if not other in self.parent(): - raise ArgumentError("'other' must live in the same algebra") + raise TypeError("'other' must live in the same algebra") return (self*other).trace() @@ -886,7 +941,13 @@ def eja_rn(dimension, field=QQ): Qs = [ matrix(field, dimension, dimension, lambda k,j: 1*(k == j == i)) for i in xrange(dimension) ] - return FiniteDimensionalEuclideanJordanAlgebra(field,Qs,rank=dimension) + # The usual inner product on R^n. + ip = lambda x, y: x.vector().inner_product(y.vector()) + + return FiniteDimensionalEuclideanJordanAlgebra(field, + Qs, + rank=dimension, + inner_product=ip) @@ -1058,7 +1119,7 @@ def _embed_complex_matrix(M): """ n = M.nrows() if M.ncols() != n: - raise ArgumentError("the matrix 'M' must be square") + raise ValueError("the matrix 'M' must be square") field = M.base_ring() blocks = [] for z in M.list(): @@ -1086,9 +1147,9 @@ def _unembed_complex_matrix(M): """ n = ZZ(M.nrows()) if M.ncols() != n: - raise ArgumentError("the matrix 'M' must be square") + raise ValueError("the matrix 'M' must be square") if not n.mod(2).is_zero(): - raise ArgumentError("the matrix 'M' must be a complex embedding") + raise ValueError("the matrix 'M' must be a complex embedding") F = QuadraticField(-1, 'i') i = F.gen() @@ -1216,13 +1277,6 @@ def JordanSpinSimpleEJA(n, field=QQ): sage: e2*e3 0 - In one dimension, this is the reals under multiplication:: - - sage: J1 = JordanSpinSimpleEJA(1) - sage: J2 = eja_rn(1) - sage: J1 == J2 - True - """ Qs = [] id_matrix = identity_matrix(field, n) @@ -1237,7 +1291,13 @@ def JordanSpinSimpleEJA(n, field=QQ): Qi[0,0] = Qi[0,0] * ~field(2) Qs.append(Qi) + # The usual inner product on R^n. + ip = lambda x, y: x.vector().inner_product(y.vector()) + # 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)) + return FiniteDimensionalEuclideanJordanAlgebra(field, + Qs, + rank=min(n,2), + inner_product=ip)