From: Michael Orlitzky Date: Tue, 4 Nov 2014 17:21:22 +0000 (-0500) Subject: Add random_doubly_nonnegative() and random_extreme_doubly_nonnegative() functions. X-Git-Url: http://gitweb.michael.orlitzky.com/?a=commitdiff_plain;h=95353d1a02424f49e4691d6f4ecef9bd5d267311;p=sage.d.git Add random_doubly_nonnegative() and random_extreme_doubly_nonnegative() functions. --- diff --git a/mjo/cone/doubly_nonnegative.py b/mjo/cone/doubly_nonnegative.py index ebb5b68..56a655e 100644 --- a/mjo/cone/doubly_nonnegative.py +++ b/mjo/cone/doubly_nonnegative.py @@ -19,7 +19,7 @@ from sage.all import * from os.path import abspath from site import addsitedir addsitedir(abspath('../../')) -from mjo.cone.symmetric_psd import factor_psd, is_symmetric_psd +from mjo.cone.symmetric_psd import factor_psd, is_symmetric_psd, random_psd from mjo.matrix_vector import isomorphism @@ -378,3 +378,141 @@ def is_extreme_doubly_nonnegative(A): # earlier. two = A.base_ring()(2) return d == (k*(k + 1)/two - 1) + + +def random_doubly_nonnegative(V, accept_zero=True, rank=None): + """ + Generate a random doubly nonnegative matrix over the vector + space ``V``. That is, the returned matrix will be a linear + transformation on ``V``, with the same base ring as ``V``. + + We take a very loose interpretation of "random," here. Otherwise we + would never (for example) choose a matrix on the boundary of the + cone. + + INPUT: + + - ``V`` - The vector space on which the returned matrix will act. + + - ``accept_zero`` - Do you want to accept the zero matrix (which + is doubly nonnegative)? Default to ``True``. + + - ``rank`` - Require the returned matrix to have the given rank + (optional). + + OUTPUT: + + A random doubly nonnegative matrix, i.e. a linear transformation + from ``V`` to itself. + + EXAMPLES: + + Well, it doesn't crash at least:: + + sage: V = VectorSpace(QQ, 2) + sage: A = random_doubly_nonnegative(V) + sage: A.matrix_space() + Full MatrixSpace of 2 by 2 dense matrices over Rational Field + sage: is_doubly_nonnegative(A) + True + + A matrix with the desired rank is returned:: + + sage: V = VectorSpace(QQ, 5) + sage: A = random_doubly_nonnegative(V,False,1) + sage: A.rank() + 1 + sage: A = random_doubly_nonnegative(V,False,2) + sage: A.rank() + 2 + sage: A = random_doubly_nonnegative(V,False,3) + sage: A.rank() + 3 + sage: A = random_doubly_nonnegative(V,False,4) + sage: A.rank() + 4 + sage: A = random_doubly_nonnegative(V,False,5) + sage: A.rank() + 5 + + """ + + # Generate random symmetric positive-semidefinite matrices until + # one of them is nonnegative, then return that. + A = random_psd(V, accept_zero, rank) + + while not all([ x >= 0 for x in A.list() ]): + A = random_psd(V, accept_zero, rank) + + return A + + + +def random_extreme_doubly_nonnegative(V, accept_zero=True, rank=None): + """ + Generate a random extreme doubly nonnegative matrix over the + vector space ``V``. That is, the returned matrix will be a linear + transformation on ``V``, with the same base ring as ``V``. + + We take a very loose interpretation of "random," here. Otherwise we + would never (for example) choose a matrix on the boundary of the + cone. + + INPUT: + + - ``V`` - The vector space on which the returned matrix will act. + + - ``accept_zero`` - Do you want to accept the zero matrix + (which is extreme)? Defaults to ``True``. + + - ``rank`` - Require the returned matrix to have the given rank + (optional). WARNING: certain ranks are not possible + in any given dimension! If an impossible rank is + requested, a ValueError will be raised. + + OUTPUT: + + A random extreme doubly nonnegative matrix, i.e. a linear + transformation from ``V`` to itself. + + EXAMPLES: + + Well, it doesn't crash at least:: + + sage: V = VectorSpace(QQ, 2) + sage: A = random_extreme_doubly_nonnegative(V) + sage: A.matrix_space() + Full MatrixSpace of 2 by 2 dense matrices over Rational Field + sage: is_extreme_doubly_nonnegative(A) + True + + Rank 2 is never allowed, so we expect an error:: + + sage: V = VectorSpace(QQ, 5) + sage: A = random_extreme_doubly_nonnegative(V, False, 2) + Traceback (most recent call last): + ... + ValueError: Rank 2 not possible in dimension 5. + + Rank 4 is not allowed in dimension 5:: + + sage: V = VectorSpace(QQ, 5) + sage: A = random_extreme_doubly_nonnegative(V, False, 4) + Traceback (most recent call last): + ... + ValueError: Rank 4 not possible in dimension 5. + + """ + + if not is_admissible_extreme_rank(rank, V.dimension()): + msg = 'Rank %d not possible in dimension %d.' + raise ValueError(msg % (rank, V.dimension())) + + # Generate random doubly-nonnegative matrices until + # one of them is extreme, then return that. + A = random_doubly_nonnegative(V, accept_zero, rank) + + while not is_extreme_doubly_nonnegative(A): + A = random_doubly_nonnegative(V, accept_zero, rank) + + return A