]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_algebra.py
eja: factor out the operator polynomial-matrix construction.
[sage.d.git] / mjo / eja / eja_algebra.py
index af4080b0807d6ac6848849f23edd237657896413..dd1bcf2584449f5b80ef13a669a28946948b3d25 100644 (file)
@@ -166,9 +166,10 @@ from sage.modules.free_module import FreeModule, VectorSpace
 from sage.rings.all import (ZZ, QQ, AA, QQbar, RR, RLF, CLF,
                             PolynomialRing,
                             QuadraticField)
-from mjo.eja.eja_element import FiniteDimensionalEJAElement
+from mjo.eja.eja_element import (CartesianProductEJAElement,
+                                 FiniteDimensionalEJAElement)
 from mjo.eja.eja_operator import FiniteDimensionalEJAOperator
-from mjo.eja.eja_utils import _all2list, _mat2vec
+from mjo.eja.eja_utils import _all2list
 
 def EuclideanJordanAlgebras(field):
     r"""
@@ -366,7 +367,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
 
         if orthonormalize:
             # Now "self._matrix_span" is the vector space of our
-            # algebra coordinates. The variables "X1", "X2",...  refer
+            # algebra coordinates. The variables "X0", "X1",...  refer
             # to the entries of vectors in self._matrix_span. Thus to
             # convert back and forth between the orthonormal
             # coordinates and the given ones, we need to stick the
@@ -870,7 +871,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
 
             sage: J = JordanSpinEJA(3)
             sage: p = J.characteristic_polynomial_of(); p
-            X1^2 - X2^2 - X3^2 + (-2*t)*X1 + t^2
+            X0^2 - X1^2 - X2^2 + (-2*t)*X0 + t^2
             sage: xvec = J.one().to_vector()
             sage: p(*xvec)
             t^2 - 2*t + 1
@@ -919,13 +920,13 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
 
             sage: J = HadamardEJA(2)
             sage: J.coordinate_polynomial_ring()
-            Multivariate Polynomial Ring in X1, X2...
+            Multivariate Polynomial Ring in X0, X1...
             sage: J = RealSymmetricEJA(3,field=QQ,orthonormalize=False)
             sage: J.coordinate_polynomial_ring()
-            Multivariate Polynomial Ring in X1, X2, X3, X4, X5, X6...
+            Multivariate Polynomial Ring in X0, X1, X2, X3, X4, X5...
 
         """
-        var_names = tuple( "X%d" % z for z in range(1, self.dimension()+1) )
+        var_names = tuple( "X%d" % z for z in range(self.dimension()) )
         return PolynomialRing(self.base_ring(), var_names)
 
     def inner_product(self, x, y):
@@ -1281,7 +1282,9 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         #
         # Of course, matrices aren't vectors in sage, so we have to
         # appeal to the "long vectors" isometry.
-        oper_vecs = [ _mat2vec(g.operator().matrix()) for g in self.gens() ]
+
+        V = VectorSpace(self.base_ring(), self.dimension()**2)
+        oper_vecs = [ V(g.operator().matrix().list()) for g in self.gens() ]
 
         # Now we use basic linear algebra to find the coefficients,
         # of the matrices-as-vectors-linear-combination, which should
@@ -1291,7 +1294,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         # We used the isometry on the left-hand side already, but we
         # still need to do it for the right-hand side. Recall that we
         # wanted something that summed to the identity matrix.
-        b = _mat2vec( matrix.identity(self.base_ring(), self.dimension()) )
+        b = V( matrix.identity(self.base_ring(), self.dimension()).list() )
 
         # Now if there's an identity element in the algebra, this
         # should work. We solve on the left to avoid having to
@@ -1515,6 +1518,64 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
                       for idx in range(count) )
 
 
+    def operator_polynomial_matrix(self):
+        r"""
+        Return the matrix of polynomials (over this algebra's
+        :meth:`coordinate_polynomial_ring`) that, when evaluated at
+        the basis coordinates of an element `x`, produces the basis
+        representation of `L_{x}`.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import (HadamardEJA,
+            ....:                                  JordanSpinEJA)
+
+        EXAMPLES::
+
+            sage: J = HadamardEJA(4)
+            sage: L_x = J.operator_polynomial_matrix()
+            sage: L_x
+            [X0  0  0  0]
+            [ 0 X1  0  0]
+            [ 0  0 X2  0]
+            [ 0  0  0 X3]
+            sage: x = J.one()
+            sage: d = zip(J.coordinate_polynomial_ring().gens(), x.to_vector())
+            sage: L_x.subs(dict(d))
+            [1 0 0 0]
+            [0 1 0 0]
+            [0 0 1 0]
+            [0 0 0 1]
+
+        ::
+
+            sage: J = JordanSpinEJA(4)
+            sage: L_x = J.operator_polynomial_matrix()
+            sage: L_x
+            [X0 X1 X2 X3]
+            [X1 X0  0  0]
+            [X2  0 X0  0]
+            [X3  0  0 X0]
+            sage: x = J.one()
+            sage: d = zip(J.coordinate_polynomial_ring().gens(), x.to_vector())
+            sage: L_x.subs(dict(d))
+            [1 0 0 0]
+            [0 1 0 0]
+            [0 0 1 0]
+            [0 0 0 1]
+
+        """
+        R = self.coordinate_polynomial_ring()
+
+        def L_x_i_j(i,j):
+            # From a result in my book, these are the entries of the
+            # basis representation of L_x.
+            return sum( v*self.monomial(k).operator().matrix()[i,j]
+                        for (k,v) in enumerate(R.gens()) )
+
+        n = self.dimension()
+        return matrix(R, n, n, L_x_i_j)
+
     @cached_method
     def _charpoly_coefficients(self):
         r"""
@@ -1538,16 +1599,9 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         """
         n = self.dimension()
         R = self.coordinate_polynomial_ring()
