5289
|
1 ## Copyright (C) 2000, 2001, 2004, 2005 Gabriele Pannocchia. |
|
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. |
|
191 rtol = sqrt (eps); |
|
192 |
|
193 eq_infeasible = (n_eq > 0 && norm (A*x0-b) > rtol*(1+norm (b))); |
|
194 in_infeasible = (n_in > 0 && any (Ain*x0-bin < -rtol*(1+norm (bin)))); |
|
195 |
|
196 info = 0; |
|
197 if (eq_infeasible || in_infeasible) |
|
198 ## The initial guess is not feasible. |
|
199 ## First define xbar that is feasible with respect to the equality |
|
200 ## constraints. |
|
201 if (eq_infeasible) |
|
202 if (rank (A) < n_eq) |
|
203 error ("qp: equality constraint matrix must be full row rank") |
|
204 endif |
|
205 xbar = pinv (A) * b; |
|
206 else |
|
207 xbar = x0; |
|
208 endif |
|
209 |
|
210 ## Check if xbar is feasible with respect to the inequality |
|
211 ## constraints also. |
|
212 if (n_in > 0) |
|
213 res = Ain * xbar - bin; |
|
214 if (any (res < -rtol * (1 + norm (bin)))) |
|
215 ## xbar is not feasible with respect to the inequality |
|
216 ## constraints. Compute a step in the null space of the |
|
217 ## equality constraints, by solving a QP. If the slack is |
|
218 ## small, we have a feasible initial guess. Otherwise, the |
|
219 ## problem is infeasible. |
|
220 if (n_eq > 0) |
|
221 Z = null (A); |
|
222 if (isempty (Z)) |
|
223 ## The problem is infeasible because A is square and full |
|
224 ## rank, but xbar is not feasible. |
|
225 info = 6; |
|
226 endif |
|
227 endif |
|
228 |
|
229 if (info != 6) |
|
230 ## Solve an LP with additional slack variables to find |
|
231 ## a feasible starting point. |
|
232 gamma = eye (n_in); |
|
233 if (n_eq > 0) |
|
234 Atmp = [Ain*Z, gamma]; |
|
235 btmp = -res; |
|
236 else |
|
237 Atmp = [Ain, gamma]; |
|
238 btmp = bin; |
|
239 endif |
|
240 ctmp = [zeros(n-n_eq, 1); ones(n_in, 1)]; |
|
241 lb = [-Inf*ones(n-n_eq,1); zeros(n_in,1)]; |
|
242 ub = []; |
|
243 ctype = repmat ("L", n_in, 1); |
|
244 [P, dummy, status] = glpk (ctmp, Atmp, btmp, lb, ub, ctype); |
|
245 if ((status == 180 || status == 181 || status == 151) |
|
246 && all (abs (P(n-n_eq+1:end)) < rtol * (1 + norm (btmp)))) |
|
247 ## We found a feasible starting point |
|
248 if (n_eq > 0) |
5306
|
249 x0 = xbar + Z*P(1:n-n_eq); |
5289
|
250 else |
|
251 x0 = P(1:n); |
|
252 endif |
|
253 else |
|
254 ## The problem is infeasible |
|
255 info = 6; |
|
256 endif |
|
257 endif |
|
258 else |
|
259 ## xbar is feasible. We use it a starting point. |
|
260 x0 = xbar; |
|
261 endif |
|
262 else |
|
263 ## xbar is feasible. We use it a starting point. |
|
264 x0 = xbar; |
|
265 endif |
|
266 endif |
|
267 |
|
268 if (info == 0) |
6848
|
269 ## FIXME -- make maxit a user option. |
5289
|
270 ## The initial (or computed) guess is feasible. |
|
271 ## We call the solver. |
6848
|
272 maxit = 200; |
5289
|
273 [x, lambda, info, iter] = __qp__ (x0, H, q, A, b, Ain, bin, maxit); |
|
274 else |
|
275 iter = 0; |
|
276 x = x0; |
|
277 lambda = []; |
|
278 endif |
|
279 obj = 0.5 * x' * H * x + q' * x; |
|
280 INFO.solveiter = iter; |
|
281 INFO.info = info; |
|
282 |
|
283 else |
6046
|
284 print_usage (); |
5289
|
285 endif |
|
286 |
|
287 endfunction |