]> gitweb.michael.orlitzky.com - sage.d.git/commitdiff
eja: add the trace (matrix) operator inner product.
authorMichael Orlitzky <michael@orlitzky.com>
Sun, 29 Jan 2023 20:57:46 +0000 (15:57 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Sun, 29 Jan 2023 21:29:22 +0000 (16:29 -0500)
mjo/eja/eja_element.py

index a832185502c7fafb16879ab3a08084499d3582ab..e1ea609efce334a9800ce162ba74d1342662da41 100644 (file)
@@ -1542,6 +1542,102 @@ class FiniteDimensionalEJAElement(IndexedFreeModuleElement):
         # 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):
         """