]> gitweb.michael.orlitzky.com - sage.d.git/commitdiff
eja: add ConcreteEJA class for EJAs we can make random instances of.
authorMichael Orlitzky <michael@orlitzky.com>
Sun, 22 Nov 2020 22:39:08 +0000 (17:39 -0500)
committerMichael Orlitzky <michael@orlitzky.com>
Sun, 22 Nov 2020 22:39:08 +0000 (17:39 -0500)
mjo/eja/eja_algebra.py

index c40c8be4c371255f9bc174f99862ef0a7a204555..d9a3abc7508e69424d4432ed64875cf17c01cac8 100644 (file)
@@ -3,6 +3,17 @@ Euclidean Jordan Algebras. These are formally-real Jordan Algebras;
 specifically those where u^2 + v^2 = 0 implies that u = v = 0. They
 are used in optimization, and have some additional nice methods beyond
 what can be supported in a general Jordan Algebra.
+
+
+SETUP::
+
+    sage: from mjo.eja.eja_algebra import random_eja
+
+EXAMPLES::
+
+    sage: random_eja()
+    Euclidean Jordan algebra of dimension...
+
 """
 
 from itertools import repeat
@@ -14,7 +25,6 @@ from sage.matrix.constructor import matrix
 from sage.matrix.matrix_space import MatrixSpace
 from sage.misc.cachefunc import cached_method
 from sage.misc.lazy_import import lazy_import
-from sage.misc.prandom import choice
 from sage.misc.table import table
 from sage.modules.free_module import FreeModule, VectorSpace
 from sage.rings.all import (ZZ, QQ, AA, QQbar, RR, RLF, CLF,
@@ -216,25 +226,6 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         coords =  W.coordinate_vector(_mat2vec(elt))
         return self.from_vector(coords)
 
-    @staticmethod
-    def _max_random_instance_size():
-        """
-        Return an integer "size" that is an upper bound on the size of
-        this algebra when it is used in a random test
-        case. Unfortunately, the term "size" is quite vague -- when
-        dealing with `R^n` under either the Hadamard or Jordan spin
-        product, the "size" refers to the dimension `n`. When dealing
-        with a matrix algebra (real symmetric or complex/quaternion
-        Hermitian), it refers to the size of the matrix, which is
-        far less than the dimension of the underlying vector space.
-
-        We default to five in this class, which is safe in `R^n`. The
-        matrix algebra subclasses (or any class where the "size" is
-        interpreted to be far less than the dimension) should override
-        with a smaller number.
-        """
-        raise NotImplementedError
-
     def _repr_(self):
         """
         Return a string representation of ``self``.
@@ -842,16 +833,6 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
         return tuple( self.random_element(thorough)
                       for idx in range(count) )
 
-    @classmethod
-    def random_instance(cls, field=AA, **kwargs):
-        """
-        Return a random instance of this type of algebra.
-
-        Beware, this will crash for "most instances" because the
-        constructor below looks wrong.
-        """
-        n = ZZ.random_element(cls._max_random_instance_size() + 1)
-        return cls(n, field, **kwargs)
 
     @cached_method
     def _charpoly_coefficients(self):
@@ -1013,32 +994,6 @@ class FiniteDimensionalEuclideanJordanAlgebra(CombinatorialFreeModule):
     Element = FiniteDimensionalEuclideanJordanAlgebraElement
 
 