-        vars = R.gens()
         F = R.fraction_field()
 
-        def L_x_i_j(i,j):
-            # From a result in my book, these are the entries of the
-            # basis representation of L_x.
-            return sum( vars[k]*self.monomial(k).operator().matrix()[i,j]
-                        for k in range(n) )
-
-        L_x = matrix(F, n, n, L_x_i_j)
+        L_x = self.operator_polynomial_matrix()
 
         r = None
         if self.rank.is_in_cache():
@@ -1768,7 +1822,7 @@ class RationalBasisEJA(FiniteDimensionalEJA):
 
             sage: J = JordanSpinEJA(3)
             sage: J._charpoly_coefficients()
-            (X1^2 - X2^2 - X3^2, -2*X1)
+            (X0^2 - X1^2 - X2^2, -2*X0)
             sage: a0 = J._charpoly_coefficients()[0]
             sage: J.base_ring()
             Algebraic Real Field
@@ -2045,7 +2099,6 @@ class MatrixEJA(FiniteDimensionalEJA):
         # if the user passes check_axioms=True.
         if "check_axioms" not in kwargs: kwargs["check_axioms"] = False
 
-
         super().__init__(self._denormalized_basis(matrix_space),
                          self.jordan_product,
                          self.trace_inner_product,
@@ -2140,10 +2193,6 @@ class RealSymmetricEJA(MatrixEJA, RationalBasisEJA, ConcreteEJA):
         return cls(n, **kwargs)
 
     def __init__(self, n, field=AA, **kwargs):
-        # We know this is a valid EJA, but will double-check
-        # if the user passes check_axioms=True.
-        if "check_axioms" not in kwargs: kwargs["check_axioms"] = False
-
         A = MatrixSpace(field, n)
         super().__init__(A, **kwargs)
 
@@ -2227,10 +2276,6 @@ class ComplexHermitianEJA(MatrixEJA, RationalBasisEJA, ConcreteEJA):
 
     """
     def __init__(self, n, field=AA, **kwargs):
-        # We know this is a valid EJA, but will double-check
-        # if the user passes check_axioms=True.
-        if "check_axioms" not in kwargs: kwargs["check_axioms"] = False
-
         from mjo.hurwitz import ComplexMatrixAlgebra
         A = ComplexMatrixAlgebra(n, scalars=field)
         super().__init__(A, **kwargs)
@@ -2317,10 +2362,6 @@ class QuaternionHermitianEJA(MatrixEJA, RationalBasisEJA, ConcreteEJA):
 
     """
     def __init__(self, n, field=AA, **kwargs):
-        # We know this is a valid EJA, but will double-check
-        # if the user passes check_axioms=True.
-        if "check_axioms" not in kwargs: kwargs["check_axioms"] = False
-
         from mjo.hurwitz import QuaternionMatrixAlgebra
         A = QuaternionMatrixAlgebra(n, scalars=field)
         super().__init__(A, **kwargs)
@@ -3100,6 +3141,7 @@ class CartesianProductEJA(FiniteDimensionalEJA):
         sage: actual == expected             # long time
         True
     """
+    Element = CartesianProductEJAElement
     def __init__(self, factors, **kwargs):
         m = len(factors)
         if m == 0:
@@ -3203,6 +3245,34 @@ class CartesianProductEJA(FiniteDimensionalEJA):
         ones = tuple(J.one().to_matrix() for J in factors)
         self.one.set_cache(self(ones))
 
+    def _sets_keys(self):
+        r"""
+
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
+            ....:                                  RealSymmetricEJA)
+
+        TESTS:
+
+        The superclass uses ``_sets_keys()`` to implement its
+        ``cartesian_factors()`` method::
+
+            sage: J1 = RealSymmetricEJA(2,
+            ....:                       field=QQ,
+            ....:                       orthonormalize=False,
+            ....:                       prefix="a")
+            sage: J2 = ComplexHermitianEJA(2,field=QQ,orthonormalize=False)
+            sage: J = cartesian_product([J1,J2])
+            sage: x = sum(i*J.gens()[i] for i in range(len(J.gens())))
+            sage: x.cartesian_factors()
+            (a1 + 2*a2, 3*b0 + 4*b1 + 5*b2 + 6*b3)
+
+        """
+        # Copy/pasted from CombinatorialFreeModule_CartesianProduct,
+        # but returning a tuple instead of a list.
+        return tuple(range(len(self.cartesian_factors())))
+
     def cartesian_factors(self):
         # Copy/pasted from CombinatorialFreeModule_CartesianProduct.
         return self._sets