A sparse MPC solver for walking motion generation (old version).
solver/matrix_ecL_ip.cpp
Go to the documentation of this file.
00001 
00008 /****************************************
00009  * INCLUDES 
00010  ****************************************/
00011 
00012 #include "matrix_ecL_ip.h"
00013 
00014 #include <cmath> // sqrt
00015 
00016 
00017 /****************************************
00018  * FUNCTIONS 
00019  ****************************************/
00020 
00021 //==============================================
00022 // constructors / destructors
00023 
00024 
00025 matrix_ecL_ip::matrix_ecL_ip (const int N)
00026 {
00027     ecL = new double[MATRIX_SIZE_6x6*N + MATRIX_SIZE_6x6*(N-1)]();
00028 
00029     M = new double[MATRIX_SIZE_6x6];
00030     MAT = new double[MATRIX_SIZE_6x6];
00031 }
00032 
00033 
00034 matrix_ecL_ip::~matrix_ecL_ip()
00035 {
00036     if (ecL != NULL)
00037         delete ecL;
00038 
00039     if (M != NULL)
00040         delete M;
00041     if (MAT != NULL)
00042         delete MAT;
00043 }
00044 
00045 //==============================================
00046 
00047 
00048 
00061 void matrix_ecL_ip::form_M (
00062         const double sinA,
00063         const double cosA,
00064         const double *i2Q,
00065         const double* i2hess)
00066 {
00067     /*
00068      * Numbers mark identical elements of M
00069      * 1  5
00070      *  2 
00071      *   3
00072      * 5  4
00073      *     2
00074      *      3
00075      */
00076     // diagonal elements
00077     M[0] = i2hess[0]*cosA*cosA + i2hess[1]*sinA*sinA;
00078     /*M[28] =*/ M[7] = i2Q[1];
00079     /*M[35] =*/ M[14] = i2Q[2];
00080     M[21] = i2hess[0]*sinA*sinA + i2hess[1]*cosA*cosA;
00081 
00082     // symmetric nondiagonal elements
00083     /*M[18] =*/ M[3] = (i2hess[0] - i2hess[1])*cosA*sinA;
00084 }
00085 
00086 
00087 
00097 void matrix_ecL_ip::chol_dec (double *mx)
00098 {
00099     double *curel;
00100 
00101     for (int i = 0; i < MATRIX_SIDE_6x6; i++) // row
00102     {
00103         // non-diagonal elements
00104         for (int j = 0; j < i; j++) // column
00105         {
00106             curel = &mx[j*MATRIX_SIDE_6x6 + i];
00107             for (int k = 0; k < j; k++) // column
00108             {
00109                 *curel -= mx[k*MATRIX_SIDE_6x6 + i] * mx[k*MATRIX_SIDE_6x6 + j];
00110             }
00111 
00112             *curel /= mx[j*MATRIX_SIDE_6x6 + j];
00113         }
00114 
00115         // diagonal element
00116         curel = &mx[i*MATRIX_SIDE_6x6 + i];
00117         for (int k = 0; k < i; k++) // column
00118         {
00119             *curel -= mx[k*MATRIX_SIDE_6x6 + i] * mx[k*MATRIX_SIDE_6x6 + i];
00120         }
00121         *curel = sqrt(*curel);
00122     }
00123 }
00124 
00125 
00126 
00137 void matrix_ecL_ip::form_MBiPB (const double *B, const double i2P, double *result)
00138 {
00139     // diagonal elements
00140     result[0]  = i2P * B[0]*B[0] + M[0];
00141     /*result[28] =*/ result[7]  = i2P * B[1]*B[1] + M[7];
00142     /*result[35] =*/ result[14] = i2P * B[2]*B[2] + M[14];
00143     result[21] = i2P * B[0]*B[0] + M[21];
00144 
00145     // symmetric elements (no need to initialize all of them)
00146     /*result[22] =*/ result[1] = i2P * B[0]*B[1];
00147     /*result[23] =*/ result[2] = i2P * B[0]*B[2];
00148     /*result[29] =*/ result[8] = i2P * B[1]*B[2];
00149     result[3] = M[3];
00150 }
00151 
00152 
00153 
00160 void matrix_ecL_ip::form_MAT (const double A3, const double A6)
00161 {
00162     // 1st column
00163     MAT[0] = M[0];
00164     MAT[1] = A3 * M[7];
00165     MAT[2] = A6 * M[14];
00166     MAT[3] = M[3];
00167 
00168     // 2nd column
00169     MAT[7] = M[7];
00170     MAT[8] = A3 * M[14];
00171 
00172     // 3rd column
00173     MAT[14] = M[14];
00174 
00175     // 4th column
00176     MAT[21] = M[21];
00177     MAT[22] = MAT[1];
00178     MAT[23] = MAT[2];
00179 
00180     // 5th column
00181     MAT[28] = MAT[7];
00182     MAT[29] = MAT[8];
00183 
00184     // 6th column
00185     MAT[35] = MAT[14];
00186 }
00187 
00188 
00189 
00197 void matrix_ecL_ip::form_L_non_diag(const double *ecLp, double *ecLc)
00198 {
00199     /* 
00200      * L(k,k)   * L(k+1,k)' = -M*A'
00201      *
00202      * x         x  x       x  x
00203      * xx        xx x       xx
00204      * xxx     * xxxx   =   xxx
00205      * xxxx      xxxx       x  x
00206      * xxxxx     xxxxx         xx
00207      * xxxxxx    xxxxxx        xxx
00208      */
00209 
00210 
00211     // copy (MAT)' to ecLc
00212     ecLc[0]  = -MAT[0];
00213     ecLc[27] = ecLc[6]  = -MAT[1];
00214     ecLc[33] = ecLc[12] = -MAT[2];
00215 
00216     ecLc[3]  = ecLc[18] = -MAT[3];
00217 
00218     ecLc[28] = ecLc[7]  = -MAT[7];
00219     ecLc[34] = ecLc[13] = -MAT[8];
00220 
00221     ecLc[35] = ecLc[14] = -MAT[14];
00222 
00223     ecLc[21] = -MAT[21];
00224 
00225     // reset elements
00226     ecLc[9]  = ecLc[15] = ecLc[19] = ecLc[20] = ecLc[24] = ecLc[25] =
00227         ecLc[26] = ecLc[30] = ecLc[31] = ecLc[32] = 0;
00228 
00229 
00230     for (int i = 0; i < MATRIX_SIDE_6x6; i++) // row of L(k+1,k)
00231     {
00232         for (int j = 0; j < MATRIX_SIDE_6x6; j++) // element in the row of L(k+1,k)
00233         {
00234             double *curel = &ecLc[j*MATRIX_SIDE_6x6 + i];
00235             for (int k = 0; k < j; k++) // elements in a row of L(k,k)
00236             {
00237                 *curel -= ecLc[k*MATRIX_SIDE_6x6 + i] * ecLp[k*MATRIX_SIDE_6x6 + j];
00238             }
00239 
00240             *curel /= ecLp[j*MATRIX_SIDE_6x6 + j];
00241         }
00242     }
00243 }
00244 
00245 
00254 void matrix_ecL_ip::form_L_diag(double *ecLc)
00255 {
00256     // finish initialization of MBiPB
00257     ecLc[28] = ecLc[7];
00258     ecLc[35] = ecLc[14];
00259     // symmetric elements (no need to initialize all of them)
00260     ecLc[22] = ecLc[1];
00261     ecLc[23] = ecLc[2];
00262     ecLc[29] = ecLc[8];
00263     // reset elements
00264     ecLc[4] = ecLc[5] = ecLc[9] = ecLc[10] = ecLc[11] = 
00265         ecLc[15] = ecLc[16] = ecLc[17] = 0;
00266 
00267 
00268     // chol (L(k+1,k+1))
00269     chol_dec (ecLc);
00270 }
00271 
00272 
00273 
00284 void matrix_ecL_ip::form_AMATMBiPB(const double A3, const double A6, double *result)
00285 {
00286     // 1st,4th column
00287     result[0] += MAT[0] + A3*MAT[1] + A6*MAT[2];
00288     result[1] +=             MAT[1] + A3*MAT[2];
00289     result[2] +=                         MAT[2];
00290     result[3] +=                         MAT[3];
00291 
00292     // 2nd column
00293     // symmetric elements are not initialized
00294     result[7] += MAT[7] +  A3*MAT[8];
00295     result[8] +=              MAT[8];
00296 
00297     // 6th column
00298     result[14] += MAT[14];
00299     result[35] = result[14];
00300 
00301     // 4th column
00302     result[21] += MAT[21] + A3*MAT[1] + A6*MAT[2];
00303     result[22] = result[1];
00304     result[23] = result[2];
00305 
00306     // 5th column
00307     result[28] = result[7];
00308     result[29] = result[8];
00309 
00310     // 6th column
00311     result[35] = result[14];
00312 
00313     // reset elements
00314     result[4] = result[5] = result[9] = result[10] = result[11] = 
00315         result[15] = result[16] = result[17] = 0;
00316 }
00317 
00318 
00319 
00330 void matrix_ecL_ip::form_L_diag (const double *ecLp, double *ecLc)
00331 {
00332     /* - L(k+1,k) * L(k+1,k)' + A*M*A' + MBiPB
00333      * xxxxxx   x  x
00334      *  xxxxx   xx x
00335      *   xxxx   xxxx
00336      * xxxxxx * xxxx
00337      *     xx   xxxxx
00338      *      x   xxxxxx
00339      */
00340     // - L(k+1,k) * L(k+1,k)'
00341     for (int i = 0; i < MATRIX_SIDE_6x6; i++) // row
00342     {
00343         for (int j = 0; j <= i; j++) // column
00344         {
00345             double *curel = &ecLc[i + MATRIX_SIDE_6x6*j];
00346             for (int k = 0; k < MATRIX_SIDE_6x6; k++) // elements in a row
00347             {
00348                 *curel -= ecLp[i + MATRIX_SIDE_6x6*k] * ecLp[j + MATRIX_SIDE_6x6*k];
00349             }
00350         }
00351     }
00352 
00353     // chol (L(k+1,k+1))
00354     chol_dec (ecLc);
00355 }
00356 
00357 
00358 
00365 void matrix_ecL_ip::form (const problem_parameters& ppar, const double *i2hess)
00366 {
00367     int i;
00368     state_parameters stp;
00369 
00370     stp = ppar.spar[0];
00371 
00372     // the first matrix on diagonal
00373     form_M (stp.sin, stp.cos, ppar.i2Q, i2hess);
00374     form_MBiPB (stp.B, ppar.i2P, ecL);
00375     form_L_diag (ecL);
00376 
00377     // offsets
00378     double *ecL_cur = &ecL[MATRIX_SIZE_6x6];
00379     double *ecL_prev = &ecL[0];
00380     for (i = 1; i < ppar.N; i++)
00381     {
00382         stp = ppar.spar[i];
00383 
00384         // form all matrices
00385         form_MAT (stp.A3, stp.A6);
00386         form_L_non_diag (ecL_prev, ecL_cur);
00387 
00388         // update offsets
00389         ecL_cur = &ecL_cur[MATRIX_SIZE_6x6];
00390         ecL_prev = &ecL_prev[MATRIX_SIZE_6x6];
00391 
00392 
00393         i2hess = &i2hess[2];
00394         form_M (stp.sin, stp.cos, ppar.i2Q, i2hess);
00395         form_MBiPB (stp.B, ppar.i2P, ecL_cur);
00396         form_AMATMBiPB(stp.A3, stp.A6, ecL_cur);
00397         form_L_diag(ecL_prev, ecL_cur);
00398 
00399         // update offsets
00400         ecL_cur = &ecL_cur[MATRIX_SIZE_6x6];
00401         ecL_prev = &ecL_prev[MATRIX_SIZE_6x6];
00402     }
00403 }
00404 
00405 
00406 
00414 void matrix_ecL_ip::solve_forward(const int N, double *x)
00415 {
00416     int i,j,k;
00417     double *xc = x; // 6 current elements of x
00418     double *xp; // 6 elements of x computed on the previous iteration
00419     double *ecL_cur = &ecL[0];  // lower triangular matrix lying on the 
00420                                 // diagonal of L
00421     double *ecL_prev;   // upper triangular matrix lying to the left from
00422                         // ecL_cur at the same level of L
00423 
00424 
00425     // compute the first 6 elements using forward substitution
00426     for (j = 0; j < MATRIX_SIDE_6x6; j++) // row
00427     {
00428         for (k = 0; k < j; k++) // column
00429         {
00430             xc[j] -= xc[k]*ecL_cur[j+k*MATRIX_SIDE_6x6];
00431         }
00432         xc[j] /= ecL_cur[j+j*MATRIX_SIDE_6x6];
00433     }
00434 
00435 
00436     for (i = 1; i < N; i++)
00437     {
00438         // switch to the next level of L / next 6 elements
00439         xp = xc;
00440         xc = &xc[SMPC_NUM_STATE_VAR];
00441 
00442         ecL_prev = &ecL_cur[MATRIX_SIZE_6x6];
00443         ecL_cur = &ecL_prev[MATRIX_SIZE_6x6];
00444 
00445         
00446         // update the right part of the equation
00447         for (j = 0; j < MATRIX_SIDE_6x6; j++) // column
00448         {
00449             for (k = 0; k < MATRIX_SIDE_6x6; k++) // row
00450             {
00451                 xc[k] -= xp[j]*ecL_prev[j*MATRIX_SIDE_6x6 + k];
00452             }
00453         }
00454 
00455         // forward substitution
00456         for (j = 0; j < MATRIX_SIDE_6x6; j++) // row
00457         {
00458             for (k = 0; k < j; k++) // column
00459             {
00460                 xc[j] -= xc[k]*ecL_cur[j+k*MATRIX_SIDE_6x6];
00461             }
00462             xc[j] /= ecL_cur[j+j*MATRIX_SIDE_6x6];
00463         }
00464     }
00465 }
00466 
00467 
00474 void matrix_ecL_ip::solve_backward (const int N, double *x)
00475 {
00476     int i,j,k;
00477     double *xc = & x[(N-1)*SMPC_NUM_STATE_VAR]; // current 6 elements of result
00478     double *xp; // 6 elements computed on the previous iteration
00479     
00480     // elements of these matrices accessed as if they were transposed
00481     // lower triangular matrix lying on the diagonal of L
00482     double *ecL_cur = &ecL[2 * (N - 1) * MATRIX_SIZE_6x6];
00483     // upper triangular matrix lying to the right from ecL_cur at the same level of L'
00484     double *ecL_prev; 
00485 
00486 
00487     // compute the last 6 elements using backward substitution
00488     for (j = MATRIX_SIDE_6x6-1; j >= 0; j--) // row
00489     {
00490         for (k = MATRIX_SIDE_6x6-1; k > j; k--) // column
00491         {
00492             xc[j] -= xc[k]*ecL_cur[k+j*MATRIX_SIDE_6x6];
00493         }
00494         xc[j] /= ecL_cur[j+j*MATRIX_SIDE_6x6];
00495     }
00496 
00497 
00498     for (i = N-2; i >= 0 ; i--)
00499     {
00500         xp = xc;
00501         xc = & x[i*SMPC_NUM_STATE_VAR];
00502 
00503         ecL_cur = &ecL[2 * i * MATRIX_SIZE_6x6];
00504         ecL_prev = &ecL_cur[MATRIX_SIZE_6x6];
00505 
00506 
00507         // update the right part of the equation
00508         for (j = 0; j < MATRIX_SIDE_6x6; j++) // row
00509         {
00510             for (k = 0; k < MATRIX_SIDE_6x6; k++) // column
00511             {
00512                 xc[j] -= xp[k]*ecL_prev[j*MATRIX_SIDE_6x6 + k];
00513             }
00514         }
00515 
00516         // backward substitution
00517         for (j = MATRIX_SIDE_6x6-1; j >= 0; j--) // row
00518         {
00519             for (k = MATRIX_SIDE_6x6-1; k > j; k--) // column
00520             {
00521                 xc[j] -= xc[k]*ecL_cur[k+j*MATRIX_SIDE_6x6];
00522             }
00523             xc[j] /= ecL_cur[j+j*MATRIX_SIDE_6x6];
00524         }
00525     }
00526 }