identity, inner_product)
from dunshire import options
-def _random_matrix(dims):
+
+def random_matrix(dims):
"""
- Generate a random square (``dims``-by-``dims``) matrix. This is used
- only by the :class:`SymmetricLinearGameTest` class.
+ Generate a random square matrix.
+
+ Parameters
+ ----------
+
+ dims : int
+ The number of rows/columns you want in the returned matrix.
+
+ Returns
+ -------
+
+ matrix
+ A new matrix whose entries are random floats chosen uniformly from
+ the interval [-10, 10].
+
+ Examples
+ --------
+
+ >>> A = random_matrix(3)
+ >>> A.size
+ (3, 3)
+
"""
return matrix([[uniform(-10, 10) for i in range(dims)]
for j in range(dims)])
-def _random_nonnegative_matrix(dims):
+
+def random_nonnegative_matrix(dims):
"""
- Generate a random square (``dims``-by-``dims``) matrix with
- nonnegative entries. This is used only by the
- :class:`SymmetricLinearGameTest` class.
+ Generate a random square matrix with nonnegative entries.
+
+ Parameters
+ ----------
+
+ dims : int
+ The number of rows/columns you want in the returned matrix.
+
+ Returns
+ -------
+
+ matrix
+ A new matrix whose entries are random floats chosen uniformly from
+ the interval [0, 10].
+
+ Examples
+ --------
+
+ >>> A = random_nonnegative_matrix(3)
+ >>> A.size
+ (3, 3)
+ >>> all([entry >= 0 for entry in A])
+ True
+
"""
- L = _random_matrix(dims)
+ L = random_matrix(dims)
return matrix([abs(entry) for entry in L], (dims, dims))
-def _random_diagonal_matrix(dims):
+
+def random_diagonal_matrix(dims):
"""
- Generate a random square (``dims``-by-``dims``) matrix with nonzero
- entries only on the diagonal. This is used only by the
- :class:`SymmetricLinearGameTest` class.
+ Generate a random square matrix with zero off-diagonal entries.
+
+ These matrices are Lyapunov-like on the nonnegative orthant, as is
+ fairly easy to see.
+
+ Parameters
+ ----------
+
+ dims : int
+ The number of rows/columns you want in the returned matrix.
+
+ Returns
+ -------
+
+ matrix
+ A new matrix whose diagonal entries are random floats chosen
+ uniformly from the interval [-10, 10] and whose off-diagonal
+ entries are zero.
+
+ Examples
+ --------
+
+ >>> A = random_diagonal_matrix(3)
+ >>> A.size
+ (3, 3)
+ >>> A[0,1] == A[0,2] == A[1,0] == A[2,0] == A[1,2] == A[2,1] == 0
+ True
+
"""
return matrix([[uniform(-10, 10)*int(i == j) for i in range(dims)]
for j in range(dims)])
-def _random_skew_symmetric_matrix(dims):
+def random_skew_symmetric_matrix(dims):
"""
- Generate a random skew-symmetrix (``dims``-by-``dims``) matrix.
+ Generate a random skew-symmetrix matrix.
+
+ Parameters
+ ----------
+
+ dims : int
+ The number of rows/columns you want in the returned matrix.
+
+ Returns
+ -------
+
+ matrix
+ A new skew-matrix whose strictly above-diagonal entries are
+ random floats chosen uniformly from the interval [-10, 10].
Examples
--------
+ >>> A = random_skew_symmetric_matrix(3)
+ >>> A.size
+ (3, 3)
+
>>> from dunshire.matrices import norm
- >>> A = _random_skew_symmetric_matrix(randint(1, 10))
+ >>> A = random_skew_symmetric_matrix(randint(1, 10))
>>> norm(A + A.trans()) < options.ABS_TOL
True
return strict_ut - strict_ut.trans()
-def _random_lyapunov_like_icecream(dims):
- """
- Generate a random Lyapunov-like matrix over the ice-cream cone in
- ``dims`` dimensions.
+def random_lyapunov_like_icecream(dims):
+ r"""
+ Generate a random matrix Lyapunov-like on the ice-cream cone.
+
+ The form of these matrices is cited in Gowda and Tao
+ [GowdaTao]_. The scalar ``a`` and the vector ``b`` (using their
+ notation) are easy to generate. The submatrix ``D`` is a little
+ trickier, but it can be found noticing that :math:`C + C^{T} = 0`
+ for a skew-symmetric matrix :math:`C` implying that :math:`C + C^{T}
+ + \left(2a\right)I = \left(2a\right)I`. Thus we can stick an
+ :math:`aI` with each of :math:`C,C^{T}` and let those be our
+ :math:`D,D^{T}`.
+
+ Parameters
+ ----------
+
+ dims : int
+ The dimension of the ice-cream cone (not of the matrix you want!)
+ on which the returned matrix should be Lyapunov-like.
+
+ Returns
+ -------
+
+ matrix
+ A new matrix, Lyapunov-like on the ice-cream cone in ``dims``
+ dimensions, whose free entries are random floats chosen uniformly
+ from the interval [-10, 10].
+
+ References
+ ----------
+
+ .. [GowdaTao] M. S. Gowda and J. Tao. On the bilinearity rank of a
+ proper cone and Lyapunov-like transformations. Mathematical
+ Programming, 147:155–170, 2014.
+
+ Examples
+ --------
+
+ >>> L = random_lyapunov_like_icecream(3)
+ >>> L.size
+ (3, 3)
+ >>> x = matrix([1,1,0])
+ >>> s = matrix([1,-1,0])
+ >>> abs(inner_product(L*x, s)) < options.ABS_TOL
+ True
+
"""
a = matrix([uniform(-10, 10)], (1, 1))
b = matrix([uniform(-10, 10) for idx in range(dims-1)], (dims-1, 1))
- D = _random_skew_symmetric_matrix(dims-1) + a*identity(dims-1)
+ D = random_skew_symmetric_matrix(dims-1) + a*identity(dims-1)
row1 = append_col(a, b.trans())
row2 = append_col(b, D)
return append_row(row1, row2)
-def _random_orthant_params():
+def random_orthant_params():
"""
Generate the ``L``, ``K``, ``e1``, and ``e2`` parameters for a
- random game over the nonnegative orthant. This is only used by
- the :class:`SymmetricLinearGameTest` class.
+ random game over the nonnegative orthant.
"""
ambient_dim = randint(1, 10)
K = NonnegativeOrthant(ambient_dim)
e1 = [uniform(0.5, 10) for idx in range(K.dimension())]
e2 = [uniform(0.5, 10) for idx in range(K.dimension())]
- L = _random_matrix(K.dimension())
+ L = random_matrix(K.dimension())
return (L, K, matrix(e1), matrix(e2))
-def _random_icecream_params():
+def random_icecream_params():
"""
Generate the ``L``, ``K``, ``e1``, and ``e2`` parameters for a
- random game over the ice cream cone. This is only used by
- the :class:`SymmetricLinearGameTest` class.
+ random game over the ice-cream cone.
"""
# Use a minimum dimension of two to avoid divide-by-zero in
# the fudge factor we make up later.
fudge_factor = 1.0 / (2.0*sqrt(K.dimension() - 1.0))
e1 += [fudge_factor*uniform(0, 1) for idx in range(K.dimension() - 1)]
e2 += [fudge_factor*uniform(0, 1) for idx in range(K.dimension() - 1)]
- L = _random_matrix(K.dimension())
+ L = random_matrix(K.dimension())
return (L, K, matrix(e1), matrix(e2))
optimal solutions should give us the optimal game value when we
apply the payoff operator to them.
"""
- (L, K, e1, e2) = _random_orthant_params()
+ (L, K, e1, e2) = random_orthant_params()
self.assert_solution_exists(L, K, e1, e2)
Like :meth:`test_solution_exists_nonnegative_orthant`, except
over the ice cream cone.
"""
- (L, K, e1, e2) = _random_icecream_params()
+ (L, K, e1, e2) = random_icecream_params()
self.assert_solution_exists(L, K, e1, e2)
Test that scaling ``L`` by a nonnegative number scales the value
of the game by the same number over the nonnegative orthant.
"""
- (L, K, e1, e2) = _random_orthant_params()
+ (L, K, e1, e2) = random_orthant_params()
self.assert_scaling_works(L, K, e1, e2)
The same test as :meth:`test_nonnegative_scaling_orthant`,
except over the ice cream cone.
"""
- (L, K, e1, e2) = _random_icecream_params()
+ (L, K, e1, e2) = random_icecream_params()
self.assert_scaling_works(L, K, e1, e2)
"""
Test that translation works over the nonnegative orthant.
"""
- (L, K, e1, e2) = _random_orthant_params()
+ (L, K, e1, e2) = random_orthant_params()
self.assert_translation_works(L, K, e1, e2)
The same as :meth:`test_translation_orthant`, except over the
ice cream cone.
"""
- (L, K, e1, e2) = _random_icecream_params()
+ (L, K, e1, e2) = random_icecream_params()
self.assert_translation_works(L, K, e1, e2)
Test the value of the "opposite" game over the nonnegative
orthant.
"""
- (L, K, e1, e2) = _random_orthant_params()
+ (L, K, e1, e2) = random_orthant_params()
self.assert_opposite_game_works(L, K, e1, e2)
Like :meth:`test_opposite_game_orthant`, except over the
ice-cream cone.
"""
- (L, K, e1, e2) = _random_icecream_params()
+ (L, K, e1, e2) = random_icecream_params()
self.assert_opposite_game_works(L, K, e1, e2)
Check the orthgonality relationships that hold for a solution
over the nonnegative orthant.
"""
- (L, K, e1, e2) = _random_orthant_params()
+ (L, K, e1, e2) = random_orthant_params()
self.assert_orthogonality(L, K, e1, e2)
Check the orthgonality relationships that hold for a solution
over the ice-cream cone.
"""
- (L, K, e1, e2) = _random_icecream_params()
+ (L, K, e1, e2) = random_icecream_params()
self.assert_orthogonality(L, K, e1, e2)
This test theoretically applies to the ice-cream cone as well,
but we don't know how to make positive operators on that cone.
"""
- (K, e1, e2) = _random_orthant_params()[1:]
- L = _random_nonnegative_matrix(K.dimension())
+ (K, e1, e2) = random_orthant_params()[1:]
+ L = random_nonnegative_matrix(K.dimension())
game = SymmetricLinearGame(L, K, e1, e2)
self.assertTrue(game.solution().game_value() >= -options.ABS_TOL)
"""
Test that a Lyapunov game on the nonnegative orthant works.
"""
- (K, e1, e2) = _random_orthant_params()[1:]
- L = _random_diagonal_matrix(K.dimension())
+ (K, e1, e2) = random_orthant_params()[1:]
+ L = random_diagonal_matrix(K.dimension())
self.assert_lyapunov_works(L, K, e1, e2)
"""
Test that a Lyapunov game on the ice-cream cone works.
"""
- (K, e1, e2) = _random_icecream_params()[1:]
- L = _random_lyapunov_like_icecream(K.dimension())
+ (K, e1, e2) = random_icecream_params()[1:]
+ L = random_lyapunov_like_icecream(K.dimension())
self.assert_lyapunov_works(L, K, e1, e2)