2 The completely positive cone `$\mathcal{K}$` over `\mathbb{R}^{n}$` is
3 the set of all matrices `$A$`of the form `$\sum uu^{T}$` for `$u \in
4 \mathbb{R}^{n}_{+}$`. Equivalently, `$A = XX{T}$` where all entries of
9 from mjo
.cone
.symmetric_psd
import factor_psd
, is_symmetric_psd
10 from mjo
.cone
.doubly_nonnegative
import (is_doubly_nonnegative
,
11 is_extreme_doubly_nonnegative
)
13 def is_completely_positive(A
):
15 Determine whether or not the matrix ``A`` is completely
16 positive. This is a known-hard problem, and we'll just give up and
17 throw a ``ValueError`` if we can't come to a decision one way or
22 - ``A`` - The matrix in question
26 Either ``True`` if ``A`` is completely positive, or ``False``
31 sage: from mjo.cone.completely_positive import is_completely_positive
35 Generate an extreme completely positive matrix and check that we
36 identify it correctly::
38 sage: v = vector([1,2,3,4])
39 sage: A = v.column() * v.row()
40 sage: A = A.change_ring(QQ)
41 sage: is_completely_positive(A)
44 Generate an intractible matrix (which does happen to be completely
45 positive) and explode::
47 sage: v = vector(map(abs, random_vector(ZZ, 10)))
48 sage: A = v.column() * v.row()
49 sage: A = A.change_ring(QQ)
50 sage: is_completely_positive(A)
51 Traceback (most recent call last):
53 ValueError: Unable to determine extremity of ``A``.
55 Generate a *non*-extreme completely positive matrix and check we
56 we identify it correctly. This doesn't work so well if we generate
57 random vectors because our algorithm can give up::
59 sage: v1 = vector([1,2,3])
60 sage: v2 = vector([4,5,6])
61 sage: A = v1.column()*v1.row() + v2.column()*v2.row()
62 sage: A = A.change_ring(QQ)
63 sage: is_completely_positive(A)
66 The following matrix isn't positive semidefinite, so it can't be
69 sage: A = matrix(QQ, [[1, 2], [2, 1]])
70 sage: is_completely_positive(A)
73 This matrix isn't even symmetric, so it can't be completely
76 sage: A = matrix(QQ, [[1, 2], [3, 4]])
77 sage: is_completely_positive(A)
80 This one is symmetric but has full rank::
82 sage: A = matrix(QQ, [[1, 0], [0, 4]])
83 sage: is_completely_positive(A)
88 if A
.base_ring() == SR
:
89 msg
= 'The matrix ``A`` cannot be symbolic.'
90 raise ValueError.new(msg
)
92 if not is_symmetric_psd(A
):
95 n
= A
.nrows() # Makes sense since ``A`` is symmetric.
98 # The two sets are the same for n <= 4.
99 return is_doubly_nonnegative(A
)
102 raise ValueError('Unable to determine extremity of ``A``.')
106 def is_extreme_completely_positive(A
):
108 Determine whether or not the matrix ``A`` is an extreme vector of
109 the completely positive cone. This is in general a known-hard
110 problem, so our algorithm will give up and throw a ``ValueError`` if
111 a decision cannot be made one way or another.
115 - ``A`` - The matrix whose extremity we want to discover
119 Either ``True`` if ``A`` is an extreme vector of the completely
120 positive cone, or ``False`` otherwise.
124 1. Berman, Abraham and Shaked-Monderer, Naomi. Completely Positive
125 Matrices. World Scientific, 2003.
129 sage: from mjo.cone.completely_positive import is_extreme_completely_positive
133 Generate an extreme completely positive matrix and check that we
134 identify it correctly::
136 sage: v = vector(map(abs, random_vector(ZZ, 10)))
137 sage: A = v.column() * v.row()
138 sage: A = A.change_ring(QQ)
139 sage: is_extreme_completely_positive(A)
142 Generate a *non*-extreme completely positive matrix and check we
143 we identify it correctly. This doesn't work so well if we generate
144 random vectors because our algorithm can give up::
146 sage: v1 = vector([1,2,3])
147 sage: v2 = vector([4,5,6])
148 sage: A = v1.column()*v1.row() + v2.column()*v2.row()
149 sage: A = A.change_ring(QQ)
150 sage: is_extreme_completely_positive(A)
153 The following matrix isn't positive semidefinite, so it can't be
154 completely positive::
156 sage: A = matrix(QQ, [[1, 2], [2, 1]])
157 sage: is_extreme_completely_positive(A)
160 This matrix isn't even symmetric, so it can't be completely
163 sage: A = matrix(QQ, [[1, 2], [3, 4]])
164 sage: is_extreme_completely_positive(A)
167 This one is symmetric but has full rank::
169 sage: A = matrix(QQ, [[1, 0], [0, 4]])
170 sage: is_extreme_completely_positive(A)
175 if A
.base_ring() == SR
:
176 msg
= 'The matrix ``A`` cannot be symbolic.'
177 raise ValueError(msg
)
179 if not is_symmetric_psd(A
):
182 n
= A
.nrows() # Makes sense since ``A`` is symmetric.
184 # Easy case, see the reference (Remark 2.4).
186 return is_extreme_doubly_nonnegative(A
)
188 # If n > 5, we don't really know. But we might get lucky? See the
189 # reference again for this claim.
190 if A
.rank() == 1 and is_doubly_nonnegative(A
):
193 # We didn't get lucky. We have a characterization of the extreme
194 # vectors, but it isn't useful if we start with ``A`` because the
195 # factorization into `$XX^{T}$` may not be unique!
196 raise ValueError('Unable to determine extremity of ``A``.')