]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/eja/eja_algebra.py
eja: add rational-basis subclass for Cartesian products.
[sage.d.git] / mjo / eja / eja_algebra.py
index 811850586f21048aba1ed07292eaf51f15350fe1..6048363d64402b91326ea599b109c238574f7cf8 100644 (file)
@@ -51,15 +51,15 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         `(a,b)` into column matrices `(a,b)^{T}` after converting
         `a` and `b` themselves.
 
-      - jordan_product -- function of two elements (in matrix form)
-        that returns their jordan product in this algebra; this will
-        be applied to ``basis`` to compute a multiplication table for
-        the algebra.
-
-      - inner_product -- function of two elements (in matrix form) that
-        returns their inner product. This will be applied to ``basis`` to
-        compute an inner-product table (basically a matrix) for this algebra.
-
+      - jordan_product -- function of two ``basis`` elements (in
+        matrix form) that returns their jordan product, also in matrix
+        form; this will be applied to ``basis`` to compute a
+        multiplication table for the algebra.
+
+      - inner_product -- function of two ``basis`` elements (in matrix
+        form) that returns their inner product. This will be applied
+        to ``basis`` to compute an inner-product table (basically a
+        matrix) for this algebra.
     """
     Element = FiniteDimensionalEJAElement
 
@@ -257,6 +257,35 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
 
 
     def product_on_basis(self, i, j):
+        r"""
+        Returns the Jordan product of the `i` and `j`th basis elements.
+
+        This completely defines the Jordan product on the algebra, and
+        is used direclty by our superclass machinery to implement
+        :meth:`product`.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import random_eja
+
+        TESTS::
+
+            sage: set_random_seed()
+            sage: J = random_eja()
+            sage: n = J.dimension()
+            sage: ei = J.zero()
+            sage: ej = J.zero()
+            sage: ei_ej = J.zero()*J.zero()
+            sage: if n > 0:
+            ....:     i = ZZ.random_element(n)
+            ....:     j = ZZ.random_element(n)
+            ....:     ei = J.gens()[i]
+            ....:     ej = J.gens()[j]
+            ....:     ei_ej = J.product_on_basis(i,j)
+            sage: ei*ej == ei_ej
+            True
+
+        """
         # We only stored the lower-triangular portion of the
         # multiplication table.
         if j <= i:
@@ -447,13 +476,23 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
             sage: J(x.to_vector().column()) == x
             True
 
+        We cannot coerce elements between algebras just because their
+        matrix representations are compatible::
+
+            sage: J1 = HadamardEJA(3)
+            sage: J2 = JordanSpinEJA(3)
+            sage: J2(J1.one())
+            Traceback (most recent call last):
+            ...
+            ValueError: not an element of this algebra
+            sage: J1(J2.zero())
+            Traceback (most recent call last):
+            ...
+            ValueError: not an element of this algebra
+
         """
         msg = "not an element of this algebra"
-        if elt == 0:
-            # The superclass implementation of random_element()
-            # needs to be able to coerce "0" into the algebra.
-            return self.zero()
-        elif elt in self.base_ring():
+        if elt in self.base_ring():
             # Ensure that no base ring -> algebra coercion is performed
             # by this method. There's some stupidity in sage that would
             # otherwise propagate to this method; for example, sage thinks
@@ -461,9 +500,11 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
             raise ValueError(msg)
 
         try:
+            # Try to convert a vector into a column-matrix...
             elt = elt.column()
         except (AttributeError, TypeError):
-            # Try to convert a vector into a column-matrix
+            # and ignore failure, because we weren't really expecting
+            # a vector as an argument anyway.
             pass
 
         if elt not in self.matrix_space():
@@ -477,7 +518,7 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         # could be QQ instead of QQbar.
         #
         # And, we also have to handle Cartesian product bases (when
-        # the matric basis consists of tuples) here. The "good news"
+        # the matrix basis consists of tuples) here. The "good news"
         # is that we're already converting everything to long vectors,
         # and that strategy works for tuples as well.
         #
