A sparse MPC solver for walking motion generation (old version).
solver/qp_ip.cpp
Go to the documentation of this file.
00001 
00008 /****************************************
00009  * INCLUDES 
00010  ****************************************/
00011 #include "qp_ip.h"
00012 #include "state_handling.h"
00013 
00014 
00015 #include <cmath> // log, fabs
00016 
00017 /****************************************
00018  * FUNCTIONS
00019  ****************************************/
00020 
00021 
00022 //==============================================
00023 // qp_ip
00024 
00034 qp_ip::qp_ip(
00035         const int N_, 
00036         const double Alpha, 
00037         const double Beta, 
00038         const double Gamma, 
00039         const double regularization, 
00040         const double tol_) : 
00041     qp_solver (N_, Alpha, Beta, Gamma, regularization, tol_),
00042     chol (N_)
00043 {
00044     g = new double[2*N];
00045     i2hess = new double[2*N];
00046     i2hess_grad = new double[N*SMPC_NUM_VAR];
00047     grad = new double[N*SMPC_NUM_VAR];
00048 
00049     Q[0] = Beta/2;
00050     Q[1] = Alpha/2;
00051     Q[2] = regularization;
00052     P = Gamma/2;
00053 }
00054 
00055 
00057 qp_ip::~qp_ip()
00058 {
00059     if (g != NULL)
00060         delete g;
00061     if (i2hess != NULL)
00062         delete i2hess;
00063     if (i2hess_grad != NULL)
00064         delete i2hess_grad;
00065     if (grad != NULL)
00066         delete grad;
00067 }
00068 
00069 
00081 void qp_ip::set_parameters(
00082         const double* T, 
00083         const double* h, 
00084         const double h_initial_, 
00085         const double* angle,
00086         const double* zref_x,
00087         const double* zref_y,
00088         const double* lb_,
00089         const double* ub_)
00090 {
00091     h_initial = h_initial_;
00092     set_state_parameters (T, h, h_initial_, angle);
00093 
00094     lb = lb_;
00095     ub = ub_;
00096 
00097     form_g (zref_x, zref_y);
00098 }
00099 
00100 
00101 
00108 void qp_ip::form_g (const double *zref_x, const double *zref_y)
00109 {
00110     double p0, p1;
00111     double cosA, sinA;
00112 
00113     for (int i = 0; i < N; i++)
00114     {
00115         cosA = spar[i].cos;
00116         sinA = spar[i].sin;
00117 
00118         // zref
00119         p0 = zref_x[i];
00120         p1 = zref_y[i];
00121 
00122         // inv (2*H) * R' * Cp' * zref
00123         g[i*2] = -(cosA*p0 + sinA*p1)*gain_beta;
00124         g[i*2 + 1] = -(-sinA*p0 + cosA*p1)*gain_beta; 
00125     }
00126 }
00127 
00128 
00129 
00136 void qp_ip::form_grad_i2hess_logbar (const double kappa)
00137 {
00138     phi_X = 0;
00139     int i,j;
00140 
00141 
00142     // grad = H*X + g + kappa * b;
00143     // initialize grad = H*X
00144     for (i = 0; i < N*SMPC_NUM_STATE_VAR; i++)
00145     {
00146         grad[i] = X[i] / i2Q[i%3];
00147     }
00148     for (; i < N*SMPC_NUM_VAR; i++)
00149     {
00150         grad[i] = X[i] / i2P;
00151     }
00152 
00153     // finish initalization of grad 
00154     // initialize inverted hessian
00155     // initialize logarithmic barrier in the function
00156     for (i = 0, j = 0; i < 2*N; i++, j += 3)
00157     {
00158         double lb_diff = -lb[i] + X[j];
00159         double ub_diff =  ub[i] - X[j];
00160 
00161         // logarithmic barrier
00162         phi_X -= log(lb_diff) + log(ub_diff);
00163 
00164         lb_diff = 1/lb_diff;
00165         ub_diff = 1/ub_diff;
00166 
00167         // grad += g + kappa * (ub_diff - lb_diff)
00168         grad[j] += g[i] + kappa * (ub_diff - lb_diff);
00169 
00170         // only elements 1:3:N*SMPC_NUM_STATE_VAR on the diagonal of hessian 
00171         // can change
00172         // hess = H + kappa * (ub_diff^2 - lb_diff^2)
00173         i2hess[i] = 1/(2*Q[0] + kappa * (ub_diff*ub_diff + lb_diff*lb_diff));
00174     }
00175     phi_X *= kappa;
00176 }
00177 
00178 
00179 
00183 void qp_ip::form_i2hess_grad ()
00184 {
00185     int i,j;
00186     for (i = 0, j = 0; i < N*2; i++)
00187     {
00188         i2hess_grad[j] = - grad[j] * i2hess[i]; 
00189         j++;
00190         i2hess_grad[j] = - grad[j] * i2Q[1]; 
00191         j++;
00192         i2hess_grad[j] = - grad[j] * i2Q[2]; 
00193         j++;
00194     }
00195     for (i = N*SMPC_NUM_STATE_VAR; i < N*SMPC_NUM_VAR; i++)
00196     {
00197         i2hess_grad[i] = - grad[i] * i2P;
00198     }
00199 }
00200 
00201 
00202 
00207 void qp_ip::form_phi_X ()
00208 {
00209     int i;
00210 
00211     // phi_X += X'*H*X
00212     for (i = 0; i < N*SMPC_NUM_STATE_VAR; i++)
00213     {
00214         phi_X += Q[i%3] * X[i] * X[i];
00215     }
00216     for (; i < N*SMPC_NUM_VAR; i++)
00217     {
00218         phi_X += P * X[i] * X[i];
00219     }
00220 
00221     // phi_X += g'*X
00222     for (i = 0; i < 2*N; i++)
00223     {
00224         phi_X += g[i] * X[i*3];
00225     }
00226 }
00227 
00228 
00234 void qp_ip::init_alpha()
00235 {
00236     double min_alpha = 1;
00237     alpha = 1;
00238 
00239     for (int i = 0; i < 2*N; i++)
00240     {
00241         // lower bound may be violated
00242         if (dX[i*3] < 0)
00243         {
00244             double tmp_alpha = (lb[i]-X[i*3])/dX[i*3];
00245             if (tmp_alpha < min_alpha)
00246             {
00247                 min_alpha = tmp_alpha;
00248             }
00249         }
00250         // upper bound may be violated
00251         else if (dX[i*3] > 0)
00252         {
00253             double tmp_alpha = (ub[i]-X[i*3])/dX[i*3];
00254             if (tmp_alpha < min_alpha)
00255             {
00256                 min_alpha = tmp_alpha;
00257             }
00258         }
00259     }
00260 
00261     if (min_alpha > tol)
00262     {
00263         while (alpha > min_alpha)
00264         {
00265             alpha *= bs_beta;
00266         }
00267     }
00268     else
00269     {
00270         alpha = 0;
00271     }
00272 }
00273 
00274 
00275 
00281 double qp_ip::form_bs_alpha_grad_dX ()
00282 {
00283     double res = 0;
00284     
00285     for (int i = 0; i < N*SMPC_NUM_VAR; i++)
00286     {
00287         res += grad[i]*dX[i];
00288     }
00289 
00290     return (res*bs_alpha);
00291 }
00292 
00293 
00301 double qp_ip::form_phi_X_tmp (const double kappa)
00302 {
00303     int i,j;
00304     double res = 0;
00305     double X_tmp;
00306 
00307 
00308     // phi_X += X'*H*X
00309     for (i = 0,j = 0; i < 2*N; i++)
00310     {
00311         X_tmp = X[j] + alpha * dX[j];
00312         j++;
00313 
00314         // logarithmic barrier
00315         res -= kappa * (log(-lb[i] + X_tmp) + log(ub[i] - X_tmp));
00316 
00317         // phi_X += g'*X
00318         res += g[i] * X_tmp;
00319 
00320 
00321         // phi_X += X'*H*X // states
00322         res += Q[0] * X_tmp*X_tmp;
00323 
00324         X_tmp = X[j] + alpha * dX[j];
00325         j++;
00326         res += Q[1] * X_tmp*X_tmp;
00327 
00328         X_tmp = X[j] + alpha * dX[j];
00329         j++;
00330         res += Q[2] * X_tmp*X_tmp;
00331     }
00332     // phi_X += X'*H*X // controls
00333     for (i = N*SMPC_NUM_STATE_VAR; i < N*SMPC_NUM_VAR; i++)
00334     {
00335         X_tmp = X[i] + alpha * dX[i];
00336         res += P * X_tmp * X_tmp;
00337     }
00338 
00339     return (res);
00340 }
00341 
00342 
00343 
00354 void qp_ip::set_ip_parameters (
00355         const double t_, 
00356         const double mu_, 
00357         const double bs_alpha_, 
00358         const double bs_beta_, 
00359         const int max_iter_,
00360         const double tol_out_)
00361 {
00362     t = t_;
00363     mu = mu_;
00364     bs_alpha = bs_alpha_;
00365     bs_beta = bs_beta_;
00366     max_iter = max_iter_;
00367     tol_out = tol_out_;
00368 }
00369 
00370 
00371 
00377 int qp_ip::solve()
00378 {
00379     double kappa = 1/t;
00380     double duality_gap = 2*N*kappa;
00381     int i;
00382 
00383 
00384     while (duality_gap > tol_out)
00385     {
00386         for (i = 0; (i < max_iter) && solve_onestep(kappa); i++);
00387         if (i == max_iter)
00388         {
00389             return (-1);
00390         }
00391 
00392         kappa /= mu;
00393         duality_gap = 2*N*kappa;
00394     }
00395     return (0);
00396 }
00397 
00398 
00406 bool qp_ip::solve_onestep (const double kappa)
00407 {
00408     int i,j;
00409 
00410 
00411     form_grad_i2hess_logbar (kappa);
00412     form_phi_X ();
00413     form_i2hess_grad ();
00414 
00415     chol.solve (*this, i2hess_grad, i2hess, X, dX);
00416 
00417 
00418     // stopping criterion (decrement)
00419     double decrement = 0;
00420     for (i = 0, j = 0; i < N*2; i++)
00421     {
00422         decrement += dX[j] * dX[j] / i2hess[i];
00423         j++;
00424         decrement += dX[j] * dX[j] / i2Q[1];
00425         j++;
00426         decrement += dX[j] * dX[j] / i2Q[2];
00427         j++;
00428     }
00429     for (i = N*SMPC_NUM_STATE_VAR; i < N*SMPC_NUM_VAR; i++)
00430     {
00431         decrement += dX[i] * dX[i] / i2P;
00432     }
00433     if (decrement < tol)
00434     {
00435         return (false);
00436     }
00437 
00438 
00439     init_alpha ();
00440     // stopping criterion (step size)
00441     if (alpha < tol)
00442     {
00443         return (false); // done
00444     }
00445 
00446 
00447     // backtracking search
00448     double bs_alpha_grad_dX = form_bs_alpha_grad_dX ();
00449     for (;;)
00450     {
00451         if (form_phi_X_tmp (kappa) <= phi_X + alpha * bs_alpha_grad_dX)
00452         {
00453             break;
00454         }
00455 
00456         alpha = bs_beta * alpha;
00457 
00458         // stopping criterion (step size)
00459         if (alpha < tol)
00460         {
00461             return (false); // done
00462         }
00463     }
00464 
00465 
00466     // Move in the feasible descent direction
00467     for (j = 0; j < N*SMPC_NUM_VAR ; j++)
00468     {
00469         X[j] += alpha * dX[j];
00470     }
00471 
00472     return (true);
00473 }