X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Feja%2Feuclidean_jordan_algebra.py;h=a73cfaf689c7206f7644e10021006e4bcf6f08f7;hb=d284bd1283830bfa1417b30c592b529a1cd1f47b;hp=8d9b27e974fff75f769579853d7ac60716d26298;hpb=1ba0ab4b33fe1a38d748a0fbbcdd2a63893a9ee8;p=sage.d.git diff --git a/mjo/eja/euclidean_jordan_algebra.py b/mjo/eja/euclidean_jordan_algebra.py index 8d9b27e..a73cfaf 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,62 @@ 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 + + The inner product on `S^n` is ` = trace(X*Y)`, where + multiplication is the usual matrix multiplication in `S^n`, + so the inner product of the identity matrix with itself + should be the `n`:: + + sage: J = RealSymmetricSimpleEJA(3) + sage: J.one().inner_product(J.one()) + 3 + + Likewise, the inner product on `C^n` is ` = + Re(trace(X*Y))`, where we must necessarily take the real + part because the product of Hermitian matrices may not be + Hermitian:: + + sage: J = ComplexHermitianSimpleEJA(3) + sage: J.one().inner_product(J.one()) + 3 + + 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 +312,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 +402,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 @@ -684,7 +758,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() @@ -847,7 +921,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() @@ -885,7 +959,10 @@ 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) + return FiniteDimensionalEuclideanJordanAlgebra(field, + Qs, + rank=dimension, + inner_product=_usual_ip) @@ -1057,7 +1134,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(): @@ -1085,9 +1162,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() @@ -1099,14 +1176,26 @@ def _unembed_complex_matrix(M): for j in xrange(n/2): submat = M[2*k:2*k+2,2*j:2*j+2] if submat[0,0] != submat[1,1]: - raise ArgumentError('bad real submatrix') + raise ValueError('bad real submatrix') if submat[0,1] != -submat[1,0]: - raise ArgumentError('bad imag submatrix') + raise ValueError('bad imag submatrix') z = submat[0,0] + submat[1,0]*i elements.append(z) return matrix(F, n/2, elements) +# The usual inner product on R^n. +def _usual_ip(x,y): + return x.vector().inner_product(y.vector()) + +# The inner product used for the real symmetric simple EJA. +# We keep it as a separate function because e.g. the complex +# algebra uses the same inner product, except divided by 2. +def _matrix_ip(X,Y): + X_mat = X.natural_representation() + Y_mat = Y.natural_representation() + return (X_mat*Y_mat).trace() + def RealSymmetricSimpleEJA(n, field=QQ): """ @@ -1142,7 +1231,8 @@ def RealSymmetricSimpleEJA(n, field=QQ): return FiniteDimensionalEuclideanJordanAlgebra(field, Qs, rank=n, - natural_basis=T) + natural_basis=T, + inner_product=_matrix_ip) def ComplexHermitianSimpleEJA(n, field=QQ): @@ -1165,10 +1255,21 @@ def ComplexHermitianSimpleEJA(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 + return FiniteDimensionalEuclideanJordanAlgebra(field, Qs, rank=n, - natural_basis=T) + natural_basis=T, + inner_product=ip) def QuaternionHermitianSimpleEJA(n): @@ -1217,10 +1318,10 @@ def JordanSpinSimpleEJA(n, field=QQ): In one dimension, this is the reals under multiplication:: - sage: J1 = JordanSpinSimpleEJA(1) - sage: J2 = eja_rn(1) - sage: J1 == J2 - True + sage: J1 = JordanSpinSimpleEJA(1) + sage: J2 = eja_rn(1) + sage: J1 == J2 + True """ Qs = [] @@ -1239,4 +1340,7 @@ def JordanSpinSimpleEJA(n, field=QQ): # 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=_usual_ip)