@@ -787,12 +828,49 @@ class FiniteDimensionalEJA(CombinatorialFreeModule):
         we think of them as matrices (including column vectors of the
         appropriate size).
 
-        Generally this will be an `n`-by-`1` column-vector space,
+        "By default" this will be an `n`-by-`1` column-matrix space,
         except when the algebra is trivial. There it's `n`-by-`n`
         (where `n` is zero), to ensure that two elements of the matrix
-        space (empty matrices) can be multiplied.
+        space (empty matrices) can be multiplied. For algebras of
+        matrices, this returns the space in which their
+        real embeddings live.
+
+        SETUP::
+
+            sage: from mjo.eja.eja_algebra import (ComplexHermitianEJA,
+            ....:                                  JordanSpinEJA,
+            ....:                                  QuaternionHermitianEJA,
+            ....:                                  TrivialEJA)
+
+        EXAMPLES:
+
+        By default, the matrix representation is just a column-matrix
+        equivalent to the vector representation::
+
+            sage: J = JordanSpinEJA(3)
+            sage: J.matrix_space()
+            Full MatrixSpace of 3 by 1 dense matrices over Algebraic
+            Real Field
+
+        The matrix representation in the trivial algebra is
+        zero-by-zero instead of the usual `n`-by-one::
+
+            sage: J = TrivialEJA()
+            sage: J.matrix_space()
+            Full MatrixSpace of 0 by 0 dense matrices over Algebraic
+            Real Field
+
+        The matrix space for complex/quaternion Hermitian matrix EJA
+        is the space in which their real-embeddings live, not the
+        original complex/quaternion matrix space::
+
+            sage: J = ComplexHermitianEJA(2,field=QQ,orthonormalize=False)
+            sage: J.matrix_space()
+            Full MatrixSpace of 4 by 4 dense matrices over Rational Field
+            sage: J = QuaternionHermitianEJA(1,field=QQ,orthonormalize=False)
+            sage: J.matrix_space()
+            Full MatrixSpace of 4 by 4 dense matrices over Rational Field
 
-        Matrix algebras override this with something more useful.
         """
         if self.is_trivial():
             return MatrixSpace(self.base_ring(), 0)
@@ -3132,10 +3210,42 @@ class CartesianProductEJA(CombinatorialFreeModule_CartesianProduct,
 
 FiniteDimensionalEJA.CartesianProduct = CartesianProductEJA
 
+class RationalBasisCartesianProductEJA(CartesianProductEJA,
+                                       RationalBasisEJA):
+    r"""
+    A separate class for products of algebras for which we know a
+    rational basis.
+
+    SETUP::
+
+        sage: from mjo.eja.eja_algebra import (JordanSpinEJA,
+        ....:                                  RealSymmetricEJA)
+
+    EXAMPLES:
+
+    This gives us fast characteristic polynomial computations in
+    product algebras, too::
+
+
+        sage: J1 = JordanSpinEJA(2)
+        sage: J2 = RealSymmetricEJA(3)
+        sage: J = cartesian_product([J1,J2])
+        sage: J.characteristic_polynomial_of().degree()
+        5
+        sage: J.rank()
+        5
+
+    """
+    def __init__(self, algebras, **kwargs):
+        CartesianProductEJA.__init__(self, algebras, **kwargs)
+
+        self._rational_algebra = None
+        if self.vector_space().base_field() is not QQ:
+            self._rational_algebra = cartesian_product([
+                r._rational_algebra for r in algebras
+            ])
+
+
+RationalBasisEJA.CartesianProduct = RationalBasisCartesianProductEJA
+
 random_eja = ConcreteEJA.random_instance
-#def random_eja(*args, **kwargs):
-#    from sage.categories.cartesian_product import cartesian_product
-#    J1 = HadamardEJA(1, **kwargs)
-#    J2 = RealSymmetricEJA(2, **kwargs)
-#    J =  cartesian_product([J1,J2])
-#    return J