Mercurial > hg > octave-nkf
annotate scripts/optimization/qp.m @ 7795:df9519e9990c
Handle single precision eps values
author | David Bateman <dbateman@free.fr> |
---|---|
date | Mon, 12 May 2008 22:57:11 +0200 |
parents | a1dbe9d80eee |
children | 5ee11a81688e |
rev | line source |
---|---|
7017 | 1 ## Copyright (C) 2000, 2001, 2004, 2005, 2006, 2007 Gabriele Pannocchia. |
5289 | 2 ## |
3 ## This file is part of Octave. | |
4 ## | |
5 ## Octave is free software; you can redistribute it and/or modify it | |
6 ## under the terms of the GNU General Public License as published by | |
7016 | 7 ## the Free Software Foundation; either version 3 of the License, or (at |
8 ## your option) any later version. | |
5289 | 9 ## |
10 ## Octave is distributed in the hope that it will be useful, but | |
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 ## General Public License for more details. | |
14 ## | |
15 ## You should have received a copy of the GNU General Public License | |
7016 | 16 ## along with Octave; see the file COPYING. If not, see |
17 ## <http://www.gnu.org/licenses/>. | |
5289 | 18 |
19 ## -*- texinfo -*- | |
6741 | 20 ## @deftypefn {Function File} {[@var{x}, @var{obj}, @var{info}, @var{lambda}] =} qp (@var{x0}, @var{H}, @var{q}, @var{A}, @var{b}, @var{lb}, @var{ub}, @var{A_lb}, @var{A_in}, @var{A_ub}) |
5289 | 21 ## Solve the quadratic program |
6741 | 22 ## @iftex |
23 ## @tex | |
24 ## $$ | |
25 ## \min_x {1 \over 2} x^T H x + x^T q | |
26 ## $$ | |
27 ## @end tex | |
28 ## @end iftex | |
29 ## @ifnottex | |
5289 | 30 ## |
31 ## @example | |
32 ## min 0.5 x'*H*x + x'*q | |
33 ## x | |
34 ## @end example | |
35 ## | |
6741 | 36 ## @end ifnottex |
37 ## subject to | |
5289 | 38 ## @iftex |
39 ## @tex | |
6741 | 40 ## $$ |
41 ## Ax = b \qquad lb \leq x \leq ub \qquad A_{lb} \leq A_{in} \leq A_{ub} | |
42 ## $$ | |
5289 | 43 ## @end tex |
44 ## @end iftex | |
6741 | 45 ## @ifnottex |
5289 | 46 ## |
47 ## @example | |
48 ## A*x = b | |
49 ## lb <= x <= ub | |
6741 | 50 ## A_lb <= A_in*x <= A_ub |
5289 | 51 ## @end example |
6741 | 52 ## @end ifnottex |
5289 | 53 ## |
54 ## @noindent | |
55 ## using a null-space active-set method. | |
56 ## | |
57 ## Any bound (@var{A}, @var{b}, @var{lb}, @var{ub}, @var{A_lb}, | |
58 ## @var{A_ub}) may be set to the empty matrix (@code{[]}) if not | |
59 ## present. If the initial guess is feasible the algorithm is faster. | |
60 ## | |
61 ## The value @var{info} is a structure with the following fields: | |
62 ## @table @code | |
63 ## @item solveiter | |
64 ## The number of iterations required to find the solution. | |
65 ## @item info | |
66 ## An integer indicating the status of the solution, as follows: | |
67 ## @table @asis | |
68 ## @item 0 | |
69 ## The problem is feasible and convex. Global solution found. | |
70 ## @item 1 | |
71 ## The problem is not convex. Local solution found. | |
72 ## @item 2 | |
73 ## The problem is not convex and unbounded. | |
74 ## @item 3 | |
75 ## Maximum number of iterations reached. | |
76 ## @item 6 | |
77 ## The problem is infeasible. | |
78 ## @end table | |
79 ## @end table | |
80 ## @end deftypefn | |
81 | |
82 function [x, obj, INFO, lambda] = qp (x0, H, q, A, b, lb, ub, A_lb, A_in, A_ub) | |
83 | |
84 if (nargin == 5 || nargin == 7 || nargin == 10) | |
85 | |
86 ## Checking the quadratic penalty | |
87 n = issquare (H); | |
88 if (n == 0) | |
89 error ("qp: quadratic penalty matrix not square"); | |
90 endif | |
91 | |
92 n1 = issymmetric (H); | |
93 if (n1 == 0) | |
94 ## warning ("qp: quadratic penalty matrix not symmetric"); | |
95 H = (H + H')/2; | |
96 endif | |
97 | |
98 ## Checking the initial guess (if empty it is resized to the | |
99 ## right dimension and filled with 0) | |
100 if (isempty (x0)) | |
101 x0 = zeros (n, 1); | |
102 elseif (length (x0) != n) | |
103 error ("qp: the initial guess has incorrect length"); | |
104 endif | |
105 | |
106 ## Linear penalty. | |
107 if (length (q) != n) | |
108 error ("qp: the linear term has incorrect length"); | |
109 endif | |
110 | |
111 ## Equality constraint matrices | |
112 if (isempty (A) || isempty(b)) | |
113 n_eq = 0; | |
114 A = zeros (n_eq, n); | |
115 b = zeros (n_eq, 1); | |
116 else | |
117 [n_eq, n1] = size (A); | |
118 if (n1 != n) | |
119 error ("qp: equality constraint matrix has incorrect column dimension"); | |
120 endif | |
121 if (length (b) != n_eq) | |
122 error ("qp: equality constraint matrix and vector have inconsistent dimension"); | |
123 endif | |
124 endif | |
125 | |
126 ## Bound constraints | |
127 Ain = zeros (0, n); | |
128 bin = zeros (0, 1); | |
129 n_in = 0; | |
130 if (nargin > 5) | |
131 if (! isempty (lb)) | |
132 if (length(lb) != n) | |
133 error ("qp: lower bound has incorrect length"); | |
134 else | |
135 Ain = [Ain; eye(n)]; | |
136 bin = [bin; lb]; | |
137 endif | |
138 endif | |
139 | |
140 if (! isempty (ub)) | |
141 if (length (ub) != n) | |
142 error ("qp: upper bound has incorrect length"); | |
143 else | |
144 Ain = [Ain; -eye(n)]; | |
145 bin = [bin; -ub]; | |
146 endif | |
147 endif | |
148 endif | |
149 | |
150 ## Inequality constraints | |
151 if (nargin > 7) | |
152 [dimA_in, n1] = size (A_in); | |
153 if (n1 != n) | |
154 error ("qp: inequality constraint matrix has incorrect column dimension"); | |
155 else | |
156 if (! isempty (A_lb)) | |
157 if (length (A_lb) != dimA_in) | |
158 error ("qp: inequality constraint matrix and lower bound vector inconsistent"); | |
159 else | |
160 Ain = [Ain; A_in]; | |
161 bin = [bin; A_lb]; | |
162 endif | |
163 endif | |
164 if (! isempty (A_ub)) | |
165 if (length (A_ub) != dimA_in) | |
166 error ("qp: inequality constraint matrix and upper bound vector inconsistent"); | |
167 else | |
168 Ain = [Ain; -A_in]; | |
169 bin = [bin; -A_ub]; | |
170 endif | |
171 endif | |
172 endif | |
173 endif | |
174 | |
175 ## Now we should have the following QP: | |
176 ## | |
177 ## min_x 0.5*x'*H*x + x'*q | |
178 ## s.t. A*x = b | |
179 ## Ain*x >= bin | |
180 | |
181 ## Discard inequality constraints that have -Inf bounds since those | |
182 ## will never be active. | |
183 idx = isinf (bin) & bin < 0; | |
6523 | 184 |
6526 | 185 bin(idx) = []; |
186 Ain(idx,:) = []; | |
5289 | 187 |
5310 | 188 n_in = length (bin); |
189 | |
5289 | 190 ## Check if the initial guess is feasible. |
7795
df9519e9990c
Handle single precision eps values
David Bateman <dbateman@free.fr>
parents:
7017
diff
changeset
|
191 if (isa (x0, "single") || isa (H, "single") || isa (q, "single") || isa (A, "single") |
df9519e9990c
Handle single precision eps values
David Bateman <dbateman@free.fr>
parents:
7017
diff
changeset
|
192 || isa (b, "single")) |
df9519e9990c
Handle single precision eps values
David Bateman <dbateman@free.fr>
parents:
7017
diff
changeset
|
193 rtol = sqrt (eps ("single")); |
df9519e9990c
Handle single precision eps values
David Bateman <dbateman@free.fr>
parents:
7017
diff
changeset
|
194 else |
df9519e9990c
Handle single precision eps values
David Bateman <dbateman@free.fr>
parents:
7017
diff
changeset
|
195 rtol = sqrt (eps); |
df9519e9990c
Handle single precision eps values
David Bateman <dbateman@free.fr>
parents:
7017
diff
changeset
|
196 endif |
5289 | 197 |
198 eq_infeasible = (n_eq > 0 && norm (A*x0-b) > rtol*(1+norm (b))); | |
199 in_infeasible = (n_in > 0 && any (Ain*x0-bin < -rtol*(1+norm (bin)))); | |
200 | |
201 info = 0; | |
202 if (eq_infeasible || in_infeasible) | |
203 ## The initial guess is not feasible. | |
204 ## First define xbar that is feasible with respect to the equality | |
205 ## constraints. | |
206 if (eq_infeasible) | |
207 if (rank (A) < n_eq) | |
208 error ("qp: equality constraint matrix must be full row rank") | |
209 endif | |
210 xbar = pinv (A) * b; | |
211 else | |
212 xbar = x0; | |
213 endif | |
214 | |
215 ## Check if xbar is feasible with respect to the inequality | |
216 ## constraints also. | |
217 if (n_in > 0) | |
218 res = Ain * xbar - bin; | |
219 if (any (res < -rtol * (1 + norm (bin)))) | |
220 ## xbar is not feasible with respect to the inequality | |
221 ## constraints. Compute a step in the null space of the | |
222 ## equality constraints, by solving a QP. If the slack is | |
223 ## small, we have a feasible initial guess. Otherwise, the | |
224 ## problem is infeasible. | |
225 if (n_eq > 0) | |
226 Z = null (A); | |
227 if (isempty (Z)) | |
228 ## The problem is infeasible because A is square and full | |
229 ## rank, but xbar is not feasible. | |
230 info = 6; | |
231 endif | |
232 endif | |
233 | |
234 if (info != 6) | |
235 ## Solve an LP with additional slack variables to find | |
236 ## a feasible starting point. | |
237 gamma = eye (n_in); | |
238 if (n_eq > 0) | |
239 Atmp = [Ain*Z, gamma]; | |
240 btmp = -res; | |
241 else | |
242 Atmp = [Ain, gamma]; | |
243 btmp = bin; | |
244 endif | |
245 ctmp = [zeros(n-n_eq, 1); ones(n_in, 1)]; | |
246 lb = [-Inf*ones(n-n_eq,1); zeros(n_in,1)]; | |
247 ub = []; | |
248 ctype = repmat ("L", n_in, 1); | |
249 [P, dummy, status] = glpk (ctmp, Atmp, btmp, lb, ub, ctype); | |
250 if ((status == 180 || status == 181 || status == 151) | |
251 && all (abs (P(n-n_eq+1:end)) < rtol * (1 + norm (btmp)))) | |
252 ## We found a feasible starting point | |
253 if (n_eq > 0) | |
5306 | 254 x0 = xbar + Z*P(1:n-n_eq); |
5289 | 255 else |
256 x0 = P(1:n); | |
257 endif | |
258 else | |
259 ## The problem is infeasible | |
260 info = 6; | |
261 endif | |
262 endif | |
263 else | |
264 ## xbar is feasible. We use it a starting point. | |
265 x0 = xbar; | |
266 endif | |
267 else | |
268 ## xbar is feasible. We use it a starting point. | |
269 x0 = xbar; | |
270 endif | |
271 endif | |
272 | |
273 if (info == 0) | |
6848 | 274 ## FIXME -- make maxit a user option. |
5289 | 275 ## The initial (or computed) guess is feasible. |
276 ## We call the solver. | |
6848 | 277 maxit = 200; |
5289 | 278 [x, lambda, info, iter] = __qp__ (x0, H, q, A, b, Ain, bin, maxit); |
279 else | |
280 iter = 0; | |
281 x = x0; | |
282 lambda = []; | |
283 endif | |
284 obj = 0.5 * x' * H * x + q' * x; | |
285 INFO.solveiter = iter; | |
286 INFO.info = info; | |
287 | |
288 else | |
6046 | 289 print_usage (); |
5289 | 290 endif |
291 | |
292 endfunction |