GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
__qp__.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2000-2017 Gabriele Pannocchia
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <cfloat>
28 
29 #include "chol.h"
30 #include "svd.h"
31 #include "mx-m-dm.h"
32 #include "EIG.h"
33 
34 #include "defun.h"
35 #include "error.h"
36 #include "errwarn.h"
37 #include "ovl.h"
38 #include "pr-output.h"
39 #include "utils.h"
40 
41 static Matrix
42 null (const Matrix& A, octave_idx_type& rank)
43 {
44  Matrix retval;
45 
46  rank = 0;
47 
48  if (! A.is_empty ())
49  {
50  octave::math::svd<Matrix> A_svd (A);
51 
52  DiagMatrix S = A_svd.singular_values ();
53 
55 
56  Matrix V = A_svd.right_singular_matrix ();
57 
58  octave_idx_type A_nr = A.rows ();
59  octave_idx_type A_nc = A.cols ();
60 
61  octave_idx_type tmp = A_nr > A_nc ? A_nr : A_nc;
62 
63  double tol = tmp * s(0) * std::numeric_limits<double>::epsilon ();
64 
65  octave_idx_type n = s.numel ();
66 
67  for (octave_idx_type i = 0; i < n; i++)
68  {
69  if (s(i) > tol)
70  rank++;
71  }
72 
73  if (rank < A_nc)
74  retval = V.extract (0, rank, A_nc-1, A_nc-1);
75  else
76  retval.resize (A_nc, 0);
77 
78  for (octave_idx_type i = 0; i < retval.numel (); i++)
79  if (std::abs (retval(i)) < std::numeric_limits<double>::epsilon ())
80  retval(i) = 0;
81  }
82 
83  return retval;
84 }
85 
86 static int
87 qp (const Matrix& H, const ColumnVector& q,
88  const Matrix& Aeq, const ColumnVector& beq,
89  const Matrix& Ain, const ColumnVector& bin,
90  int maxit,
91  ColumnVector& x, ColumnVector& lambda, int& iter)
92 {
93  int info = 0;
94 
95  iter = 0;
96 
97  double rtol = sqrt (std::numeric_limits<double>::epsilon ());
98 
99  // Problem dimension.
100  octave_idx_type n = x.numel ();
101 
102  // Dimension of constraints.
103  octave_idx_type n_eq = beq.numel ();
104  octave_idx_type n_in = bin.numel ();
105 
106  // Filling the current active set.
107 
108  octave_idx_type n_act = n_eq;
109 
110  octave_idx_type n_tot = n_eq + n_in;
111 
112  // Equality constraints come first. We won't check the sign of the
113  // Lagrange multiplier for those.
114 
115  Matrix Aact = Aeq;
116  ColumnVector bact = beq;
117  ColumnVector Wact;
118 
119  if (n_in > 0)
120  {
121  ColumnVector res = Ain*x - bin;
122 
123  for (octave_idx_type i = 0; i < n_in; i++)
124  {
125  res(i) /= (1.0 + std::abs (bin(i)));
126 
127  if (res(i) < rtol)
128  {
129  n_act++;
130  Aact = Aact.stack (Ain.row (i));
131  bact.resize (n_act, bin(i));
132  Wact.resize (n_act-n_eq, i);
133  }
134  }
135  }
136 
137  // Computing the ???
138 
139  EIG eigH;
140 
141  try
142  {
143  eigH = EIG (H);
144  }
145  catch (octave::execution_exception& e)
146  {
147  error (e, "qp: failed to compute eigenvalues of H");
148  }
149 
150  ColumnVector eigenvalH = real (eigH.eigenvalues ());
151  Matrix eigenvecH = real (eigH.right_eigenvectors ());
152  double minReal = eigenvalH.min ();
153  octave_idx_type indminR = 0;
154  for (octave_idx_type i = 0; i < n; i++)
155  {
156  if (minReal == eigenvalH(i))
157  {
158  indminR = i;
159  break;
160  }
161  }
162 
163  bool done = false;
164 
165  double alpha = 0.0;
166 
167  Matrix R;
168  Matrix Y (n, 0, 0.0);
169 
170  ColumnVector g (n, 0.0);
171  ColumnVector p (n, 0.0);
172 
173  ColumnVector lambda_tmp (n_in, 0.0);
174 
175  while (! done)
176  {
177  iter++;
178 
179  // Current Gradient
180  // g = q + H * x;
181 
182  g = q + H * x;
183 
184  if (n_act == 0)
185  {
186  // There are no active constraints.
187 
188  if (minReal > 0.0)
189  {
190  // Inverting the Hessian. Using the Cholesky
191  // factorization since the Hessian is positive
192  // definite.
193 
194  octave::math::chol<Matrix> cholH (H);
195 
196  R = cholH.chol_matrix ();
197 
198  Matrix Hinv = octave::math::chol2inv (R);
199 
200  // Computing the unconstrained step.
201  // p = -Hinv * g;
202 
203  p = -Hinv * g;
204 
205  info = 0;
206  }
207  else
208  {
209  // Finding the negative curvature of H.
210 
211  p = eigenvecH.column (indminR);
212 
213  // Following the negative curvature of H.
214 
215  if (p.transpose () * g > std::numeric_limits<double>::epsilon ())
216  p = -p;
217 
218  info = 1;
219  }
220 
221  // Multipliers are zero.
222  lambda_tmp.fill (0.0);
223  }
224  else
225  {
226  // There are active constraints.
227 
228  // Computing the null space.
229 
230  octave_idx_type rank;
231 
232  Matrix Z = null (Aact, rank);
233 
234  octave_idx_type dimZ = n - rank;
235 
236  // FIXME: still remain to handle the case of
237  // non-full rank active set matrix.
238 
239  // Computing the Y matrix (orthogonal to Z)
240  Y = Aact.pseudo_inverse ();
241 
242  // Reduced Hessian
243  Matrix Zt = Z.transpose ();
244  Matrix rH = Zt * H * Z;
245 
246  octave_idx_type pR = 0;
247 
248  if (dimZ > 0)
249  {
250  // Computing the Cholesky factorization (pR = 0 means
251  // that the reduced Hessian was positive definite).
252 
253  octave::math::chol<Matrix> cholrH (rH, pR);
254  Matrix tR = cholrH.chol_matrix ();
255  if (pR == 0)
256  R = tR;
257  }
258 
259  if (pR == 0)
260  {
261  info = 0;
262 
263  // Computing the step pz.
264  if (dimZ > 0)
265  {
266  // Using the Cholesky factorization to invert rH
267 
268  Matrix rHinv = octave::math::chol2inv (R);
269 
270  ColumnVector pz = -rHinv * Zt * g;
271 
272  // Global step.
273  p = Z * pz;
274  }
275  else
276  {
277  // Global step.
278  p.fill (0.0);
279  }
280  }
281  else
282  {
283  info = 1;
284 
285  // Searching for the most negative curvature.
286 
287  EIG eigrH;
288 
289  try
290  {
291  eigrH = EIG (rH);
292  }
293  catch (octave::execution_exception& e)
294  {
295  error (e, "qp: failed to compute eigenvalues of rH");
296  }
297 
298  ColumnVector eigenvalrH = real (eigrH.eigenvalues ());
299  Matrix eigenvecrH = real (eigrH.right_eigenvectors ());
300  double mRrH = eigenvalrH.min ();
301  indminR = 0;
302  for (octave_idx_type i = 0; i < n; i++)
303  {
304  if (mRrH == eigenvalH(i))
305  {
306  indminR = i;
307  break;
308  }
309  }
310 
311  ColumnVector eVrH = eigenvecrH.column (indminR);
312 
313  // Computing the step pz.
314  p = Z * eVrH;
315 
316  if (p.transpose () * g > std::numeric_limits<double>::epsilon ())
317  p = -p;
318  }
319  }
320 
321  // Checking the step-size.
322  ColumnVector abs_p (n);
323  for (octave_idx_type i = 0; i < n; i++)
324  abs_p(i) = std::abs (p(i));
325  double max_p = abs_p.max ();
326 
327  if (max_p < rtol)
328  {
329  // The step is null. Checking constraints.
330  if (n_act - n_eq == 0)
331  // Solution is found because no inequality
332  // constraints are active.
333  done = true;
334  else
335  {
336  // Computing the multipliers only for the inequality
337  // constraints that are active. We do NOT compute
338  // multipliers for the equality constraints.
339  Matrix Yt = Y.transpose ();
340  Yt = Yt.extract_n (n_eq, 0, n_act-n_eq, n);
341  lambda_tmp = Yt * (g + H * p);
342 
343  // Checking the multipliers. We remove the most
344  // negative from the set (if any).
345  double min_lambda = lambda_tmp.min ();
346  if (min_lambda >= 0)
347  {
348  // Solution is found.
349  done = true;
350  }
351  else
352  {
353  octave_idx_type which_eig = 0;
354  for (octave_idx_type i = 0; i < n_act; i++)
355  {
356  if (lambda_tmp(i) == min_lambda)
357  {
358  which_eig = i;
359  break;
360  }
361  }
362 
363  // At least one multiplier is negative, we
364  // remove it from the set.
365 
366  n_act--;
367  for (octave_idx_type i = which_eig; i < n_act - n_eq; i++)
368  {
369  Wact(i) = Wact(i+1);
370  for (octave_idx_type j = 0; j < n; j++)
371  Aact(n_eq+i,j) = Aact(n_eq+i+1,j);
372  bact(n_eq+i) = bact(n_eq+i+1);
373  }
374 
375  // Resizing the active set.
376  Wact.resize (n_act-n_eq);
377  bact.resize (n_act);
378  Aact.resize (n_act, n);
379  }
380  }
381  }
382  else
383  {
384  // The step is not null.
385  if (n_act - n_eq == n_in)
386  {
387  // All inequality constraints were active. We can
388  // add the whole step.
389  x += p;
390  }
391  else
392  {
393  // Some constraints were not active. Checking if
394  // there is a blocking constraint.
395  alpha = 1.0;
396  octave_idx_type is_block = -1;
397 
398  for (octave_idx_type i = 0; i < n_in; i++)
399  {
400  bool found = false;
401 
402  for (octave_idx_type j = 0; j < n_act-n_eq; j++)
403  {
404  if (Wact(j) == i)
405  {
406  found = true;
407  break;
408  }
409  }
410 
411  if (! found)
412  {
413  // The i-th constraint was not in the set. Is it a
414  // blocking constraint?
415 
416  RowVector tmp_row = Ain.row (i);
417  double tmp = tmp_row * p;
418  double res = tmp_row * x;
419 
420  if (tmp < 0.0)
421  {
422  double alpha_tmp = (bin(i) - res) / tmp;
423 
424  if (alpha_tmp < alpha)
425  {
426  alpha = alpha_tmp;
427  is_block = i;
428  }
429  }
430  }
431  }
432 
433  // In is_block there is the index of the blocking
434  // constraint (if any).
435  if (is_block >= 0)
436  {
437  // There is a blocking constraint (index in
438  // is_block) which is added to the active set.
439  n_act++;
440  Aact = Aact.stack (Ain.row (is_block));
441  bact.resize (n_act, bin(is_block));
442  Wact.resize (n_act-n_eq, is_block);
443 
444  // Adding the reduced step
445  x += alpha * p;
446  }
447  else
448  {
449  // There are no blocking constraints. Adding the
450  // whole step.
451  x += alpha * p;
452  }
453  }
454  }
455 
456  if (iter == maxit)
457  {
458  done = true;
459  // warning ("qp_main: maximum number of iteration reached");
460  info = 3;
461  }
462  }
463 
464  lambda_tmp = Y.transpose () * (g + H * p);
465 
466  // Reordering the Lagrange multipliers.
467 
468  lambda.resize (n_tot);
469  lambda.fill (0.0);
470  for (octave_idx_type i = 0; i < n_eq; i++)
471  lambda(i) = lambda_tmp(i);
472 
473  for (octave_idx_type i = n_eq; i < n_tot; i++)
474  {
475  for (octave_idx_type j = 0; j < n_act-n_eq; j++)
476  {
477  if (Wact(j) == i - n_eq)
478  {
479  lambda(i) = lambda_tmp(n_eq+j);
480  break;
481  }
482  }
483  }
484 
485  return info;
486 }
487 
488 DEFUN (__qp__, args, ,
489  doc: /* -*- texinfo -*-
490 @deftypefn {} {[@var{x}, @var{lambda}, @var{info}, @var{iter}] =} __qp__ (@var{x0}, @var{H}, @var{q}, @var{Aeq}, @var{beq}, @var{Ain}, @var{bin}, @var{maxit})
491 Undocumented internal function.
492 @end deftypefn */)
493 {
494  if (args.length () != 8)
495  print_usage ();
496 
497  const ColumnVector x0 (args(0).vector_value ());
498  const Matrix H (args(1).matrix_value ());
499  const ColumnVector q (args(2).vector_value ());
500  const Matrix Aeq (args(3).matrix_value ());
501  const ColumnVector beq (args(4).vector_value ());
502  const Matrix Ain (args(5).matrix_value ());
503  const ColumnVector bin (args(6).vector_value ());
504  const int maxit (args(7).int_value ());
505 
506  int iter = 0;
507 
508  // Copy the initial guess into the working variable
509  ColumnVector x = x0;
510 
511  // Reordering the Lagrange multipliers
512  ColumnVector lambda;
513 
514  int info = qp (H, q, Aeq, beq, Ain, bin, maxit, x, lambda, iter);
515 
516  return ovl (x, lambda, info, iter);
517 }
518 
519 /*
520 ## No test needed for internal helper function.
521 %!assert (1)
522 */
ColumnVector & fill(double val)
Definition: dColVector.cc:76
static int qp(const Matrix &H, const ColumnVector &q, const Matrix &Aeq, const ColumnVector &beq, const Matrix &Ain, const ColumnVector &bin, int maxit, ColumnVector &x, ColumnVector &lambda, int &iter)
Definition: __qp__.cc:87
bool is_empty(void) const
Definition: Array.h:575
F77_RET_T const F77_INT const F77_INT const F77_INT const F77_DBLE const F77_DBLE F77_INT F77_DBLE * V
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:145
Matrix extract(octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) const
Definition: dMatrix.cc:398
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
Definition: EIG.h:34
Matrix extract_n(octave_idx_type r1, octave_idx_type c1, octave_idx_type nr, octave_idx_type nc) const
Definition: dMatrix.cc:408
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:46
void error(const char *fmt,...)
Definition: error.cc:570
RowVector row(octave_idx_type i) const
Definition: dMatrix.cc:417
s
Definition: file-io.cc:2682
ColumnVector extract_diag(octave_idx_type k=0) const
Definition: dDiagMatrix.h:104
i e
Definition: data.cc:2724
octave_idx_type rows(void) const
Definition: Array.h:401
RowVector transpose(void) const
Definition: dColVector.cc:124
ComplexColumnVector eigenvalues(void) const
Definition: EIG.h:117
OCTAVE_EXPORT octave_value_list return the value of the option it must match the dimension of the state and the relative tolerance must also be a vector of the same length tem it must match the dimension of the state and the absolute tolerance must also be a vector of the same length The local error test applied at each integration step is xample roup calculate Y_a and Y _d item Given Y
Definition: DASPK-opts.cc:739
T right_singular_matrix(void) const
Definition: svd.cc:60
OCTAVE_EXPORT octave_value_list search each directory of the loadpath for element of the cell array and return the first that matches If the second optional argument return a cell array containing the list of all files that have the same name in the path If no files are found
Definition: utils.cc:302
JNIEnv void * args
Definition: ov-java.cc:67
static Matrix null(const Matrix &A, octave_idx_type &rank)
Definition: __qp__.cc:42
done
Definition: syscalls.cc:248
T chol2inv(const T &r)
Definition: chol.cc:247
DM_T singular_values(void) const
Definition: svd.h:86
double tmp
Definition: data.cc:6300
octave_value retval
Definition: data.cc:6294
Matrix transpose(void) const
Definition: dMatrix.h:129
Array< T > column(octave_idx_type k) const
Extract column: A(:,k+1).
Definition: Array.cc:269
F77_RET_T const F77_INT const F77_INT const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE * Z
Definition: dMatrix.h:37
double min(void) const
Definition: dColVector.cc:244
Matrix stack(const Matrix &a) const
Definition: dMatrix.cc:326
double max(void) const
Definition: dColVector.cc:260
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
OCTAVE_EXPORT octave_value_list return the value of the option it must match the dimension of the state and the relative tolerance must also be a vector of the same length tem it must match the dimension of the state and the absolute tolerance must also be a vector of the same length The local error test applied at each integration step is xample roup abs(local error in x(i))<
p
Definition: lu.cc:138
ComplexMatrix right_eigenvectors(void) const
Definition: EIG.h:118
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:136
octave_idx_type cols(void) const
Definition: Array.h:409
Matrix pseudo_inverse(double tol=0.0) const
Definition: dMatrix.cc:643
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x
void resize(octave_idx_type n, const double &rfv=0)
Definition: dColVector.h:108
F77_RET_T const F77_INT F77_CMPLX * A
T chol_matrix(void) const
Definition: chol.h:71