-
-def random_eja(field=AA):
-    """
-    Return a "random" finite-dimensional Euclidean Jordan Algebra.
-
-    SETUP::
-
-        sage: from mjo.eja.eja_algebra import random_eja
-
-    TESTS::
-
-        sage: random_eja()
-        Euclidean Jordan algebra of dimension...
-
-    """
-    classname = choice([TrivialEJA,
-                        HadamardEJA,
-                        JordanSpinEJA,
-                        RealSymmetricEJA,
-                        ComplexHermitianEJA,
-                        QuaternionHermitianEJA])
-    return classname.random_instance(field=field)
-
-
-
-
 class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
     r"""
     Algebras whose basis consists of vectors with rational
@@ -1098,12 +1053,45 @@ class RationalBasisEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebr
         return tuple(map(lambda x: x.change_ring(self.base_ring()), a))
 
 
-class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
+class ConcreteEuclideanJordanAlgebra:
+    r"""
+    A class for the Euclidean Jordan algebras that we know by name.
+
+    These are the Jordan algebras whose basis, multiplication table,
+    rank, and so on are known a priori. More to the point, they are
+    the Euclidean Jordan algebras for which we are able to conjure up
+    a "random instance."
+    """
+
     @staticmethod
     def _max_random_instance_size():
-        # Play it safe, since this will be squared and the underlying
-        # field can have dimension 4 (quaternions) too.
-        return 2
+        """
+        Return an integer "size" that is an upper bound on the size of
+        this algebra when it is used in a random test
+        case. Unfortunately, the term "size" is ambiguous -- when
+        dealing with `R^n` under either the Hadamard or Jordan spin
+        product, the "size" refers to the dimension `n`. When dealing
+        with a matrix algebra (real symmetric or complex/quaternion
+        Hermitian), it refers to the size of the matrix, which is far
+        less than the dimension of the underlying vector space.
+
+        This method must be implemented in each subclass.
+        """
+        raise NotImplementedError
+
+    @classmethod
+    def random_instance(cls, field=AA, **kwargs):
+        """
+        Return a random instance of this type of algebra.
+
+        This method should be implemented in each subclass.
+        """
+        from sage.misc.prandom import choice
+        eja_class = choice(cls.__subclasses__())
+        return eja_class.random_instance(field)
+
+
+class MatrixEuclideanJordanAlgebra(FiniteDimensionalEuclideanJordanAlgebra):
 
     def __init__(self, field, basis, normalize_basis=True, **kwargs):
         """
@@ -1287,7 +1275,8 @@ class RealMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         return M
 
 
-class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra):
+class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra,
+                       ConcreteEuclideanJordanAlgebra):
     """
     The rank-n simple EJA consisting of real symmetric n-by-n
     matrices, the usual symmetric Jordan product, and the trace inner
@@ -1407,6 +1396,13 @@ class RealSymmetricEJA(RealMatrixEuclideanJordanAlgebra):
     def _max_random_instance_size():
         return 4 # Dimension 10
 
+    @classmethod
+    def random_instance(cls, field=AA, **kwargs):
+        """
+        Return a random instance of this type of algebra.
+        """
+        n = ZZ.random_element(cls._max_random_instance_size() + 1)
+        return cls(n, field, **kwargs)
 
     def __init__(self, n, field=AA, **kwargs):
         basis = self._denormalized_basis(n, field)
@@ -1450,8 +1446,7 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         Embedding is a homomorphism (isomorphism, in fact)::
 
             sage: set_random_seed()
-            sage: n_max = ComplexMatrixEuclideanJordanAlgebra._max_random_instance_size()
-            sage: n = ZZ.random_element(n_max)
+            sage: n = ZZ.random_element(3)
             sage: F = QuadraticField(-1, 'I')
             sage: X = random_matrix(F, n)
             sage: Y = random_matrix(F, n)
@@ -1576,7 +1571,8 @@ class ComplexMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         return RealMatrixEuclideanJordanAlgebra.natural_inner_product(X,Y)/2
 
 
-class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra):
+class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra,
+                          ConcreteEuclideanJordanAlgebra):
     """
     The rank-n simple EJA consisting of complex Hermitian n-by-n
     matrices over the real numbers, the usual symmetric Jordan product,
@@ -1715,6 +1711,17 @@ class ComplexHermitianEJA(ComplexMatrixEuclideanJordanAlgebra):
                                                  **kwargs)
         self.rank.set_cache(n)
 
+    @staticmethod
+    def _max_random_instance_size():
+        return 3 # Dimension 9
+
+    @classmethod
+    def random_instance(cls, field=AA, **kwargs):
+        """
+        Return a random instance of this type of algebra.
+        """
+        n = ZZ.random_element(cls._max_random_instance_size() + 1)
+        return cls(n, field, **kwargs)
 
 class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
     @staticmethod
@@ -1746,8 +1753,7 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         Embedding is a homomorphism (isomorphism, in fact)::
 
             sage: set_random_seed()
-            sage: n_max = QuaternionMatrixEuclideanJordanAlgebra._max_random_instance_size()
-            sage: n = ZZ.random_element(n_max)
+            sage: n = ZZ.random_element(2)
             sage: Q = QuaternionAlgebra(QQ,-1,-1)
             sage: X = random_matrix(Q, n)
             sage: Y = random_matrix(Q, n)
