"""
@staticmethod
- def _max_random_instance_size():
+ def _max_random_instance_dimension():
+ r"""
+ The maximum dimension of any random instance. Ten dimensions seems
+ to be about the point where everything takes a turn for the
+ worse. And dimension ten (but not nine) allows the 4-by-4 real
+ Hermitian matrices, the 2-by-2 quaternion Hermitian matrices,
+ and the 2-by-2 octonion Hermitian matrices.
+ """
+ return 10
+
+ @staticmethod
+ def _max_random_instance_size(max_dimension):
"""
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 algebra when it is used in a random test case. This size
+ (which can be passed to the algebra's constructor) is itself
+ based on the ``max_dimension`` parameter.
This method must be implemented in each subclass.
"""
raise NotImplementedError
@classmethod
- def random_instance(cls, *args, **kwargs):
+ def random_instance(cls, max_dimension=None, *args, **kwargs):
"""
- Return a random instance of this type of algebra.
+ Return a random instance of this type of algebra whose dimension
+ is less than or equal to ``max_dimension``. If the dimension bound
+ is omitted, then the ``_max_random_instance_dimension()`` is used
+ to get a suitable bound.
This method should be implemented in each subclass.
"""
"""
@staticmethod
- def _max_random_instance_size():
- return 4 # Dimension 10
+ def _max_random_instance_size(max_dimension):
+ # Obtained by solving d = (n^2 + n)/2.
+ return int(ZZ(8*max_dimension + 1).sqrt()/2 - 1/2)
@classmethod
- def random_instance(cls, **kwargs):
+ def random_instance(cls, max_dimension=None, **kwargs):
"""
Return a random instance of this type of algebra.
"""
- n = ZZ.random_element(cls._max_random_instance_size() + 1)
+ if max_dimension is None:
+ max_dimension = cls._max_random_instance_dimension()
+ max_size = cls._max_random_instance_size(max_dimension) + 1
+ n = ZZ.random_element(max_size)
return cls(n, **kwargs)
def __init__(self, n, field=AA, **kwargs):
sage: ComplexHermitianEJA(0)
Euclidean Jordan algebra of dimension 0 over Algebraic Real Field
+
"""
def __init__(self, n, field=AA, **kwargs):
# We know this is a valid EJA, but will double-check
self._rational_algebra._charpoly_coefficients.set_cache(a)
@staticmethod
- def _max_random_instance_size():
- return 3 # Dimension 9
+ def _max_random_instance_size(max_dimension):
+ # Obtained by solving d = n^2.
+ return int(ZZ(max_dimension).sqrt())
@classmethod
- def random_instance(cls, **kwargs):
+ def random_instance(cls, max_dimension=None, **kwargs):
"""
Return a random instance of this type of algebra.
"""
- n = ZZ.random_element(cls._max_random_instance_size() + 1)
+ if max_dimension is None:
+ max_dimension = cls._max_random_instance_dimension()
+ n = ZZ.random_element(cls._max_random_instance_size(max_dimension) + 1)
return cls(n, **kwargs)
@staticmethod
- def _max_random_instance_size():
+ def _max_random_instance_size(max_dimension):
r"""
The maximum rank of a random QuaternionHermitianEJA.
"""
- return 2 # Dimension 6
+ # Obtained by solving d = 2n^2 - n.
+ return int(ZZ(8*max_dimension + 1).sqrt()/4 + 1/4)
@classmethod
- def random_instance(cls, **kwargs):
+ def random_instance(cls, max_dimension=None, **kwargs):
"""
Return a random instance of this type of algebra.
"""
- n = ZZ.random_element(cls._max_random_instance_size() + 1)
+ if max_dimension is None:
+ max_dimension = cls._max_random_instance_dimension()
+ n = ZZ.random_element(cls._max_random_instance_size(max_dimension) + 1)
return cls(n, **kwargs)
class OctonionHermitianEJA(MatrixEJA, RationalBasisEJA, ConcreteEJA):
"""
@staticmethod
- def _max_random_instance_size():
+ def _max_random_instance_size(max_dimension):
r"""
The maximum rank of a random QuaternionHermitianEJA.
"""
- return 1 # Dimension 1
+ # There's certainly a formula for this, but with only four
+ # cases to worry about, I'm not that motivated to derive it.
+ if max_dimension >= 27:
+ return 3
+ elif max_dimension >= 10:
+ return 2
+ elif max_dimension >= 1:
+ return 1
+ else:
+ return 0
@classmethod
- def random_instance(cls, **kwargs):
+ def random_instance(cls, max_dimension=None, **kwargs):
"""
Return a random instance of this type of algebra.
"""
- n = ZZ.random_element(cls._max_random_instance_size() + 1)
+ if max_dimension is None:
+ max_dimension = cls._max_random_instance_dimension()
+ n = ZZ.random_element(cls._max_random_instance_size(max_dimension) + 1)
return cls(n, **kwargs)
def __init__(self, n, field=AA, **kwargs):
self.one.set_cache( self.sum(self.gens()) )
@staticmethod
- def _max_random_instance_size():
+ def _max_random_instance_dimension():
r"""
- The maximum dimension of a random HadamardEJA.
+ There's no reason to go higher than five here. That's
+ enough to get the point across.
"""
return 5
+ @staticmethod
+ def _max_random_instance_size(max_dimension):
+ r"""
+ The maximum size (=dimension) of a random HadamardEJA.
+ """
+ return max_dimension
+
@classmethod
- def random_instance(cls, **kwargs):
+ def random_instance(cls, max_dimension=None, **kwargs):
"""
Return a random instance of this type of algebra.
"""
- n = ZZ.random_element(cls._max_random_instance_size() + 1)
+ if max_dimension is None:
+ max_dimension = cls._max_random_instance_dimension()
+ n = ZZ.random_element(cls._max_random_instance_size(max_dimension) + 1)
return cls(n, **kwargs)
self.one.set_cache( self.monomial(0) )
@staticmethod
- def _max_random_instance_size():
+ def _max_random_instance_dimension():
r"""
- The maximum dimension of a random BilinearFormEJA.
+ There's no reason to go higher than five here. That's
+ enough to get the point across.
"""
return 5
+ @staticmethod
+ def _max_random_instance_size(max_dimension):
+ r"""
+ The maximum size (=dimension) of a random BilinearFormEJA.
+ """
+ return max_dimension
+
@classmethod
- def random_instance(cls, **kwargs):
+ def random_instance(cls, max_dimension=None, **kwargs):
"""
Return a random instance of this algebra.
"""
- n = ZZ.random_element(cls._max_random_instance_size() + 1)
+ if max_dimension is None:
+ max_dimension = cls._max_random_instance_dimension()
+ n = ZZ.random_element(cls._max_random_instance_size(max_dimension) + 1)
if n.is_zero():
B = matrix.identity(ZZ, n)
return cls(B, **kwargs)
# can pass in a field!
super().__init__(B, *args, **kwargs)
- @staticmethod
- def _max_random_instance_size():
- r"""
- The maximum dimension of a random JordanSpinEJA.
- """
- return 5
-
@classmethod
- def random_instance(cls, **kwargs):
+ def random_instance(cls, max_dimension=None, **kwargs):
"""
Return a random instance of this type of algebra.
Needed here to override the implementation for ``BilinearFormEJA``.
"""
- n = ZZ.random_element(cls._max_random_instance_size() + 1)
+ if max_dimension is None:
+ max_dimension = cls._max_random_instance_dimension()
+ n = ZZ.random_element(cls._max_random_instance_size(max_dimension) + 1)
return cls(n, **kwargs)
RationalBasisEJA.CartesianProduct = RationalBasisCartesianProductEJA
-def random_eja(*args, **kwargs):
- J1 = ConcreteEJA.random_instance(*args, **kwargs)
+def random_eja(max_dimension=None, *args, **kwargs):
+ # Use the ConcreteEJA default as the total upper bound (regardless
+ # of any whether or not any individual factors set a lower limit).
+ if max_dimension is None:
+ max_dimension = ConcreteEJA._max_random_instance_dimension()
+ J1 = ConcreteEJA.random_instance(max_dimension, *args, **kwargs)
- # This might make Cartesian products appear roughly as often as
- # any other ConcreteEJA.
- if ZZ.random_element(len(ConcreteEJA.__subclasses__()) + 1) == 0:
- # Use random_eja() again so we can get more than two factors.
- J2 = random_eja(*args, **kwargs)
- J = cartesian_product([J1,J2])
- return J
- else:
+
+ # Roll the dice to see if we attempt a Cartesian product.
+ dice_roll = ZZ.random_element(len(ConcreteEJA.__subclasses__()) + 1)
+ new_max_dimension = max_dimension - J1.dimension()
+ if new_max_dimension == 0 or dice_roll != 0:
+ # If it's already as big as we're willing to tolerate, just
+ # return it and don't worry about Cartesian products.
return J1
+ else:
+ # Use random_eja() again so we can get more than two factors
+ # if the sub-call also Decides on a cartesian product.
+ J2 = random_eja(new_max_dimension, *args, **kwargs)
+ return cartesian_product([J1,J2])