BTDLinearSolver.h

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 :: Modules                               *
00020 *                                                                             *
00021 * Authors: The SOFA Team and external contributors (see Authors.txt)          *
00022 *                                                                             *
00023 * Contact information: contact@sofa-framework.org                             *
00024 ******************************************************************************/
00025 #ifndef SOFA_COMPONENT_LINEARSOLVER_BTDLINEARSOLVER_H
00026 #define SOFA_COMPONENT_LINEARSOLVER_BTDLINEARSOLVER_H
00027 
00028 #include <sofa/core/componentmodel/behavior/LinearSolver.h>
00029 #include <sofa/simulation/common/MatrixLinearSolver.h>
00030 #include <sofa/component/linearsolver/SparseMatrix.h>
00031 #include <sofa/component/linearsolver/FullMatrix.h>
00032 #include <math.h>
00033 
00034 namespace sofa
00035 {
00036 
00037 namespace component
00038 {
00039 
00040 namespace linearsolver
00041 {
00042 
00050 template<class Matrix, class Vector>
00051 class BTDLinearSolver : public sofa::simulation::MatrixLinearSolver<Matrix,Vector>, public virtual sofa::core::objectmodel::BaseObject
00052 {
00053 public:
00054     Data<bool> f_verbose;
00055     Data<bool> problem;
00056     
00057     typedef typename Matrix::SubMatrixType SubMatrix;
00058     
00059     //helper::vector<SubMatrix> alpha;
00060     helper::vector<SubMatrix> alpha_inv;
00061     helper::vector<SubMatrix> lambda;
00062     helper::vector<SubMatrix> B;
00063     typename Matrix::InvMatrixType Minv;
00064     helper::vector<int> nBlockComputedMinv;
00065     Vector Y;
00066 
00067     Data<int> f_blockSize;
00068 
00069     BTDLinearSolver()
00070     : f_verbose( initData(&f_verbose,false,"verbose","Dump system state at each iteration") )
00071     , problem(initData(&problem, false,"showProblem", "Suppress the computation of all elements of the inverse") ) 
00072     , f_blockSize( initData(&f_blockSize,6,"blockSize","dimension of the blocks in the matrix") )
00073     {
00074     }
00075     
00115     template<class T>
00116     void invert(SubMatrix& Inv, const T& m)
00117     {
00118     SubMatrix M;
00119     M = m;
00120         // Check for diagonal matrices
00121         unsigned int i0 = 0;
00122     const unsigned int n = M.Nrows();
00123     Inv.resize(n,n);
00124     while (i0 < n)
00125     {
00126         unsigned int j0 = i0+1;
00127         double eps = M.element(i0,i0)*1.0e-10;
00128         while (j0 < n)
00129             if (fabs(M.element(i0,j0)) > eps) break;
00130             else ++j0;
00131         if (j0 == n)
00132         { // i0 row is the identity
00133             Inv.set(i0,i0,1.0/M.element(i0,i0));
00134             ++i0;
00135         }
00136         else break;
00137     }
00138     if (i0 == 0)
00139             Inv = M.i();
00140     else if (i0 < n)
00141         Inv.sub(i0,i0,n-i0,n-i0) = M.sub(i0,i0,n-i0,n-i0).i();
00142         //else return true;
00143         //return false;
00144     }
00145     void invert(Matrix& M)
00146     {
00147         const bool verbose  = f_verbose.getValue() || f_printLog.getValue();
00148         
00149         if( verbose )
00150         {
00151             std::cerr<<"BTDLinearSolver, M = "<< M <<std::endl;
00152         }
00153         
00154         const int bsize = f_blockSize.getValue();
00155         const int nb = M.rowSize() / bsize;
00156         if (nb == 0) return;
00157         //alpha.resize(nb);
00158         alpha_inv.resize(nb);
00159         lambda.resize(nb-1);
00160         B.resize(nb);
00161         
00162         SubMatrix A, C;
00163         //int ndiag = 0;
00164         M.getSubMatrix(0*bsize,0*bsize,bsize,bsize,A);
00165         //if (verbose) std::cout << "A[0] = " << A << std::endl;
00166         M.getSubMatrix(0*bsize,1*bsize,bsize,bsize,C);
00167         //if (verbose) std::cout << "C[0] = " << C << std::endl;
00168         //alpha[0] = A;
00169         invert(alpha_inv[0],A);
00170         if (verbose) std::cout << "alpha_inv[0] = " << alpha_inv[0] << std::endl;
00171         lambda[0] = alpha_inv[0]*C;
00172         if (verbose) std::cout << "lambda[0] = " << lambda[0] << std::endl;
00173         //if (verbose) std::cout << "C[0] = alpha[0]*lambda[0] = " << alpha[0]*lambda[0] << std::endl;
00174         for (int i=1;i<nb;++i)
00175         {
00176             M.getSubMatrix((i  )*bsize,(i  )*bsize,bsize,bsize,A);
00177             //if (verbose) std::cout << "A["<<i<<"] = " << A << std::endl;
00178             M.getSubMatrix((i  )*bsize,(i-1)*bsize,bsize,bsize,B[i]);
00179             //if (verbose) std::cout << "B["<<i<<"] = " << B[i] << std::endl;
00180             //alpha[i] = (A - B[i]*lambda[i-1]);
00181         invert(alpha_inv[i], (A - B[i]*lambda[i-1]));
00182             if (verbose) std::cout << "alpha_inv["<<i<<"] = " << alpha_inv[i] << std::endl;
00183             //if (verbose) std::cout << "A["<<i<<"] = B["<<i<<"]*lambda["<<i-1<<"]+alpha["<<i<<"] = " << B[i]*lambda[i-1]+alpha[i] << std::endl;
00184             if (i<nb-1)
00185             {
00186                 M.getSubMatrix((i  )*bsize,(i+1)*bsize,bsize,bsize,C);
00187                 //if (verbose) std::cout << "C["<<i<<"] = " << C << std::endl;
00188                 lambda[i] = alpha_inv[i]*C;
00189                 if (verbose) std::cout << "lambda["<<i<<"] = " << lambda[i] << std::endl;
00190                 //if (verbose) std::cout << "C["<<i<<"] = alpha["<<i<<"]*lambda["<<i<<"] = " << alpha[i]*lambda[i] << std::endl;
00191             }
00192         }
00193         nBlockComputedMinv.resize(nb);
00194         for (int i=0;i<nb;++i)
00195             nBlockComputedMinv[i] = 0;
00196         Minv.resize(nb*bsize,nb*bsize);
00197         Minv.setSubMatrix((nb-1)*bsize,(nb-1)*bsize,bsize,bsize,alpha_inv[nb-1]);
00198         nBlockComputedMinv[nb-1] = 1;
00199         //std::cout << "BTDLinearSolver: "<<ndiag<<"/"<<nb<<"diagonal blocs."<<std::endl;
00200     }
00201     
00208     
00209     void computeMinvBlock(int i, int j)
00210     {
00211         const int bsize = f_blockSize.getValue();
00212         if (i < j)
00213         { // lower diagonal
00214             int t = i; i = j; j = t;
00215         }
00216         if (nBlockComputedMinv[i] > i-j) return;
00217         int i0 = i;
00218         while (nBlockComputedMinv[i0]==0)
00219             ++i0;
00220         while (i0 > i)
00221         {
00222             if (nBlockComputedMinv[i0] == 1)
00223             {
00224                 // compute bloc (i0,i0-1)
00225                 Minv.sub((i0  )*bsize,(i0-1)*bsize,bsize,bsize) = Minv.sub((i0  )*bsize,(i0  )*bsize,bsize,bsize)*(-lambda[i0-1].t());
00226                 ++nBlockComputedMinv[i0];
00227             }
00228             // compute bloc (i0-1,i0-1)
00229             Minv.sub((i0-1)*bsize,(i0-1)*bsize,bsize,bsize) = alpha_inv[i0-1] - lambda[i0-1]*Minv.sub((i0  )*bsize,(i0-1)*bsize,bsize,bsize);
00230             ++nBlockComputedMinv[i0-1];
00231             --i0;
00232         }
00233         int j0 = i-nBlockComputedMinv[i];
00234         while (j0 >= j)
00235         {
00236             // compute bloc (i0,j0)
00237             Minv.sub((i0  )*bsize,(j0  )*bsize,bsize,bsize) = Minv.sub((i0  )*bsize,(j0+1)*bsize,bsize,bsize)*(-lambda[j0].t());
00238             ++nBlockComputedMinv[i0];
00239             --j0;
00240         }
00241     }
00242     
00243     double getMinvElement(int i, int j)
00244     {
00245         const int bsize = f_blockSize.getValue();
00246         if (i < j)
00247         { // lower diagonal
00248             int t = i; i = j; j = t;
00249         }
00250         computeMinvBlock(i/bsize, j/bsize);
00251         return Minv.element(i,j);
00252     }
00253     
00255     void solve (Matrix& /*M*/, Vector& x, Vector& b)
00256     {
00257         const bool verbose  = f_verbose.getValue() || f_printLog.getValue();
00258         
00259         if( verbose )
00260         {
00261             std::cerr<<"BTDLinearSolver, b = "<< b <<std::endl;
00262         }
00263         
00264         //invert(M);
00265         
00266         const int bsize = f_blockSize.getValue();
00267         const int nb = b.size() / bsize;
00268         if (nb == 0) return;
00269         
00270         //if (verbose) std::cout << "D["<<0<<"] = " << b.sub(0,bsize) << std::endl;
00271         x.sub(0,bsize) = alpha_inv[0] * b.sub(0,bsize);
00272         //if (verbose) std::cout << "Y["<<0<<"] = " << x.sub(0,bsize) << std::endl;
00273         for (int i=1;i<nb;++i)
00274         {
00275             //if (verbose) std::cout << "D["<<i<<"] = " << b.sub(i*bsize,bsize) << std::endl;
00276             x.sub(i*bsize,bsize) = alpha_inv[i]*(b.sub(i*bsize,bsize) - B[i]*x.sub((i-1)*bsize,bsize));
00277             //if (verbose) std::cout << "Y["<<i<<"] = " << x.sub(i*bsize,bsize) << std::endl;
00278         }
00279         //x.sub((nb-1)*bsize,bsize) = Y.sub((nb-1)*bsize,bsize);
00280         //if (verbose) std::cout << "x["<<nb-1<<"] = " << x.sub((nb-1)*bsize,bsize) << std::endl;
00281         for (int i=nb-2;i>=0;--i)
00282         {
00283             x.sub(i*bsize,bsize) /* = Y.sub(i*bsize,bsize)- */ -= lambda[i]*x.sub((i+1)*bsize,bsize);
00284             //if (verbose) std::cout << "x["<<i<<"] = " << x.sub(i*bsize,bsize) << std::endl;
00285         }
00286         
00287         // x is the solution of the system
00288         if( verbose )
00289         {
00290             std::cerr<<"BTDLinearSolver::solve, solution = "<<x<<std::endl;
00291         }
00292     }
00293     
00294     template<class RMatrix, class JMatrix>
00295     bool addJMInvJt(RMatrix& result, JMatrix& J, double fact)
00296     {
00297         //const int Jrows = J.rowSize();
00298         const int Jcols = J.colSize();
00299         if (Jcols != Minv.rowSize())
00300         {
00301             std::cerr << "BTDLinearSolver::addJMInvJt ERROR: incompatible J matrix size." << std::endl;
00302             return false;
00303         }
00304 
00305 
00306 #if 0
00307 // WARNING !!! 
00308         //Getting all elements of Minv modifies the obtained Matrix "result"!! 
00309         // It seems that result is computed more accurately.
00310         // There is a BUG to find here...
00311         if (!problem.getValue()){
00312         for  (int mr=0; mr<Minv.rowSize(); mr++)
00313         {
00314             for (int mc=0; mc<Minv.colSize(); mc++)
00315             {
00316                 /*double toto=*/getMinvElement(mr,mc);
00317             }           
00318         }
00319         }
00321 #endif
00322         if (f_verbose.getValue()){
00323 // debug christian: print of the inverse matrix:
00324         std::cout<< "C = ["<<std::endl; 
00325         for  (int mr=0; mr<Minv.rowSize(); mr++)
00326         {
00327             std::cout<<" "<<std::endl;
00328             for (int mc=0; mc<Minv.colSize(); mc++)
00329             {
00330                 std::cout<<" "<< getMinvElement(mr,mc);
00331             }           
00332         }
00333         std::cout<< "];"<<std::endl; 
00334 
00335 // debug christian: print of matrix J:              
00336         std::cout<< "J = ["<<std::endl; 
00337         for  (int jr=0; jr<J.rowSize(); jr++)
00338         {
00339             std::cout<<" "<<std::endl;
00340             for (int jc=0; jc<J.colSize(); jc++)
00341             {
00342                 std::cout<<" "<< J.element(jr, jc) ;
00343             }           
00344         }
00345         std::cout<< "];"<<std::endl;
00346         }
00347 
00348         
00349         const typename JMatrix::LineConstIterator jitend = J.end();
00350         for (typename JMatrix::LineConstIterator jit1 = J.begin(); jit1 != jitend; ++jit1)
00351         {
00352             int row1 = jit1->first;
00353             for (typename JMatrix::LineConstIterator jit2 = jit1; jit2 != jitend; ++jit2)
00354             {
00355                 int row2 = jit2->first;
00356                 double acc = 0.0;
00357                 for (typename JMatrix::LElementConstIterator i1 = jit1->second.begin(), i1end = jit1->second.end(); i1 != i1end; ++i1)
00358                 {
00359                     int col1 = i1->first;
00360                     double val1 = i1->second;
00361                     for (typename JMatrix::LElementConstIterator i2 = jit2->second.begin(), i2end = jit2->second.end(); i2 != i2end; ++i2)
00362                     {
00363                         int col2 = i2->first;
00364                         double val2 = i2->second;
00365                         acc += val1 * getMinvElement(col1,col2) * val2;
00366                     }
00367                 }
00368                 //std::cout << "W("<<row1<<","<<row2<<") += "<<acc<<" * "<<fact<<std::endl;
00369                 acc *= fact;
00370                 result.add(row1,row2,acc);
00371                 if (row1!=row2)
00372                     result.add(row2,row1,acc);
00373             }
00374         }
00375         return true;
00376     }
00377     
00383     bool addJMInvJt(defaulttype::BaseMatrix* result, defaulttype::BaseMatrix* J, double fact)
00384     {
00385         if (FullMatrix<double>* r = dynamic_cast<FullMatrix<double>*>(result))
00386         {
00387             if (SparseMatrix<double>* j = dynamic_cast<SparseMatrix<double>*>(J))
00388             {
00389                 return addJMInvJt(*r,*j,fact);
00390             }
00391             else if (SparseMatrix<float>* j = dynamic_cast<SparseMatrix<float>*>(J))
00392             {
00393                 return addJMInvJt(*r,*j,fact);
00394             }
00395         }
00396         else if (FullMatrix<double>* r = dynamic_cast<FullMatrix<double>*>(result))
00397         {
00398             if (SparseMatrix<double>* j = dynamic_cast<SparseMatrix<double>*>(J))
00399             {
00400                 return addJMInvJt(*r,*j,fact);
00401             }
00402             else if (SparseMatrix<float>* j = dynamic_cast<SparseMatrix<float>*>(J))
00403             {
00404                 return addJMInvJt(*r,*j,fact);
00405             }
00406         }
00407         else if (defaulttype::BaseMatrix* r = result)
00408         {
00409             if (SparseMatrix<double>* j = dynamic_cast<SparseMatrix<double>*>(J))
00410             {
00411                 return addJMInvJt(*r,*j,fact);
00412             }
00413             else if (SparseMatrix<float>* j = dynamic_cast<SparseMatrix<float>*>(J))
00414             {
00415                 return addJMInvJt(*r,*j,fact);
00416             }
00417         }
00418         return false;
00419     }
00420 
00421 };
00422 
00423 } // namespace linearsolver
00424 
00425 } // namespace component
00426 
00427 } // namespace sofa
00428 
00429 #endif

Generated on Sun Nov 23 03:25:07 2008 for Sofa by  doxygen 1.5.7.1