A sparse MPC solver for walking motion generation (old version).
solver/chol_solve_as.cpp
Go to the documentation of this file.
00001 
00009 /****************************************
00010  * INCLUDES 
00011  ****************************************/
00012 
00013 #include "chol_solve_as.h"
00014 
00015 #include <cmath> // sqrt
00016 #include <cstring> // memset
00017 
00018 
00019 /****************************************
00020  * FUNCTIONS 
00021  ****************************************/
00022 
00023 //==============================================
00024 // constructors / destructors
00025 
00031 chol_solve_as::chol_solve_as (const int N) : ecL(N)
00032 {
00033     nu = new double[SMPC_NUM_VAR*N];
00034     XiHg = new double[SMPC_NUM_VAR*N];
00035     z = new double[SMPC_NUM_VAR*N];
00036 
00037     icL = new double*[N*2];
00038     icL_mem = new double[SMPC_NUM_VAR*N*N*2];
00039     for(int i = 0; i < N*2; i++)
00040     {
00041         icL[i] = &icL_mem[i * SMPC_NUM_VAR*N];
00042     }
00043 }
00044 
00045 
00046 chol_solve_as::~chol_solve_as()
00047 {
00048     if (icL != NULL)
00049     {
00050         delete icL_mem;
00051         delete icL;
00052     }
00053     if (z != NULL)
00054         delete z;
00055     if (nu != NULL)
00056         delete nu;
00057     if (XiHg != NULL)
00058         delete XiHg;
00059 }
00060 //==============================================
00061 
00062 
00071 void chol_solve_as::form_sa_row(
00072         const problem_parameters& ppar, 
00073         const int ic_num, 
00074         const int var_num, 
00075         double *row)
00076 {
00077     double aiH = ppar.i2Q[0]; // a'*inv(H) = a'*inv(H)*a
00078     int state_num = var_num / 2; // number of state in the preview window
00079     int first_num = state_num * SMPC_NUM_STATE_VAR; // first !=0 element
00080     double aiHcosA;
00081     double aiHsinA;
00082 
00083 
00084     // reset memory
00085     memset(row, 0, (SMPC_NUM_STATE_VAR * ppar.N + ic_num) * sizeof(double));
00086 
00087     aiHcosA = aiH * ppar.spar[state_num].cos;
00088     aiHsinA = aiH * ppar.spar[state_num].sin;
00089 
00090     // compute elements of 'a'
00091     if (var_num%2 == 0)   // constraint on z_x
00092     {
00093         // a * -R
00094         row[first_num] = -aiHcosA;
00095         row[first_num + 3] = -aiHsinA;
00096 
00097         // a * A'*R'
00098         if (state_num != ppar.N-1)
00099         {
00100             row[first_num + 6] = aiHcosA;
00101             row[first_num + 9] = aiHsinA;
00102         }
00103     }
00104     else  // constraint on z_y
00105     {   
00106         // a * -R
00107         row[first_num] = aiHsinA;
00108         row[first_num + 3] = -aiHcosA;
00109 
00110         // a * A'*R'
00111         if (state_num != ppar.N-1)
00112         {
00113             row[first_num + 6] = -aiHsinA;
00114             row[first_num + 9] = aiHcosA;
00115         }
00116     }
00117 
00118     // initialize the last element in the row
00119     row[ic_num + ppar.N*SMPC_NUM_STATE_VAR] = aiH;
00120 }
00121 
00122 
00123 
00132 void chol_solve_as::solve(
00133         const problem_parameters& ppar, 
00134         const double *iHg,
00135         const double *x, 
00136         double *dx)
00137 {
00138     double *s_nu = nu;
00139     int i;
00140     double i2Q[3] = {ppar.i2Q[0], ppar.i2Q[1], ppar.i2Q[2]};
00141 
00142 
00143     // generate L
00144     ecL.form (ppar);
00145 
00146     // -(x + inv(H) * g)
00147     //  x - initial feasible point
00148     for (i = 0; i < SMPC_NUM_VAR * ppar.N; i++)
00149     {
00150         XiHg[i] = -x[i];
00151     }
00152     for (i = 0; i < 2*ppar.N; i++)
00153     {
00154         XiHg[i*3] -= iHg[i];
00155     }
00156 
00157     // obtain s = E * x;
00158     E.form_Ex (ppar, XiHg, s_nu);
00159 
00160     // obtain nu
00161     ecL.solve_forward(ppar.N, s_nu);
00162     // make copy of z - it is constant
00163     for (i = 0; i < SMPC_NUM_STATE_VAR * ppar.N; i++)
00164     {
00165         z[i] = s_nu[i];
00166     }
00167     ecL.solve_backward(ppar.N, s_nu);
00168 
00169     // E' * nu
00170     E.form_ETx (ppar, s_nu, dx);
00171 
00172     
00173     // dx = -iH*(grad + E'*nu)
00174     //
00175     // dx = -(x + inv(H) * g + inv(H) * E' * nu)
00176     //        ~~~~~~~~~~~~~~            ~~~~~~~
00177     // dx   -(   -XiHg       + inv(H) *   dx   ) 
00178     for (i = 0; i < ppar.N*SMPC_NUM_STATE_VAR; i++)
00179     {
00180         // dx for state variables
00181         dx[i] = XiHg[i] - i2Q[i%3] * dx[i];
00182     }
00183     for (; i < ppar.N*SMPC_NUM_VAR; i++)
00184     {
00185         // dx for control variables
00186         dx[i] = XiHg[i] - ppar.i2P * dx[i];
00187     }
00188 }
00189 
00190 
00202 void chol_solve_as::up_resolve(
00203         const problem_parameters& ppar, 
00204         const double *iHg,
00205         const int nW, 
00206         const int *W, 
00207         const double *x, 
00208         double *dx)
00209 {
00210     update (ppar, nW, W);
00211     update_z (ppar, iHg, nW, W, x);
00212     resolve (ppar, iHg, nW, W, x, dx);
00213 }
00214 
00215 
00224 void chol_solve_as::update (const problem_parameters& ppar, const int nW, const int *W)
00225 {
00226     int i, j, k;
00227 
00228     int ic_num = nW-1; // index of added constraint in W
00229     double *new_row = icL[ic_num]; // current row in icL
00230     // trailing elements of new_row corresponding to active constraints
00231     double *new_row_end = &new_row[ppar.N*SMPC_NUM_STATE_VAR]; 
00232 
00233     int last_num = ic_num + ppar.N*SMPC_NUM_STATE_VAR; // the last !=0 element
00234 
00235 
00236 
00237     // form row 'a' in the current row of icL
00238     form_sa_row(ppar, ic_num, W[ic_num], new_row);
00239 
00240     // update elements starting from the first non-zero
00241     // element in the row to SMPC_NUM_STATE_VAR * N (size of ecL)
00242     // the calculation of the last elements is completed
00243     // in a separate loop
00244     // each number in row 'a' causes update of only 3 elements following
00245     // it, they can be 1,2,6; 1,5,6; 4,5,6
00246     for(i = W[ic_num]/2; i < ppar.N; i++)
00247     {                                  
00248         // variables corresponding to x and y are computed using the same matrices
00249         for (k = 0; k < 2; k++)
00250         {
00251             double* cur_pos = &new_row[i*SMPC_NUM_STATE_VAR + 3*k];
00252 
00253             // ----------------------------------------------------------------
00254             cur_pos[0] /= ecL.ecL_diag[i][0];
00255             cur_pos[1] -= cur_pos[0] * ecL.ecL_diag[i][1];
00256             cur_pos[1] /= ecL.ecL_diag[i][4];
00257             cur_pos[2] -= cur_pos[0] * ecL.ecL_diag[i][2] + cur_pos[1] * ecL.ecL_diag[i][5];
00258             cur_pos[2] /= ecL.ecL_diag[i][8];
00259 
00260             // make a copy for faster computations
00261             double tmp_copy_el[3] = {cur_pos[0], cur_pos[1], cur_pos[2]};
00262 
00263             // ----------------------------------------------------------------
00264             if (i < ppar.N - 1) // non-diagonal matrix of ecL cannot be
00265             {                   // used when the last state is processed
00266 
00267                 // these elements can be updated here, since they are not 
00268                 // used in computation of other elements on this iteration
00269                 cur_pos[6] -= tmp_copy_el[0] * ecL.ecL_ndiag[i][0] 
00270                             + tmp_copy_el[1] * ecL.ecL_ndiag[i][3]
00271                             + tmp_copy_el[2] * ecL.ecL_ndiag[i][6];
00272 
00273                 cur_pos[7] -= tmp_copy_el[1] * ecL.ecL_ndiag[i][4]
00274                             + tmp_copy_el[2] * ecL.ecL_ndiag[i][7];
00275 
00276                 cur_pos[8] -= tmp_copy_el[2] * ecL.ecL_ndiag[i][8];
00277             }
00278             // update the last (diagonal) number in the row
00279             new_row[last_num] -= tmp_copy_el[0] * tmp_copy_el[0] 
00280                                + tmp_copy_el[1] * tmp_copy_el[1] 
00281                                + tmp_copy_el[2] * tmp_copy_el[2];
00282 
00283             // update elements after N*SMPC_NUM_STATE_VAR using the previously added rows
00284             // in icL
00285             for (j = 0; j < ic_num; j++)
00286             {
00287                 new_row_end[j] -= tmp_copy_el[0] * icL[j][i*SMPC_NUM_STATE_VAR + 3*k]
00288                                 + tmp_copy_el[1] * icL[j][i*SMPC_NUM_STATE_VAR + 3*k + 1]
00289                                 + tmp_copy_el[2] * icL[j][i*SMPC_NUM_STATE_VAR + 3*k + 2];
00290             }
00291         }
00292     }
00293 
00294     // update elements in the end of icL
00295     for(i = SMPC_NUM_STATE_VAR * ppar.N, k = 0; i < last_num; i++, k++)
00296     {
00297         new_row[i] /= icL[k][i];
00298         double tmp_copy_el = new_row[i];
00299 
00300         // determine number in the row of L
00301 
00302         // update the last (diagonal) number in the row
00303         new_row[last_num] -= tmp_copy_el * tmp_copy_el;
00304 
00305         for (j = k+1; j < ic_num; j++)
00306         {
00307             new_row_end[j] -= tmp_copy_el * icL[j][i];
00308         }
00309     }
00310 
00311     // square root of the diagonal element
00312     new_row[last_num] = sqrt(new_row[last_num]);
00313 }
00314 
00315 
00316 
00326 void chol_solve_as::update_z (
00327         const problem_parameters& ppar, 
00328         const double *iHg,
00329         const int nW, 
00330         const int *W, 
00331         const double *x)
00332 {
00333     int ic_num = nW-1; // index of added constraint in W
00334     // update lagrange multipliers
00335     int zind = ppar.N*SMPC_NUM_STATE_VAR + ic_num;
00336     // sn
00337     double zn = -iHg[W[ic_num]] - x[W[ic_num]*3];
00338 
00339     int i;
00340     int first_nz_el = W[ic_num]/2 * SMPC_NUM_STATE_VAR;
00341 
00342     // zn
00343     for (i = 0; i < first_nz_el; i++)
00344     {
00345         nu[i] = z[i];
00346     }
00347     for (; i < zind; i++)
00348     {
00349         zn -= z[i] * icL[ic_num][i];
00350         nu[i] = z[i];
00351     }
00352     nu[zind] = z[zind] = zn/icL[ic_num][zind];
00353     return;
00354 }
00355 
00356 
00357 
00369 void chol_solve_as::resolve (
00370         const problem_parameters& ppar, 
00371         const double *iHg,
00372         const int nW, 
00373         const int *W, 
00374         const double *x, 
00375         double *dx)
00376 {
00377     int i;
00378 
00379     // backward substitution for icL
00380     for (i = nW-1; i >= 0; i--)
00381     {
00382         int last_el_num = i + ppar.N*SMPC_NUM_STATE_VAR;
00383         nu[last_el_num] /= icL[i][last_el_num];
00384 
00385         for (int j = last_el_num - 1; j >= W[i]/2 * SMPC_NUM_STATE_VAR; j--)
00386         {
00387             nu[j] -= nu[last_el_num] * icL[i][j];
00388         }
00389     }
00390     // backward substitution for ecL
00391     ecL.solve_backward(ppar.N, nu);
00392 
00393 
00394     // E' * nu
00395     E.form_ETx (ppar, nu, dx);
00396 
00397     // dx = -iH*(grad + E'*nu  + A(W,:)'*lambda)
00398     //
00399     // dx = -(x + inv(H) * g + inv(H) * E' * nu)
00400     //            ~~~~~~~~~~            ~~~~~~~
00401     // dx   -(x +  iHg       + inv(H) *   dx   ) 
00402     double i2Q[3] = {ppar.i2Q[0], ppar.i2Q[1], ppar.i2Q[2]};
00403 
00404     for (i = 0; i < ppar.N*SMPC_NUM_STATE_VAR; i++)
00405     {
00406         // dx for state variables
00407         dx[i] = -x[i] - i2Q[i%3] * dx[i];
00408     }
00409     for (; i < ppar.N*SMPC_NUM_VAR; i++)
00410     {
00411         // dx for control variables
00412         dx[i] = -x[i] - ppar.i2P * dx[i];
00413     }
00414     for (i = 0; i < 2*ppar.N; i++)
00415     {
00416         // dx for state variables
00417         dx[i*3] -= iHg[i];
00418     }
00419 
00420     // -iH * A(W,:)' * lambda
00421     double *lambda = &nu[ppar.N*SMPC_NUM_STATE_VAR];
00422     for (i = 0; i < nW; i++)
00423     {
00424         dx[W[i]*3] -= i2Q[0] * lambda[i];
00425     }
00426 }
00427 
00428 
00429 
00444 void chol_solve_as::down_resolve(
00445         const problem_parameters& ppar, 
00446         const double *iHg,
00447         const int nW, 
00448         const int *W, 
00449         const int ind_exclude, 
00450         const double *x, 
00451         double *dx)
00452 {
00453     // for each element of z affected by removed constraint
00454     // find a base that stays the same
00455     double z_tmp = 0;
00456     for (int i = nW; i > ind_exclude; i--)
00457     {
00458         int zind = ppar.N*SMPC_NUM_STATE_VAR + i;
00459         double zn = z[zind] * icL[i][zind];
00460         z[zind] = z_tmp;
00461 
00462         for (int j = ppar.N*SMPC_NUM_STATE_VAR + ind_exclude; j < zind; j++)
00463         {
00464             zn += z[j] * icL[i][j];
00465         }
00466         z_tmp = zn;
00467     }
00468     z[ppar.N*SMPC_NUM_STATE_VAR + ind_exclude] = z_tmp;
00469 
00470 
00471     // downdate L
00472     downdate (ppar, nW, ind_exclude, x);
00473 
00474 
00475     // recompute elements of z
00476     for (int i = ind_exclude; i < nW; i++)
00477     {
00478         int zind = ppar.N*SMPC_NUM_STATE_VAR + i;
00479         double zn = z[zind];
00480 
00481         // zn
00482         // start from the first !=0 element
00483         for (int j = ppar.N*SMPC_NUM_STATE_VAR+ind_exclude; j < zind; j++)
00484         {
00485             zn -= z[j] * icL[i][j];
00486         }
00487         z[zind] = zn/icL[i][zind];
00488     }
00489 
00490     // copy z to nu
00491     for (int i = 0; i < ppar.N*SMPC_NUM_STATE_VAR + nW; i++)
00492     {
00493         nu[i] = z[i];
00494     }
00495 
00496 
00497     resolve (ppar, iHg, nW, W, x, dx);
00498 }
00499 
00500 
00501 
00506 double * chol_solve_as::get_lambda(const problem_parameters& ppar)
00507 {
00508     return(&nu[SMPC_NUM_STATE_VAR*ppar.N]);
00509 }
00510 
00511 
00512 
00513 
00522 void chol_solve_as::downdate(
00523         const problem_parameters& ppar, 
00524         const int nW, 
00525         const int ind_exclude, 
00526         const double *x)
00527 {
00528     // Shuffle memory pointers to avoid copying of the data.
00529     double * downdate_row = icL[ind_exclude];
00530     for (int i = ind_exclude + 1; i < nW + 1; i++)
00531     {
00532         icL[i-1] = icL[i];
00533     }
00534     icL[nW] = downdate_row;
00535 
00536 
00537     for (int i = ind_exclude; i < nW; i++)
00538     {
00539         int el_index = SMPC_NUM_STATE_VAR*ppar.N + i;
00540         double *cur_el = &icL[i][el_index];
00541         double x1 = cur_el[0];
00542         double x2 = cur_el[1];
00543         double cosT, sinT;
00544 
00545 
00546         // Givens rotation matrix
00547         if (abs(x2) >= abs(x1))
00548         {
00549             double t = x1/x2;
00550             sinT = 1/sqrt(1 + t*t);
00551             cosT = sinT*t;
00552         }
00553         else
00554         {
00555             double t = x2/x1;
00556             cosT = 1/sqrt(1 + t*t);
00557             sinT = cosT*t;
00558         }
00559 
00560 
00561         // update elements in the current line
00562         cur_el[0] = cosT*x1 + sinT*x2;
00563         cur_el[1] = 0;
00564 
00565         // change sign if needed (diagonal elements of Cholesky 
00566         // decomposition must be positive)
00567         double sign = copysign(1, cur_el[0]);
00568         cur_el[0] = fabs(cur_el[0]);
00569 
00570         // update the lines below the current one.
00571         for (int j = i + 1; j < nW; j++)
00572         {
00573             x1 = icL[j][el_index];
00574             x2 = icL[j][el_index + 1];
00575 
00576             icL[j][el_index] = sign * (cosT*x1 + sinT*x2);
00577             icL[j][el_index + 1] = -sinT*x1 + cosT*x2;
00578         }
00579     }
00580 }