ALGORITHM:
- .........
+ First we handle the special cases where the algebra is
+ trivial, this element is zero, or the dimension of the algebra
+ is one and this element is not zero. With those out of the
+ way, we may assume that ``self`` is nonzero, the algebra is
+ nontrivial, and that the dimension of the algebra is at least
+ two.
+
+ Beginning with the algebra's unit element (power zero), we add
+ successive (basis representations of) powers of this element
+ to a matrix, row-reducing at each step. After row-reducing, we
+ check the rank of the matrix. If adding a row and row-reducing
+ does not increase the rank of the matrix at any point, the row
+ we've just added lives in the span of the previous ones; thus
+ the corresponding power of ``self`` lives in the span of its
+ lesser powers. When that happens, the degree of the minimal
+ polynomial is the rank of the matrix; if it never happens, the
+ degree must be the dimension of the entire space.
SETUP::
sage: x = random_eja().random_element()
sage: x.degree() == x.minimal_polynomial().degree()
True
-
"""
n = self.parent().dimension()
where there are non-nilpotent elements, or that we get the dumb
solution in the trivial algebra::
- sage: J = random_eja()
+ sage: J = random_eja(field=QQ, orthonormalize=False)
sage: x = J.random_element()
sage: while x.is_nilpotent() and not J.is_trivial():
....: x = J.random_element()
# we want the negative of THAT for the trace.
return -p(*self.to_vector())
+ def operator_inner_product(self, other):
+ r"""
+ Return the operator inner product of myself and ``other``.
+
+ The "operator inner product," whose name is not standard, is
+ defined be the usual linear-algebraic trace of the
+ ``(x*y).operator()``.
+
+ Proposition III.1.5 in Faraut and Korányi shows that on any
+ Euclidean Jordan algebra, this is another associative inner
+ product under which the cone of squares is symmetric.
+
+ This *probably* works even if the basis hasn't been
+ orthonormalized because the eigenvalues of the corresponding
+ matrix don't change when the basis does (they're preserved by
+ any similarity transformation).
+
+ SETUP::
+
+ sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+ ....: RealSymmetricEJA,
+ ....: ComplexHermitianEJA,
+ ....: random_eja)
+
+ EXAMPLES:
+
+ Proposition III.4.2 of Faraut and Korányi shows that on a
+ simple algebra of rank `r` and dimension `n`, this inner
+ product is `n/r` times the canonical
+ :meth:`trace_inner_product`::
+
+ sage: J = JordanSpinEJA(4, field=QQ)
+ sage: x,y = J.random_elements(2)
+ sage: n = J.dimension()
+ sage: r = J.rank()
+ sage: actual = x.operator_inner_product(y)
+ sage: expected = (n/r)*x.trace_inner_product(y)
+ sage: actual == expected
+ True
+
+ ::
+
+ sage: J = RealSymmetricEJA(3)
+ sage: x,y = J.random_elements(2)
+ sage: n = J.dimension()
+ sage: r = J.rank()
+ sage: actual = x.operator_inner_product(y)
+ sage: expected = (n/r)*x.trace_inner_product(y)
+ sage: actual == expected
+ True
+
+ ::
+
+ sage: J = ComplexHermitianEJA(3, field=QQ, orthonormalize=False)
+ sage: x,y = J.random_elements(2)
+ sage: n = J.dimension()
+ sage: r = J.rank()
+ sage: actual = x.operator_inner_product(y)
+ sage: expected = (n/r)*x.trace_inner_product(y)
+ sage: actual == expected
+ True
+
+ TESTS:
+
+ The operator inner product is commutative, bilinear, and
+ associative::
+
+ sage: J = random_eja()
+ sage: x,y,z = J.random_elements(3)
+ sage: # commutative
+ sage: x.operator_inner_product(y) == y.operator_inner_product(x)
+ True
+ sage: # bilinear
+ sage: a = J.base_ring().random_element()
+ sage: actual = (a*(x+z)).operator_inner_product(y)
+ sage: expected = ( a*x.operator_inner_product(y) +
+ ....: a*z.operator_inner_product(y) )
+ sage: actual == expected
+ True
+ sage: actual = x.operator_inner_product(a*(y+z))
+ sage: expected = ( a*x.operator_inner_product(y) +
+ ....: a*x.operator_inner_product(z) )
+ sage: actual == expected
+ True
+ sage: # associative
+ sage: actual = (x*y).operator_inner_product(z)
+ sage: expected = y.operator_inner_product(x*z)
+ sage: actual == expected
+ True
+
+ """
+ if not other in self.parent():
+ raise TypeError("'other' must live in the same algebra")
+
+ return (self*other).operator().matrix().trace()
+
def trace_inner_product(self, other):
"""
sage: x.trace_inner_product(y) == y.trace_inner_product(x)
True
sage: # bilinear
- sage: a = J.base_ring().random_element();
+ 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) )