A sparse MPC solver for walking motion generation (old version).
|
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 }