LCPcalc.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                              SOFA :: Framework                              *
00020 *                                                                             *
00021 * Authors: M. Adam, J. Allard, B. Andre, P-J. Bensoussan, S. Cotin, C. Duriez,*
00022 * H. Delingette, F. Falipou, F. Faure, S. Fonteneau, L. Heigeas, C. Mendoza,  *
00023 * M. Nesme, P. Neumann, J-P. de la Plata Alcade, F. Poyer and F. Roy          *
00024 *                                                                             *
00025 * Contact information: contact@sofa-framework.org                             *
00026 ******************************************************************************/
00027 #include <sofa/helper/LCPcalc.h>
00028 #include <vector>
00029 #include <algorithm>
00030 #include <functional>
00031 #include <iostream>
00032 #include <fstream>
00033 #include <cstring>
00034 
00035 namespace sofa
00036 {
00037 
00038 namespace helper
00039 {
00040 
00041 using namespace std;
00042 
00043 
00044 LCP::LCP(unsigned int mxC) : maxConst(mxC), tol(0.00001), numItMax(1000), useInitialF(true), mu(0.0), dim(0)
00045 {
00046     W = new double*[maxConst];
00047     for (int i = 0; i < maxConst; i++)
00048     {
00049         W[i] = new double[maxConst];
00050         memset(W[i], 0, maxConst * sizeof(double));
00051     }
00052     dfree = new double[maxConst];
00053     f = new double[2 * maxConst + 1];
00054 
00055     memset(dfree, 0, maxConst * sizeof(double));
00056     memset(f, 0, (2 * maxConst + 1) * sizeof(double));
00057 }
00058 /*
00059 LCP& LCP::operator=(LCP& lcp)
00060 {
00061     if(this == &lcp) return *this; //self assignment
00062 
00063     if(maxConst != lcp.maxConst)
00064     {
00065         maxConst = lcp.maxConst;
00066 
00067         delete [] dfree;
00068         for (unsigned int i = 0; i < maxConst; i++)
00069         {
00070             delete [] W[i];
00071         }
00072         delete [] W;
00073 
00074         W = new double*[maxConst];
00075         for (unsigned int i = 0; i < maxConst; i++)
00076         {
00077             W[i] = new double[maxConst];
00078         }
00079         dfree = new double[maxConst];
00080         f = new double[2 * maxConst + 1];
00081     }
00082 
00083     dim = lcp.dim;
00084     mu = lcp.mu;
00085     tol = lcp.tol;
00086     numItMax = lcp.numItMax;
00087     useInitialF = lcp.useInitialF;
00088     nbConst = lcp.nbConst;
00089 
00090     for (unsigned int i = 0; i < maxConst; i++)
00091         memcpy(W[i], lcp.W[i], maxConst * sizeof(double));
00092     memcpy(dfree, lcp.dfree, maxConst * sizeof(double));
00093     memcpy(f, lcp.f, maxConst * sizeof(double));
00094 
00095     return *this;
00096 }
00097 */
00098 
00099 LCP::~LCP()
00100 {
00101     delete [] dfree;
00102     for (int i = 0; i < maxConst; i++)
00103     {
00104         delete [] W[i];
00105     }
00106     delete [] W;
00107 }
00108 
00109 
00110 void LCP::reset(void)
00111 {
00112 
00113     for (int i = 0; i < maxConst; i++)
00114     {
00115         memset(W[i], 0, maxConst * sizeof(double));
00116     }
00117 
00118     memset(dfree, 0, maxConst * sizeof(double));
00119 }
00120 
00121 
00122 
00123 //#include "mex.h"
00124 /* Resoud un LCP écrit sous la forme U = q + M.F
00125  * dim : dimension du pb
00126  * res[0..dim-1] = U
00127  * res[dim..2*dim-1] = F
00128  */
00129 int resoudreLCP(int dim, double * q, double ** M, double * res) {
00130 
00131     // déclaration des variables
00132     int compteur;   // compteur de boucle
00133     int compteur2;  // compteur de boucle
00134     double ** mat;  // matrice de travail
00135     int * base;     // base des variables non nulles
00136     int ligPiv;     // ligne du pivot
00137     int colPiv;     // colonne du pivot
00138     double pivot;   // pivot
00139     double min;     // recherche du minimum pour le pivot
00140     double coeff;   // valeur du coefficient de la combinaison linéaire
00141     int boucles;    // compteur du nombre de passages dans la boucle
00142     int result=1;
00143 
00144     // allocation de la mémoire nécessaire
00145     mat = (double **)malloc(dim*sizeof(double *));
00146     for(compteur=0;compteur<dim;compteur++) {
00147         mat[compteur]=(double *)malloc((2*dim+1)*sizeof(double));
00148     }
00149 
00150     base = (int *)malloc(dim*sizeof(int));
00151 
00152     // initialisation de la matrice de travail
00153     for(compteur=0;compteur<dim;compteur++) {
00154         // colonnes correspondantes ?w
00155         for(compteur2=0;compteur2<dim;compteur2++) {
00156             if(compteur2==compteur) {
00157                 mat[compteur][compteur2] = 1;
00158             }
00159             else {
00160                 mat[compteur][compteur2] = 0;
00161             }
00162         }
00163         // colonnes correspondantes ?z
00164         for(;compteur2<2*dim;compteur2++) {
00165             mat[compteur][compteur2] = -(M[compteur][compteur2-dim]);
00166         }
00167         // colonne correspondante ?q
00168         mat[compteur][compteur2] = q[compteur];
00169     }
00170 
00171     /*printf("mat = [");
00172     for(compteur=0;compteur<dim;compteur++) {
00173         for(compteur2=0;compteur2<2*dim+1;compteur2++) {
00174             printf("\t%.2f",mat[compteur][compteur2]);
00175         }
00176         printf("\n");
00177     }
00178     printf("      ]\n\n");*/
00179 
00180     // initialisation de la base
00181     for(compteur=0;compteur<dim;compteur++) {
00182         base[compteur]=compteur;
00183     }
00184 
00185     // initialisation du nombre de boucles
00186     boucles=0;
00187 
00188     // recherche de la ligne du pivot
00189     ligPiv=-1;
00190     min = -EPSILON_LCP;
00191     for(compteur=0;compteur<dim;compteur++) {
00192         if (mat[compteur][2*dim]<min) {
00193             ligPiv=compteur;
00194             min=mat[compteur][2*dim];
00195         }
00196     }
00197 
00198     // tant que tous les q[i] ne sont pas > 0 et qu'on ne boucle pas trop
00199     while ((ligPiv>=0) && (boucles<MAX_BOU)) {
00200         // augmentation du nombre de passages dans cette boucle
00201         boucles++;
00202         // recherche de la colonne du pivot
00203         if (base[ligPiv]<dim) {
00204             // c'est un wi dans la base
00205             colPiv=dim+base[ligPiv];
00206         }
00207         else {
00208             // c'est un zi dans la base
00209             colPiv=base[ligPiv]-dim;
00210         }
00211 
00212         // stockage de la valeur du pivot
00213         pivot=mat[ligPiv][colPiv];
00214         // et son affichage
00215         // printf("pivot=mat[%d][%d]=%f\n\n",ligPiv,colPiv,pivot);
00216 
00217         // si le pivot est nul, le LCP echoue
00218         if (fabs(pivot)<EPSILON_LCP) {
00219             afficheLCP(q,M,dim);
00220             printf("*** Pas de solution *** \n");
00221             boucles=MAX_BOU;
00222             result=0;
00223             return result;
00224         } else {
00225             // division de la ligne du pivot par le pivot
00226             for(compteur=0;compteur<2*dim+1;compteur++) {
00227                 mat[ligPiv][compteur]/=pivot;
00228             }
00229 
00230             // combinaisons linéaires mettant la colonne du pivot a 0
00231             for(compteur=0;compteur<dim;compteur++) {
00232                 if (compteur!=ligPiv) {
00233                     coeff=mat[compteur][colPiv];
00234                     for(compteur2=0;compteur2<2*dim+1;compteur2++) {
00235                         mat[compteur][compteur2]-=coeff*mat[ligPiv][compteur2];
00236                     }
00237                 }
00238             }
00239 
00240             // on rentre dans la base la nouvelle variable
00241             base[ligPiv]=colPiv;
00242 
00243             // recherche de la nouvelle ligne du pivot
00244             ligPiv=-1;
00245             min = -EPSILON_LCP;
00246             for(compteur=0;compteur<dim;compteur++) {
00247                 if (mat[compteur][2*dim]<min) {
00248                     ligPiv=compteur;
00249                     min=mat[compteur][2*dim];
00250                 }
00251             }
00252 
00253         }
00254     }
00255 
00256     // affichage du nb de boucles
00257     //printf("\n %d boucle(s) ",boucles);
00258 
00259     // stockage du resultat
00260     for(compteur=0;compteur<2*dim;compteur++) {
00261         res[compteur]=0;
00262     }
00263     // si on est arrivé à résoudre le pb, seules les variables en base sont non nulles
00264     if (boucles<MAX_BOU) {
00265         for(compteur=0;compteur<dim;compteur++) {
00266             res[base[compteur]]=mat[compteur][2*dim];
00267         }
00268     }
00269 
00270     // libération de la mémoire allouée
00271     for(compteur=0;compteur<dim;compteur++) {
00272         free(mat[compteur]);
00273     }
00274     free(mat);
00275 
00276     free(base);
00277 
00278     return result;
00279 }
00280 
00281 
00282 
00283 
00284 void afficheSyst(double *q,double **M, int *base, double **mat, int dim)
00285 {
00286     int compteur, compteur2;
00287 
00288     // affichage de la matrice du LCP
00289     printf("M = [");
00290     for(compteur=0;compteur<dim;compteur++) {
00291         for(compteur2=0;compteur2<dim;compteur2++) {
00292             printf("\t%.4f",M[compteur][compteur2]);
00293         }
00294         printf("\n");
00295     }
00296     printf("      ]\n\n");
00297 
00298     // affichage de q
00299     printf("q = [");
00300     for(compteur=0;compteur<dim;compteur++) {
00301         printf("\t%.4f\n",q[compteur]);
00302     }
00303     printf("      ]\n\n");
00304 
00305     // afficahge base courante
00306     printf("B = [");
00307     for(compteur=0;compteur<dim;compteur++) {
00308         printf("\t%d",base[compteur]);
00309     }
00310     printf("\t]\n\n");
00311 
00312     // affichage matrice courante
00313     printf("mat = [");
00314     for(compteur=0;compteur<dim;compteur++) {
00315         for(compteur2=0;compteur2<2*dim+1;compteur2++) {
00316             printf("\t%.4f",mat[compteur][compteur2]);
00317         }
00318         printf("\n");
00319     }
00320     printf("      ]\n\n");
00321 }
00322 
00323 /* Siconos-Numerics version 1.2.0, Copyright INRIA 2005-2006.
00324  * Siconos is a program dedicated to modeling, simulation and control
00325  * of non smooth dynamical systems.
00326  * Siconos is a free software; you can redistribute it and/or modify
00327  * it under the terms of the GNU General Public License as published by
00328  * the Free Software Foundation; either version 2 of the License, or
00329  * (at your option) any later version.
00330  * Siconos is distributed in the hope that it will be useful,
00331  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00332  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00333  * GNU General Public License for more details.
00334  *
00335  * You should have received a copy of the GNU General Public License
00336  * along with Siconos; if not, write to the Free Software
00337  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00338  *
00339  * Contact: Vincent ACARY vincent.acary@inrialpes.fr
00340 */
00341 
00390 //void lcp_lexicolemke( int *nn , double *vec , double *q , double *zlem , double *wlem , int *info , int *iparamLCP , double *dparamLCP ){
00391 //void lcp_lexicolemke( int dim , double *vec , double *q , double *zlem )
00392 
00393 int lcp_lexicolemke(int dim, double * q, double ** M, double * res) {
00394 
00395   int i,drive,block,Ifound;
00396   int ic,jc;
00397   int dim2,ITER;
00398   int nobasis;
00399   int itermax,ispeak;
00400 
00401   double qs,z0,zb,dblock;
00402   double pivot, tovip;
00403   double tmp;
00404   int *basis;
00405   static double** A;
00406   //static int dimTest=0;
00407 
00408   dim2 = 2*(dim+1);
00409 
00410  /*input*/
00411 
00412   itermax = dim2;
00413   ispeak  = 0;
00414 
00415   /*output*/
00416 
00417 
00418   basis = (int *)malloc( dim*sizeof(int) );
00419 
00420   /* Allocation */
00421   A = (double **)malloc( dim*sizeof(double*) );
00422   for( ic = 0 ; ic < dim; ++ic )
00423       A[ic] = (double *)malloc( dim2*sizeof(double) );
00424 
00425   for( ic = 0 ; ic < dim; ++ic )
00426     for( jc = 0 ; jc < dim2; ++jc )
00427       A[ic][jc] = 0.0;
00428 
00429   /* construction of A matrix such as
00430    * A = [ q | Id | -d | -M ] with d = (1,...1)
00431    */
00432 
00433   for( ic = 0 ; ic < dim; ++ic )
00434     for( jc = 0 ; jc < dim; ++jc )
00435       A[ic][jc+dim+2] = -M[ic][jc];
00436 
00437   for( ic = 0 ; ic < dim; ++ic ) A[ic][0] = q[ic];
00438 
00439   for( ic = 0 ; ic < dim; ++ic ) A[ic][ic+1 ] =  1.0;
00440   for( ic = 0 ; ic < dim; ++ic ) A[ic][dim+1] = -1.0;
00441 
00442   /* End of construction of A */
00443 
00444   /* STEP 0
00445    * qs = min{ q[i], i=1,...,NC }
00446    */
00447 
00448   qs = q[0];
00449 
00450   for( ic = 1 ; ic < dim ; ++ic ){
00451     if( q[ic] < qs ) qs = q[ic];
00452   }
00453 
00454   Ifound = 0;
00455 
00456   ITER=0;
00457   if( qs >= 0 ){
00458 
00459     /* TRIVIAL CASE
00460      * z = 0 and w = q is solution of LCP(q,M)
00461      */
00462 
00463     for( ic = 0 ; ic < dim; ++ic ){
00464       res[ic] = 0.0;
00465       //wlem[ic] = q[ic];
00466       z0 = 0.0;
00467     }
00468 
00469     Ifound=1;
00470 
00471   }
00472   else{
00473 
00474     for( ic = 0 ; ic < dim  ; ++ic ) basis[ic]=ic+1;
00475 
00476     drive = dim+1;
00477     block = 0;
00478     z0 = A[block][0];
00479 
00480 
00481     /* Start research of argmin lexico */
00482     /* With this first step the covering vector enter in the basis */
00483 
00484     for( ic = 1 ; ic < dim ; ++ic ){
00485       zb = A[ic][0];
00486       if( zb < z0 ){
00487         z0    = zb;
00488         block = ic;
00489       }
00490       else if( zb == z0 ){
00491     for( jc = 0 ; jc < dim ; ++jc ){
00492       dblock = A[block][1+jc] - A[ic][1+jc];
00493       if( dblock < 0 ){
00494           break;
00495       }
00496       else if( dblock > 0 ){
00497           block = ic;
00498           break;
00499       }
00500     }
00501       }
00502     }
00503 
00504     /* Stop research of argmin lexico */
00505 
00506     pivot = A[block][drive];
00507     tovip = 1.0/pivot;
00508 
00509     /* Pivot < block , drive > */
00510 
00511     A[block][drive] = 1;
00512     for( ic = 0       ; ic < drive ; ++ic ) A[block][ic] = A[block][ic]*tovip;
00513     for( ic = drive+1 ; ic < dim2  ; ++ic ) A[block][ic] = A[block][ic]*tovip;
00514 
00515     /* */
00516 
00517     for( ic = 0 ; ic < block ; ++ic ){
00518       tmp = A[ic][drive];
00519       for( jc = 0 ; jc < dim2 ; ++jc ) A[ic][jc] -=  tmp*A[block][jc];
00520     }
00521     for( ic = block+1 ; ic < dim ; ++ic ){
00522       tmp = A[ic][drive];
00523       for( jc = 0 ; jc < dim2 ; ++jc ) A[ic][jc] -=  tmp*A[block][jc];
00524     }
00525 
00526     nobasis = basis[block];
00527     basis[block] = drive;
00528 
00529     while( ITER < itermax && !Ifound ){
00530 
00531       ++ITER;
00532 
00533       if( nobasis < dim + 1 )      drive = nobasis + (dim+1);
00534       else if( nobasis > dim + 1 ) drive = nobasis - (dim+1);
00535 
00536       /* Start research of argmin lexico for minimum ratio test */
00537 
00538       pivot = 1e20;
00539       block = -1;
00540 
00541       for( ic = 0 ; ic < dim ; ++ic ){
00542     zb = A[ic][drive];
00543     if( zb > 0.0 ){
00544       z0 = A[ic][0]/zb;
00545       if( z0 > pivot ) continue;
00546       if( z0 < pivot ){
00547         pivot = z0;
00548         block = ic;
00549       }
00550       else{
00551         for( jc = 1 ; jc < dim+1 ; ++jc ){
00552           dblock = A[block][jc]/pivot - A[ic][jc]/zb;
00553           if( dblock < 0 ) break;
00554           else if( dblock > 0 ){
00555         block = ic;
00556         break;
00557           }
00558         }
00559       }
00560     }
00561       }
00562       if( block == -1 ) break;
00563 
00564       if( basis[block] == dim+1 ) Ifound = 1;
00565 
00566       /* Pivot < block , drive > */
00567 
00568       pivot = A[block][drive];
00569       tovip = 1.0/pivot;
00570       A[block][drive] = 1;
00571 
00572       for( ic = 0       ; ic < drive ; ++ic ) A[block][ic] = A[block][ic]*tovip;
00573       for( ic = drive+1 ; ic < dim2  ; ++ic ) A[block][ic] = A[block][ic]*tovip;
00574 
00575       /* */
00576 
00577       for( ic = 0 ; ic < block ; ++ic ){
00578     tmp = A[ic][drive];
00579     for( jc = 0 ; jc < dim2 ; ++jc ) A[ic][jc] -=  tmp*A[block][jc];
00580       }
00581       for( ic = block+1 ; ic < dim ; ++ic ){
00582     tmp = A[ic][drive];
00583     for( jc = 0 ; jc < dim2 ; ++jc ) A[ic][jc] -=  tmp*A[block][jc];
00584       }
00585 
00586       nobasis = basis[block];
00587       basis[block] = drive;
00588 
00589     }
00590 
00591     for( ic = 0 ; ic < dim; ++ic ){
00592       drive = basis[ic];
00593       if( drive < dim + 1 ){
00594     res[drive-1] = 0.0;
00595     //wlem[drive-1] = A[ic][0];
00596       }
00597       else if( drive > dim + 1 ){
00598     res[drive-dim-2] = A[ic][0];
00599     //wlem[drive-dim-2] = 0.0;
00600       }
00601     }
00602 
00603   }
00604 
00605 
00606 
00607 //  if(Ifound) *info = 0;
00608  // else *info = 1;
00609 
00610   free(basis);
00611 
00612 
00613   for( i = 0 ; i < dim ; ++i ) free(A[i]);
00614   free(A);
00615 
00616 
00617 
00618   // for compatibility with previous LCP solver
00619   for( i = 0 ; i < dim ; ++i )
00620       res[i+dim] = res[i];
00621 
00622 
00623   if (Ifound) return 1;
00624 
00625   printf("\n Problem with this LCP :\n");
00626   afficheLCP(q,M,dim);
00627   return 0;
00628 
00629 }
00630 
00631 /******************************** WITHOUT ALLOCATION of A ************************************/
00632 int lcp_lexicolemke(int dim, double * q, double ** M, double **A, double * res) {
00633 
00634   int i,drive,block,Ifound;
00635   int ic,jc;
00636   int dim2,ITER;
00637   int nobasis;
00638   int itermax,ispeak;
00639 
00640   double qs,z0,zb,dblock;
00641   double pivot, tovip;
00642   double tmp;
00643   int *basis;
00644 
00645   dim2 = 2*(dim+1);
00646 
00647  /*input*/
00648 
00649   itermax = dim2;
00650   ispeak  = 0;
00651 
00652   /*output*/
00653 
00654   basis = (int *)malloc( dim*sizeof(int) );
00655 
00656   for( ic = 0 ; ic < dim; ++ic )
00657     for( jc = 0 ; jc < dim2; ++jc )
00658       A[ic][jc] = 0.0;
00659 
00660   /* construction of A matrix such as
00661    * A = [ q | Id | -d | -M ] with d = (1,...1)
00662    */
00663 
00664   for( ic = 0 ; ic < dim; ++ic )
00665     for( jc = 0 ; jc < dim; ++jc )
00666       A[ic][jc+dim+2] = -M[ic][jc];
00667 
00668   for( ic = 0 ; ic < dim; ++ic ) A[ic][0] = q[ic];
00669 
00670   for( ic = 0 ; ic < dim; ++ic ) A[ic][ic+1 ] =  1.0;
00671   for( ic = 0 ; ic < dim; ++ic ) A[ic][dim+1] = -1.0;
00672 
00673   /* End of construction of A */
00674 
00675   /* STEP 0
00676    * qs = min{ q[i], i=1,...,NC }
00677    */
00678 
00679   qs = q[0];
00680 
00681   for( ic = 1 ; ic < dim ; ++ic ){
00682     if( q[ic] < qs ) qs = q[ic];
00683   }
00684 
00685   Ifound = 0;
00686 
00687   ITER=0;
00688   if( qs >= 0 ){
00689 
00690     /* TRIVIAL CASE
00691      * z = 0 and w = q is solution of LCP(q,M)
00692      */
00693 
00694     for( ic = 0 ; ic < dim; ++ic ){
00695       res[ic] = 0.0;
00696       //wlem[ic] = q[ic];
00697       z0 = 0.0;
00698     }
00699 
00700     Ifound=1;
00701 
00702   }
00703   else{
00704 
00705     for( ic = 0 ; ic < dim  ; ++ic ) basis[ic]=ic+1;
00706 
00707     drive = dim+1;
00708     block = 0;
00709     z0 = A[block][0];
00710 
00711 
00712     /* Start research of argmin lexico */
00713     /* With this first step the covering vector enter in the basis */
00714 
00715     for( ic = 1 ; ic < dim ; ++ic ){
00716       zb = A[ic][0];
00717       if( zb < z0 ){
00718         z0    = zb;
00719         block = ic;
00720       }
00721       else if( zb == z0 ){
00722     for( jc = 0 ; jc < dim ; ++jc ){
00723       dblock = A[block][1+jc] - A[ic][1+jc];
00724       if( dblock < 0 ){
00725           break;
00726       }
00727       else if( dblock > 0 ){
00728           block = ic;
00729           break;
00730       }
00731     }
00732       }
00733     }
00734 
00735     /* Stop research of argmin lexico */
00736 
00737     pivot = A[block][drive];
00738     tovip = 1.0/pivot;
00739 
00740     /* Pivot < block , drive > */
00741 
00742     A[block][drive] = 1;
00743     for( ic = 0       ; ic < drive ; ++ic ) A[block][ic] = A[block][ic]*tovip;
00744     for( ic = drive+1 ; ic < dim2  ; ++ic ) A[block][ic] = A[block][ic]*tovip;
00745 
00746     /* */
00747 
00748     for( ic = 0 ; ic < block ; ++ic ){
00749       tmp = A[ic][drive];
00750       for( jc = 0 ; jc < dim2 ; ++jc ) A[ic][jc] -=  tmp*A[block][jc];
00751     }
00752     for( ic = block+1 ; ic < dim ; ++ic ){
00753       tmp = A[ic][drive];
00754       for( jc = 0 ; jc < dim2 ; ++jc ) A[ic][jc] -=  tmp*A[block][jc];
00755     }
00756 
00757     nobasis = basis[block];
00758     basis[block] = drive;
00759 
00760     while( ITER < itermax && !Ifound ){
00761 
00762       ++ITER;
00763 
00764       if( nobasis < dim + 1 )      drive = nobasis + (dim+1);
00765       else if( nobasis > dim + 1 ) drive = nobasis - (dim+1);
00766 
00767       /* Start research of argmin lexico for minimum ratio test */
00768 
00769       pivot = 1e20;
00770       block = -1;
00771 
00772       for( ic = 0 ; ic < dim ; ++ic ){
00773     zb = A[ic][drive];
00774     if( zb > 0.0 ){
00775       z0 = A[ic][0]/zb;
00776       if( z0 > pivot ) continue;
00777       if( z0 < pivot ){
00778         pivot = z0;
00779         block = ic;
00780       }
00781       else{
00782         for( jc = 1 ; jc < dim+1 ; ++jc ){
00783           dblock = A[block][jc]/pivot - A[ic][jc]/zb;
00784           if( dblock < 0 ) break;
00785           else if( dblock > 0 ){
00786         block = ic;
00787         break;
00788           }
00789         }
00790       }
00791     }
00792       }
00793       if( block == -1 ) break;
00794 
00795       if( basis[block] == dim+1 ) Ifound = 1;
00796 
00797       /* Pivot < block , drive > */
00798 
00799       pivot = A[block][drive];
00800       tovip = 1.0/pivot;
00801       A[block][drive] = 1;
00802 
00803       for( ic = 0       ; ic < drive ; ++ic ) A[block][ic] = A[block][ic]*tovip;
00804       for( ic = drive+1 ; ic < dim2  ; ++ic ) A[block][ic] = A[block][ic]*tovip;
00805 
00806       /* */
00807 
00808       for( ic = 0 ; ic < block ; ++ic ){
00809     tmp = A[ic][drive];
00810     for( jc = 0 ; jc < dim2 ; ++jc ) A[ic][jc] -=  tmp*A[block][jc];
00811       }
00812       for( ic = block+1 ; ic < dim ; ++ic ){
00813     tmp = A[ic][drive];
00814     for( jc = 0 ; jc < dim2 ; ++jc ) A[ic][jc] -=  tmp*A[block][jc];
00815       }
00816 
00817       nobasis = basis[block];
00818       basis[block] = drive;
00819 
00820     }
00821 
00822     for( ic = 0 ; ic < dim; ++ic ){
00823       drive = basis[ic];
00824       if( drive < dim + 1 ){
00825     res[drive-1] = 0.0;
00826     //wlem[drive-1] = A[ic][0];
00827       }
00828       else if( drive > dim + 1 ){
00829     res[drive-dim-2] = A[ic][0];
00830     //wlem[drive-dim-2] = 0.0;
00831       }
00832     }
00833 
00834   }
00835 
00836 
00837 
00838 //  if(Ifound) *info = 0;
00839  // else *info = 1;
00840 
00841   free(basis);
00842 
00843   /*
00844   for( i = 0 ; i < dim ; ++i ) free(A[i]);
00845   free(A);
00846   */
00847 
00848 
00849   // for compatibility with previous LCP solver
00850   for( i = 0 ; i < dim ; ++i )
00851       res[i+dim] = res[i];
00852 
00853 
00854   if (Ifound) return 1;
00855 
00856   printf("\n Problem with this LCP :\n");
00857 //  afficheLCP(q,M,dim);
00858   return 0;
00859 
00860 }
00861 /********************************************************************************************/
00862 void afficheLCP(double *q, double **M, int dim)
00863 {
00864     int compteur, compteur2;
00865     // affichage de la matrice du LCP
00866     printf("M = [");
00867     for(compteur=0;compteur<dim;compteur++) {
00868         for(compteur2=0;compteur2<dim;compteur2++) {
00869             printf("\t%.4f",M[compteur][compteur2]);
00870         }
00871         printf("\n");
00872     }
00873     printf("      ];\n\n");
00874 
00875     // affichage de q
00876     printf("q = [");
00877     for(compteur=0;compteur<dim;compteur++) {
00878         printf("\t%.4f\n",q[compteur]);
00879     }
00880     printf("      ]\n\n");
00881 }
00882 
00883 /********************************************************************************************/
00884 void afficheLCP(double *q, double **M, double *f, int dim)
00885 {
00886     int compteur, compteur2;
00887     // affichage de la matrice du LCP
00888     printf("\n M = [");
00889     for(compteur=0;compteur<dim;compteur++) {
00890         for(compteur2=0;compteur2<dim;compteur2++) {
00891             printf("\t%.5f",M[compteur][compteur2]);
00892         }
00893         printf("\n");
00894     }
00895     printf("      ];\n\n");
00896 
00897     // affichage de q
00898     printf("q = [");
00899     for(compteur=0;compteur<dim;compteur++) {
00900         printf("\t%.5f\n",q[compteur]);
00901     }
00902     printf("      ];\n\n");
00903 
00904     // affichage de f
00905     printf("f = [");
00906     for(compteur=0;compteur<dim;compteur++) {
00907         printf("\t%.5f\n",f[compteur]);
00908     }
00909     printf("      ];\n\n");
00910 
00911 }
00912 
00913 
00914 /********************************************************************************************/
00915 // special class to obtain the inverse of a symetric matrix 3x3
00916 void LocalBlock33::compute(double &w11, double &w12, double &w13, double &w22, double &w23, double &w33)
00917 {
00918     w[0]=w11; w[1]=w12; w[2] = w13; w[3]=w22; w[4]=w23; w[5]=w33;
00919     det = w11*w22*w33-w11*w23*w23-w12*w12*w33+2*w12*w13*w23-w13*w13*w22;
00920     wInv[0] = (w22*w33-w23*w23)/det;
00921     wInv[1] = -(w12*w33-w13*w23)/det;
00922     wInv[2] = (w12*w23-w13*w22)/det;
00923     wInv[3] = (w11*w33-w13*w13)/det;
00924     wInv[4] = -(w11*w23-w12*w13)/det;
00925     wInv[5] = (w11*w22-w12*w12)/det;
00926     computed=true;
00927 }
00928 
00929 void LocalBlock33::stickState(double &dn, double &dt, double &ds, double &fn, double &ft, double &fs)
00930 {
00931     fn = -wInv[0]*dn - wInv[1]*dt - wInv[2]*ds;
00932     ft = -wInv[1]*dn - wInv[3]*dt - wInv[4]*ds;
00933     fs = -wInv[2]*dn - wInv[4]*dt - wInv[5]*ds;
00934 }
00935 
00936 
00937 
00938 
00939 void LocalBlock33::slipState(double &mu, double &dn, double &dt, double &ds, double &fn, double &ft, double &fs)
00940 {
00941     double d[3];
00942     double normFt;
00943 
00944     for (int iteration=0; iteration<10000; iteration++)
00945     {
00946         // we set the previous value of the force
00947         f_1[0]=fn; f_1[1]=ft; f_1[2]=fs;
00948 
00949         // evaluation of the current normal position
00950         d[0] = w[0]*fn + w[1]*ft + w[2]*fs + dn;
00951         // evaluation of the new contact force
00952         fn -= d[0]/w[0];
00953 
00954         // evaluation of the current tangent positions
00955         d[1] = w[1]*fn + w[3]*ft + w[4]*fs + dt;
00956         d[2] = w[2]*fn + w[4]*ft + w[5]*fs + ds;
00957 
00958         // envaluation of the new fricton forces
00959         ft -= 2*d[1]/(w[3]+w[5]);
00960         fs -= 2*d[2]/(w[3]+w[5]);
00961         normFt=sqrt(ft*ft+fs*fs);
00962         ft *=mu*fn/normFt;
00963         fs *=mu*fn/normFt;
00964 
00965 
00966         if (normError(fn,ft,fs,f_1[0],f_1[1],f_1[2]) < 0.000001)
00967         {
00968             dn=d[0]; dt=d[1]; ds=d[2];
00969             //mexPrintf("\n convergence of slipState after %d iteration(s)",iteration);
00970             return;
00971         }
00972 
00973     }
00974 //  mexPrintf("\n No convergence in slipState function: error =%f",normError(fn,ft,fs,f_1[0],f_1[1],f_1[2]));
00975 //  printf("\n No convergence in slipState function");
00976 
00977 }
00978 
00979 void LocalBlock33::GS_State(double &mu, double &dn, double &dt, double &ds, double &fn, double &ft, double &fs)
00980 {
00981     double d[3];
00982     double normFt;
00983     f_1[0]=fn; f_1[1]=ft; f_1[2]=fs;
00984 
00985     // evaluation of the current normal position
00986     d[0] = w[0]*fn + w[1]*ft + w[2]*fs + dn;
00987     // evaluation of the new contact force
00988     fn -= d[0]/w[0];
00989 
00990     if (fn < 0){
00991         fn=0; ft=0; fs=0;
00992         return;
00993     }
00994 
00995 
00996     // evaluation of the current tangent positions
00997     d[1] = w[1]*fn + w[3]*ft + w[4]*fs + dt;
00998     d[2] = w[2]*fn + w[4]*ft + w[5]*fs + ds;
00999 
01000     // envaluation of the new fricton forces
01001     ft -= 2*d[1]/(w[3]+w[5]);
01002     fs -= 2*d[2]/(w[3]+w[5]);
01003 
01004     normFt=sqrt(ft*ft+fs*fs);
01005 
01006     if (normFt > mu*fn){
01007         ft *=mu*fn/normFt;
01008         fs *=mu*fn/normFt;
01009     }
01010 
01011     dn += w[0]*fn + w[1]*ft + w[2]*fs;
01012     dt += w[1]*fn + w[3]*ft + w[4]*fs;
01013     ds += w[2]*fn + w[4]*ft + w[5]*fs;
01014 
01015 }
01016 
01018  // // test sur LocalBlock33 // //
01020  // LocalBlock33 *Z;
01021  // Z = new LocalBlock33(W[0][0],W[0][1],W[0][2],W[1][1],W[1][2],W[2][2]);
01022  // Z->stickState(dfree[0],dfree[1],dfree[2],f[0],f[1],f[2]);
01023 
01024  // if (nlhs>0)
01025  // {
01026     //double *prF;
01027     //plhs[0]=mxCreateDoubleMatrix(3,1,mxREAL);
01028     //prF = mxGetPr(plhs[0]);
01029     //for(i=0; i<3; i++)
01030     //  prF[i] = f[i];
01031  // }
01032 
01033 
01034 /********************************************************************************************/
01035 
01037 // sorted list of the contact (depending on interpenetration)
01039 
01040 typedef struct{ double value; int index;} listElem;
01041 struct listSortAscending {
01042     bool operator()(const listElem& e1, const listElem& e2){
01043         return e1.value < e2.value;
01044     }
01045 };
01046 
01047 int nlcp_gaussseidel(int dim, double *dfree, double**W, double *f, double mu, double tol, int numItMax, bool useInitialF)
01048 {
01049     double test = dim/3;
01050     double zero = 0.0;
01051     int numContacts =  (int) floor(test);
01052     test = dim/3 - numContacts;
01053 
01054     if (test>0.01){
01055         printf("\n WARNING dim should be dividable by 3 in nlcp_gaussseidel");
01056         return 0;
01057     }
01058     // iterators
01059     int it,c1,i;
01060 
01061     // memory allocation of vector d
01062     double *d;
01063     d = (double*)malloc(dim*sizeof(double));
01064     // put the vector force to zero
01065     if (!useInitialF)
01066         memset(f, 0, dim*sizeof(double));
01067 
01068     // previous value of the force and the displacment
01069     double f_1[3];
01070     double d_1[3];
01071 
01072     // allocation of the inverted system 3x3
01073     LocalBlock33 **W33;
01074     W33 = (LocalBlock33 **) malloc (dim*sizeof(LocalBlock33));
01075     for (c1=0; c1<numContacts; c1++)
01076         W33[c1] = new LocalBlock33();
01077     /*
01078     std::vector<listElem> sortedList;
01079     listElem buf;
01080     sortedList.clear();
01081     for (c1=0; c1<numContacts; c1++)
01082     {
01083         buf.value = dfree[3*c1];
01084         buf.index = c1;
01085         sortedList.push_back(buf);
01086     }
01087     */
01088 
01090     // Beginning of iterative computations
01092     double error = 0;
01093     double dn, dt, ds, fn, ft, fs;
01094 
01095     for (it=0; it<numItMax; it++)
01096     {
01097         error =0;
01098         for (c1=0; c1<numContacts; c1++)
01099         {
01100             // index of contact
01101             int index1 = c1;
01102 
01103             // put the previous value of the contact force in a buffer and put the current value to 0
01104             f_1[0] = f[3*index1]; f_1[1] = f[3*index1+1]; f_1[2] = f[3*index1+2];
01105             set3Dof(f,index1,zero,zero,zero); //        f[3*index] = 0.0; f[3*index+1] = 0.0; f[3*index+2] = 0.0;
01106 
01107             // computation of actual d due to contribution of other contacts
01108             dn=dfree[3*index1];dt=dfree[3*index1+1]; ds=dfree[3*index1+2];
01109             for (i=0; i<dim; i++){
01110                 dn += W[3*index1  ][i]*f[i];
01111                 dt += W[3*index1+1][i]*f[i];
01112                 ds += W[3*index1+2][i]*f[i];
01113             }
01114             d_1[0] = dn + W[3*index1  ][3*index1  ]*f_1[0]+W[3*index1  ][3*index1+1]*f_1[1]+W[3*index1  ][3*index1+2]*f_1[2];
01115             d_1[1] = dt + W[3*index1+1][3*index1  ]*f_1[0]+W[3*index1+1][3*index1+1]*f_1[1]+W[3*index1+1][3*index1+2]*f_1[2];
01116             d_1[2] = ds + W[3*index1+2][3*index1  ]*f_1[0]+W[3*index1+2][3*index1+1]*f_1[1]+W[3*index1+2][3*index1+2]*f_1[2];
01117 
01118             if(W33[index1]->computed==false)
01119             {
01120                 W33[index1]->compute(W[3*index1][3*index1],W[3*index1][3*index1+1],W[3*index1][3*index1+2],
01121                                             W[3*index1+1][3*index1+1], W[3*index1+1][3*index1+2],W[3*index1+2][3*index1+2]);
01122             }
01123 
01124 
01125             fn=f_1[0]; ft=f_1[1]; fs=f_1[2];
01126             W33[index1]->GS_State(mu,dn,dt,ds,fn,ft,fs);
01127             error += absError(dn,dt,ds,d_1[0],d_1[1],d_1[2]);
01128 
01129 
01130             set3Dof(f,index1,fn,ft,fs);
01131 
01132         }
01133 
01134         if (error < tol){
01135             free(d);
01136             for (int i = 0; i < numContacts; i++)
01137                 delete W33[i];
01138             free(W33);
01139             //printf("Convergence after %d iteration(s) with tolerance : %f and error : %f with dim : %d\n",it, tol, error, dim);
01140             //afficheLCP(dfree,W,f,dim);
01141             return 1;
01142         }
01143     }
01144     free(d);
01145     for (int i = 0; i < numContacts; i++)
01146         delete W33[i];
01147     free(W33);
01148 
01149     //printf("\n No convergence in nlcp_gaussseidel function : error =%f after %d iterations", error, it);
01150     //afficheLCP(dfree,W,f,dim);
01151     return 0;
01152 
01153 }
01154 
01155 int nlcp_gaussseidelTimed(int dim, double *dfree, double**W, double *f, double mu, double tol, int numItMax, bool useInitialF, double timeout)
01156 {
01157     double test = dim/3;
01158     double zero = 0.0;
01159     int numContacts =  (int) floor(test);
01160     test = dim/3 - numContacts;
01161 
01162     ctime_t t0 = CTime::getTime()/CTime::getTicksPerSec();
01163 
01164     if (test>0.01){
01165         printf("\n WARNING dim should be dividable by 3 in nlcp_gaussseidel");
01166         return 0;
01167     }
01168     // iterators
01169     int it,c1,i;
01170 
01171     // memory allocation of vector d
01172     double *d;
01173     d = (double*)malloc(dim*sizeof(double));
01174     // put the vector force to zero
01175     if (!useInitialF)
01176         memset(f, 0, dim*sizeof(double));
01177 
01178     // previous value of the force and the displacment
01179     double f_1[3];
01180     double d_1[3];
01181 
01182     // allocation of the inverted system 3x3
01183     LocalBlock33 **W33;
01184     W33 = (LocalBlock33 **) malloc (dim*sizeof(LocalBlock33));
01185     for (c1=0; c1<numContacts; c1++)
01186         W33[c1] = new LocalBlock33();
01187     /*
01188     std::vector<listElem> sortedList;
01189     listElem buf;
01190     sortedList.clear();
01191     for (c1=0; c1<numContacts; c1++)
01192     {
01193         buf.value = dfree[3*c1];
01194         buf.index = c1;
01195         sortedList.push_back(buf);
01196     }
01197     */
01198 
01200     // Beginning of iterative computations
01202     double error = 0;
01203     double dn, dt, ds, fn, ft, fs;
01204 
01205     for (it=0; it<numItMax; it++)
01206     {
01207         error =0;
01208         for (c1=0; c1<numContacts; c1++)
01209         {
01210             // index of contact
01211             int index1 = c1;
01212 
01213             // put the previous value of the contact force in a buffer and put the current value to 0
01214             f_1[0] = f[3*index1]; f_1[1] = f[3*index1+1]; f_1[2] = f[3*index1+2];
01215             set3Dof(f,index1,zero,zero,zero); //        f[3*index] = 0.0; f[3*index+1] = 0.0; f[3*index+2] = 0.0;
01216 
01217             // computation of actual d due to contribution of other contacts
01218             dn=dfree[3*index1];dt=dfree[3*index1+1]; ds=dfree[3*index1+2];
01219             for (i=0; i<dim; i++){
01220                 dn += W[3*index1  ][i]*f[i];
01221                 dt += W[3*index1+1][i]*f[i];
01222                 ds += W[3*index1+2][i]*f[i];
01223             }
01224             d_1[0] = dn + W[3*index1  ][3*index1  ]*f_1[0]+W[3*index1  ][3*index1+1]*f_1[1]+W[3*index1  ][3*index1+2]*f_1[2];
01225             d_1[1] = dt + W[3*index1+1][3*index1  ]*f_1[0]+W[3*index1+1][3*index1+1]*f_1[1]+W[3*index1+1][3*index1+2]*f_1[2];
01226             d_1[2] = ds + W[3*index1+2][3*index1  ]*f_1[0]+W[3*index1+2][3*index1+1]*f_1[1]+W[3*index1+2][3*index1+2]*f_1[2];
01227 
01228             if(W33[index1]->computed==false)
01229             {
01230                 W33[index1]->compute(W[3*index1][3*index1],W[3*index1][3*index1+1],W[3*index1][3*index1+2],
01231                                             W[3*index1+1][3*index1+1], W[3*index1+1][3*index1+2],W[3*index1+2][3*index1+2]);
01232             }
01233 
01234 
01235             fn=f_1[0]; ft=f_1[1]; fs=f_1[2];
01236             W33[index1]->GS_State(mu,dn,dt,ds,fn,ft,fs);
01237             error += absError(dn,dt,ds,d_1[0],d_1[1],d_1[2]);
01238 
01239 
01240             set3Dof(f,index1,fn,ft,fs);
01241 
01242             ctime_t t1 = CTime::getTime()/CTime::getTicksPerSec();
01243             if((t1-t0) > timeout)
01244             {
01245                 free(d);
01246                 for (int i = 0; i < numContacts; i++)
01247                     delete W33[i];
01248                 free(W33);
01249                 //printf("Convergence after %d iteration(s) with tolerance : %f and error : %f with dim : %d\n",it, tol, error, dim);
01250                 //afficheLCP(dfree,W,f,dim);
01251                 return 1;
01252             }
01253         }
01254 
01255         if (error < tol){
01256             free(d);
01257             for (int i = 0; i < numContacts; i++)
01258                 delete W33[i];
01259             free(W33);
01260             //printf("Convergence after %d iteration(s) with tolerance : %f and error : %f with dim : %d\n",it, tol, error, dim);
01261             //afficheLCP(dfree,W,f,dim);
01262             return 1;
01263         }
01264     }
01265     free(d);
01266     for (int i = 0; i < numContacts; i++)
01267         delete W33[i];
01268     free(W33);
01269 
01270     //printf("\n No convergence in nlcp_gaussseidel function : error =%f after %d iterations", error, it);
01271     //afficheLCP(dfree,W,f,dim);
01272     return 0;
01273 
01274 }
01275 
01276 
01277 /* Resoud un LCP écrit sous la forme U = q + M.F
01278  * dim : dimension du pb
01279  * res[0..dim-1] = U
01280  * res[dim..2*dim-1] = F
01281  */
01282 void gaussSeidelLCP1(int dim, FemClipsReal * q, FemClipsReal ** M, FemClipsReal * res, double tol, int numItMax) {
01283     int compteur;   // compteur de boucle
01284     int compteur2, compteur3;   // compteur de boucle
01285 
01286     double f_1;
01287     double error=0.0;
01288 
01289     for (compteur=0; compteur<numItMax; compteur++)
01290     {
01291 
01292         error=0.0;
01293         for (compteur2=0; compteur2<dim; compteur2++)
01294         {
01295             //res[compteur2]=(FemClipsReal)0.0;
01296             res[compteur2]=q[compteur2];
01297             for (compteur3=0; compteur3<dim; compteur3++)
01298             {
01299                 res[compteur2]+=M[compteur2][compteur3]* res[dim+compteur3]/* + q[compteur2]*/;
01300             }
01301             res[compteur2] -= M[compteur2][compteur2]* res[dim+compteur2];
01302             f_1 = res[dim+compteur2];
01303 
01304             if (res[compteur2]<0)
01305             {
01306                 res[dim+compteur2]=-res[compteur2]/M[compteur2][compteur2];
01307             }
01308             else
01309             {
01310                 res[dim+compteur2]=(FemClipsReal)0.0;
01311             }
01312 
01313             error +=fabs( M[compteur2][compteur2] * (res[dim+compteur2] - f_1) );
01314 
01315 
01316         }
01317 
01318         if (error < tol)
01319         {
01320         //  std::cout << "convergence in gaussSeidelLCP1 with " << compteur << " iterations\n";
01321             break;
01322         }
01323 
01324     }
01325 
01326     for (compteur=0; compteur<dim; compteur++)
01327         res[compteur] = res[compteur+dim];
01328 
01329     if (error >= tol)
01330     {
01331         std::cout << "No convergence in gaussSeidelLCP1 : error = " << error << std::endl;
01332     //  afficheLCP(q, M, res, dim);
01333     }
01334 }
01335 
01336 } // namespace helper
01337 
01338 } // namespace sofa

Generated on Sun Nov 23 02:29:30 2008 for Sofa by  doxygen 1.5.7.1