@@ -1879,8 +1885,9 @@ class QuaternionMatrixEuclideanJordanAlgebra(MatrixEuclideanJordanAlgebra):
         return RealMatrixEuclideanJordanAlgebra.natural_inner_product(X,Y)/4
 
 
-class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra):
-    """
+class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra,
+                             ConcreteEuclideanJordanAlgebra):
+    r"""
     The rank-n simple EJA consisting of self-adjoint n-by-n quaternion
     matrices, the usual symmetric Jordan product, and the
     real-part-of-trace inner product. It has dimension `2n^2 - n` over
@@ -2019,8 +2026,24 @@ class QuaternionHermitianEJA(QuaternionMatrixEuclideanJordanAlgebra):
                                                     **kwargs)
         self.rank.set_cache(n)
 
+    @staticmethod
+    def _max_random_instance_size():
+        r"""
+        The maximum rank of a random QuaternionHermitianEJA.
+        """
+        return 2 # Dimension 6
+
+    @classmethod
+    def random_instance(cls, field=AA, **kwargs):
+        """
+        Return a random instance of this type of algebra.
+        """
+        n = ZZ.random_element(cls._max_random_instance_size() + 1)
+        return cls(n, field, **kwargs)
+
 
-class HadamardEJA(RationalBasisEuclideanJordanAlgebra):
+class HadamardEJA(RationalBasisEuclideanJordanAlgebra,
+                  ConcreteEuclideanJordanAlgebra):
     """
     Return the Euclidean Jordan Algebra corresponding to the set
     `R^n` under the Hadamard product.
@@ -2078,8 +2101,20 @@ class HadamardEJA(RationalBasisEuclideanJordanAlgebra):
 
     @staticmethod
     def _max_random_instance_size():
+        r"""
+        The maximum dimension of a random HadamardEJA.
+        """
         return 5
 
+    @classmethod
+    def random_instance(cls, field=AA, **kwargs):
+        """
+        Return a random instance of this type of algebra.
+        """
+        n = ZZ.random_element(cls._max_random_instance_size() + 1)
+        return cls(n, field, **kwargs)
+
+
     def inner_product(self, x, y):
         """
         Faster to reimplement than to use natural representations.
@@ -2105,7 +2140,8 @@ class HadamardEJA(RationalBasisEuclideanJordanAlgebra):
         return x.to_vector().inner_product(y.to_vector())
 
 
-class BilinearFormEJA(RationalBasisEuclideanJordanAlgebra):
+class BilinearFormEJA(RationalBasisEuclideanJordanAlgebra,
+                      ConcreteEuclideanJordanAlgebra):
     r"""
     The rank-2 simple EJA consisting of real vectors ``x=(x0, x_bar)``
     with the half-trace inner product and jordan product ``x*y =
@@ -2222,6 +2258,9 @@ class BilinearFormEJA(RationalBasisEuclideanJordanAlgebra):
 
     @staticmethod
     def _max_random_instance_size():
+        r"""
+        The maximum dimension of a random BilinearFormEJA.
+        """
         return 5
 
     @classmethod
@@ -2334,6 +2373,13 @@ class JordanSpinEJA(BilinearFormEJA):
         B = matrix.identity(field, n)
         super(JordanSpinEJA, self).__init__(B, field, **kwargs)
 
+    @staticmethod
+    def _max_random_instance_size():
+        r"""
+        The maximum dimension of a random JordanSpinEJA.
+        """
+        return 5
+
     @classmethod
     def random_instance(cls, field=AA, **kwargs):
         """
@@ -2345,7 +2391,8 @@ class JordanSpinEJA(BilinearFormEJA):
         return cls(n, field, **kwargs)
 
 
-class TrivialEJA(FiniteDimensionalEuclideanJordanAlgebra):
+class TrivialEJA(FiniteDimensionalEuclideanJordanAlgebra,
+                 ConcreteEuclideanJordanAlgebra):
     """
     The trivial Euclidean Jordan algebra consisting of only a zero element.
 
@@ -2572,3 +2619,7 @@ class DirectSumEJA(FiniteDimensionalEuclideanJordanAlgebra):
         y2 = pi_right(y)
 
         return (x1.inner_product(y1) + x2.inner_product(y2))
+
+
+
+random_eja = ConcreteEuclideanJordanAlgebra.random_instance