SparseMatrix.cpp

Go to the documentation of this file.
00001 
00009 // SpMatrix2.cpp: implementation of the CSpMatrix class.
00010 //
00012 
00013 #include "SparseMatrix.h"
00014 #include "Matlab.h"
00015 #include <assert.h>
00016 #include <math.h>
00017 
00018 using namespace MeshLib;
00019 
00024 inline bool isZero(double x)
00025 {
00026         return (fabs(x) < 1e-9);
00027 }
00028 
00030 // Construction/Destruction
00032 
00039 CSparseMatrix::CSparseMatrix(int nRows, int nCols, int nnz /* = 0 */)
00040 {
00041         m_nRows = nRows;
00042         m_nCols = nCols;
00043         assert(nRows > 0);
00044         assert(nCols > 0);
00045         m_pEntries = new vector<_Entry>();
00046         if (nnz > 0)
00047                 m_pEntries->reserve(nnz);
00048 
00049         if (nnz > 1024)
00050         {
00051                 m_nHashCode = nnz;
00052         }
00053         else
00054         {
00055                 m_nHashCode = (nRows > nCols)? nRows * 6: nCols * 6;
00056         }
00057 
00058         // prime will be better
00059         if (m_nHashCode % 2 == 0)
00060                 m_nHashCode++;
00061 
00062         m_bAccessed = new bool[m_nHashCode];
00063         memset(m_bAccessed, 0, sizeof(bool) * m_nHashCode);
00064 }
00065 
00070 CSparseMatrix::~CSparseMatrix()
00071 {
00072         if (m_pEntries != NULL)
00073                 delete m_pEntries;
00074 
00075         delete [] m_bAccessed;
00076 }
00084 int CSparseMatrix::CalcHashCode(int nRow, int nCol)
00085 {
00086         return (nRow * 37 + nCol * 103) % m_nHashCode;
00087 }
00088 
00095 void CSparseMatrix::AddElement(int nRow, int nCol, double dVal)
00096 {
00097         _Entry entry;
00098         assert(nRow >= 0 && nRow < m_nRows);
00099         assert(nCol >= 0 && nCol < m_nCols);
00100         bool bFound = false;
00101         
00102         int hash = CalcHashCode(nRow, nCol);
00103         if (m_bAccessed[hash])
00104         {
00105                 for (int i = 0; i < (int)m_pEntries->size(); i++)
00106                 {
00107                         _Entry& e = m_pEntries->at(i);
00108                         if (e.i == nRow && e.j == nCol)
00109                         {
00110                                 e.val += dVal;
00111                                 if (isZero(e.val))
00112                                 {
00113                                         if (m_pEntries->size() > 0)     // Copy last to current
00114                                         {
00115                                                 m_pEntries->at(i) = m_pEntries->at(m_pEntries->size() - 1);
00116                                         }
00117                                         m_pEntries->resize(m_pEntries->size() - 1);
00118                                 }
00119                                 bFound = true;
00120                                 break;
00121                         }
00122                 }
00123         }
00124         if (!bFound)
00125         {
00126                 m_bAccessed[hash] = true;
00127                 entry.i = nRow;
00128                 entry.j = nCol;
00129                 entry.val = dVal;
00130                 m_pEntries->push_back(entry);
00131         }
00132 }
00133 
00134 // Adding new entry, No Checking for duplicacy
00141 void CSparseMatrix::AddElementTail(int nRow, int nCol, double dVal)
00142 {
00143         _Entry entry;
00144         assert(nRow >= 0 && nRow < m_nRows);
00145         assert(nCol >= 0 && nCol < m_nCols);
00146 
00147         entry.i = nRow;
00148         entry.j = nCol;
00149         entry.val = dVal;
00150         m_bAccessed[CalcHashCode(nRow, nCol)] = true;
00151 
00152         m_pEntries->push_back(entry);
00153 //      printf("(%d,%d) %f\n", nRow, nCol, dVal);
00154 }
00155 
00162 bool CSparseMatrix::CGSolver(double b[], double x[], double eps, int& itrs )
00163 {
00164         if( GetRows()!=GetCols() )
00165                 return false;
00166 
00167         int size = this->GetRows();
00168         // initialize
00169         double alpha, beta;
00170         double* r = new double[size];
00171         double* p = new double[size];
00172         double* temp = new double[size];
00173         double* multi = new double[size];
00174         assert( r != NULL && p != NULL && temp != NULL && multi != NULL );
00175 
00176         // x_0 = b_0
00177         for( int i=0; i<size; i++ )
00178                 x[i] = b[i];
00179 
00180         // r_0 = b - A*x_0
00181     Multiply( x, multi );
00182         
00183         //spM->TimesVDirect( x, size, multi, size );
00184 
00185         for( int i=0; i<size; i++ )
00186                 r[i] = b[i] - multi[i];
00187 
00188         //for( int i=0; i<size; i++ )
00189         //x[i] = multi[i];
00190         //  p_1 = r_0
00191         for( int i=0; i<size; i++ )
00192                 p[i] = r[i];
00193 
00194         double numerator, denominator;
00195 
00196         int step = 0;
00197 
00198         double norm_b = 0.0;
00199         for( int i=0; i<size; i++ )
00200                 norm_b += b[i]*b[i];
00201         norm_b = sqrt( norm_b );
00202 
00203         double norm_r = 0.0;
00204 
00205         while( true )
00206         {
00207                 if( itrs>=0 )
00208                         if( step>=itrs )
00209                                 break;
00210                 // ||r||/||b|| < threshold, then break
00211                 norm_r = 0.0;
00212                 for( int i=0; i<size; i++ )
00213                         norm_r += r[i]*r[i];
00214                 norm_r = sqrt( norm_r );
00215 
00216                 if( norm_r/norm_b<eps )
00217                         break;
00218 
00219                 // \alpha_k = r_{k-1}^T*r_{k-1}/p_k^T(A*p_k) 
00220                 numerator = 0.0;
00221                 for( int i=0; i<size; i++ )
00222                         numerator += r[i]*r[i];
00223 
00224 
00225                 //spM->TimesVDirect( p, size, multi, size );
00226                 this->Multiply( p, multi );
00227 
00228                 denominator = 0.0;
00229                 for( int i=0; i<size; i++ )
00230                         denominator += p[i]*multi[i];
00231 
00232                 alpha = numerator/denominator;
00233 
00234                 // x_k = x_{k-1} + \alpha_k * p_k
00235                 for( int i=0; i<size; i++ )
00236                         x[i] = x[i] + alpha*p[i];
00237 
00238                 for( int i=0; i<size; i++ )
00239                         temp[i] = r[i];         // temp ---- r_{k-1}
00240 
00241                 // r_k = r_{k-1} - \alpha_k*(A*p_k)
00242                 for( int i=0; i<size; i++ )
00243                         r[i] = temp[i] - alpha*multi[i];
00244 
00245                 // \beta = r_k^T*r_k/(r_{k-1}^T*r_{k-1})
00246                 numerator = 0.0;
00247                 for( int i=0; i<size; i++ )
00248                         numerator += r[i]*r[i];
00249                 denominator = 0.0;
00250                 for( int i=0; i<size; i++ )
00251                         denominator += temp[i]*temp[i];
00252                 beta = numerator/denominator;
00253 
00254                 // p_{k+1} = r_k + \beta*p_k
00255                 for( int i=0; i<size; i++ )
00256                         p[i] = r[i]+beta*p[i];
00257 
00258                 step++;
00259         }
00260 
00261         //spM->TimesVDirect( x, size, multi, size );
00262         this->Multiply( x, multi );
00263 
00264         double sum = 0.0;
00265         for( int i=0; i<size; i++ )
00266                 sum += (multi[i]-b[i])*(multi[i]-b[i]);
00267         sum = sqrt( sum );
00268 
00269         
00270         printf( "CG iter_num: %d error: %.10f\n", step, norm_r/norm_b );
00271 
00272         delete []r;
00273         delete []p;
00274         delete []multi;
00275         delete []temp;
00276 
00277         return true;
00278 }
00279 
00280 
00286 void CSparseMatrix::Multiply(double iVector[], double oVector[])
00287 {
00288         memset(oVector, 0, sizeof(double) *     m_nRows);
00289         for (int i = 0; i < (int)m_pEntries->size(); i++)
00290         {
00291                 _Entry& entry = m_pEntries->at(i);
00292                 oVector[entry.i] += iVector[entry.j] * entry.val;
00293         }
00294 }
00300 void CSparseMatrix::TransMul(double iVector[], double oVector[])
00301 {
00302         memset(oVector, 0, sizeof(double) * m_nCols);
00303         for (int i = 0; i < (int)m_pEntries->size(); i++)
00304         {
00305                 _Entry& entry = m_pEntries->at(i);
00306                 oVector[entry.j] += iVector[entry.i] * entry.val;
00307         }
00308 }
00309 /*
00310 bool CSparseMatrix::CGSolver2Matlab(double b[], double x[], double eps, int& itrs)
00311 {
00312 #ifndef NO_MATLAB
00313         InitMatlabEngine();
00314         Engine* ep = GetEngine();
00315         if (ep == NULL)
00316                 return (false);
00317 
00318         mxArray* bb = NULL;
00319         bb = mxCreateDoubleMatrix(m_nRows, 1, mxREAL);
00320         
00321         double* bbr = mxGetPr(bb);
00322         for (int i = 0; i < m_nRows; i++)
00323                 bbr[i] = b[i];
00324         
00325         engPutVariable(ep, "b", bb);    
00326         mxDestroyArray(bb);
00327         
00328         mxArray* AA = NULL;
00329         // statistic total non-zeros
00330         int tnz = (int) m_pEntries->size();
00331         // Count nnz in each column
00332         int* pNumInCol = new int[m_nCols];
00333         memset(pNumInCol, 0, sizeof(int) * m_nCols);
00334         for (int i = 0; i < (int)m_pEntries->size(); i++)
00335         {
00336                 pNumInCol[m_pEntries->at(i).j]++;
00337         }
00338 
00339         AA = mxCreateSparse(m_nRows, m_nCols, tnz, mxREAL);
00340 
00341         double* AAr = mxGetPr(AA);
00342         
00343         mwIndex* ir = (mwIndex*)mxGetIr(AA);
00344         mwIndex* jc = (mwIndex*)mxGetJc(AA);
00345 
00346         // update jc
00347         jc[0] = 0;
00348         for (int i = 1; i <= m_nCols; i++)
00349         {
00350                 jc[i] = jc[i - 1] + pNumInCol[i - 1];
00351         }
00352         
00353         // fill data
00354         // pNumInCol now represents # of elements currently filled
00355         memset(pNumInCol, 0, sizeof(int) * m_nCols);
00356         for (int i = 0; i < (int)m_pEntries->size(); i++)
00357         {
00358                 _Entry & e = m_pEntries->at(i);
00359                 int t = (int)( pNumInCol[e.j] + jc[e.j] );
00360                 AAr[t] = e.val;
00361                 ir[t] = e.i;
00362                 pNumInCol[e.j]++;
00363         }
00364 
00365         delete [] pNumInCol;
00366 
00367         engPutVariable(ep, "A", AA);
00368         mxDestroyArray(AA);
00369         
00370 //      engEvalString(ep, "x = A\\b;");
00371         engEvalString(ep, "x = (A'*A)\\(A'*b);");
00372         mxArray* xx = NULL;
00373         xx = engGetVariable(ep, "x");
00374         assert(xx != NULL);
00375         double* xxr = mxGetPr(xx);
00376         memcpy(x, xxr, sizeof(double) * m_nCols);
00377         
00378         mxDestroyArray(xx);
00379 //      CloseMatlabEngine();
00380 #else
00381         assert(false);
00382 #endif
00383         return (true);
00384 }
00385 */
00386 
00393 bool CSparseMatrix::CGSolverStable(double b[], double x[], double eps, int& itrs )
00394 {
00395         if( GetRows()!=GetCols() )
00396                 return false;
00397 
00398         int size = this->GetRows();
00399         // initialize
00400         double alpha, beta;
00401         double  sum;
00402         double* r = new double[size];
00403         double* p = new double[size];
00404         double* multi = new double[size];
00405         double* temp = new double[size];
00406 
00407         // x_0 = b_0
00408         for( int i=0; i<size; i++ )
00409                 x[i] = b[i];
00410 
00411         // r_0 = b - A*x_0
00412         sum = 0.0;
00413         for( int i=0; i<size; i++)
00414                 sum += x[i];
00415         for( int i=0; i<size; i++ )
00416         {
00417                 temp[i] = -(sum-x[i]);
00418         }
00419         //spM->TimesVDirect( temp, size, multi, size );
00420         this->Multiply( temp, multi ); 
00421 
00422 
00423         sum = 0.0;
00424         for( int i=0; i<size; i++)
00425                 sum += multi[i];
00426         for( int i=0; i<size; i++ )
00427         {
00428                 temp[i] = -(sum-multi[i]);
00429         }
00430 
00431         for( int i=0; i<size; i++ )
00432                 r[i] = b[i] - temp[i];
00433 
00434         //  p_1 = r_0
00435         for( int i=0; i<size; i++ )
00436                 p[i] = r[i];
00437 
00438         double numerator, denominator;
00439 
00440         int step = 0;
00441 
00442         double norm_b = 0.0;
00443         for( int i=0; i<size; i++ )
00444                 norm_b += multi[i]*multi[i];
00445         norm_b = sqrt( norm_b );
00446 
00447         double norm_r = 0.0;
00448 
00449         while( true )
00450         {
00451                 if( itrs>=0 )
00452                         if( step>=itrs )
00453                                 break;
00454                 // ||r||/||b|| < threshold, then break
00455                 norm_r = 0.0;
00456                 for( int i=0; i<size; i++ )
00457                         norm_r += r[i]*r[i];
00458                 norm_r = sqrt( norm_r );
00459 
00460                 if( norm_r/norm_b<eps )
00461                         break;
00462 
00463                 //fprintf( stderr, "%d - norm_r/norm_b = %.10f\n", step, norm_r/norm_b );
00464 
00465                 // \alpha_k = r_{k-1}^T*r_{k-1}/p_k^T(A*p_k) 
00466 
00467                 numerator = 0.0;
00468                 for( int i=0; i<size; i++ )
00469                         numerator += r[i]*r[i];
00470 
00471                 sum = 0.0;
00472                 for( int i=0; i<size; i++ )
00473                         sum += p[i];
00474                 for( int i=0; i<size; i++ )
00475                 {
00476                         temp[i] = -(sum-p[i]);
00477                 }
00478                 //spM->TimesVDirect( temp, size, multi, size );
00479                 this->Multiply( temp, multi );
00480                 sum = 0.0;
00481                 for( int i=0; i<size; i++ )
00482                         sum += multi[i];
00483                 for( int i=0; i<size; i++ )
00484                 {
00485                         temp[i] = -(sum-multi[i]);
00486                 }               // temp --- A*p_k
00487 
00488                 denominator = 0.0;
00489                 for( int i=0; i<size; i++ )
00490                         denominator += p[i]*temp[i];
00491 
00492                 alpha = numerator/denominator;
00493 
00494                 // x_k = x_{k-1} + \alpha_k * p_k
00495                 for( int i=0; i<size; i++ )
00496                         x[i] = x[i] + alpha*p[i];
00497 
00498                 for( int i=0; i<size; i++ )
00499                         multi[i] = r[i];                // multi ---- r_{k-1}
00500 
00501                 // r_k = r_{k-1} - \alpha_k*(A*p_k)
00502                 for( int i=0; i<size; i++ )
00503                         r[i] = multi[i] - alpha*temp[i];
00504 
00505                 // \beta = r_k^T*r_k/(r_{k-1}^T*r_{k-1})
00506                 numerator = 0.0;
00507                 for( int i=0; i<size; i++ )
00508                         numerator += r[i]*r[i];
00509                 denominator = 0.0;
00510                 for( int i=0; i<size; i++ )
00511                         denominator += multi[i]*multi[i];
00512                 beta = numerator/denominator;
00513 
00514                 // p_{k+1} = r_k + \beta*p_k
00515                 for( int i=0; i<size; i++ )
00516                         p[i] = r[i]+beta*p[i];
00517 
00518                 step++;
00519         }
00520 
00521 
00522         //printf( "CG iter_num: %d error: %.10f\n", step, norm_r/norm_b );
00523 
00524         delete []r;
00525         delete []p;
00526         delete []temp;
00527         delete []multi;
00528 
00529         return true;
00530 }
00531 
00535 bool Predicate(const _Entry & d1, const _Entry & d2)
00536 {
00537   return ( d1.j < d2.j || (d1.j==d2.j && d1.i < d2.i) );
00538 }
00539 
00544 bool CSparseMatrix::SolverUMF(double b[], double x[])
00545 {
00546         std::sort( (*m_pEntries).begin(), (*m_pEntries).end(), Predicate );
00547 
00548 
00549         int n = m_pEntries->size();
00550 /*
00551         for( int i = 0; i < n ; i ++ )
00552         {
00553                 _Entry & e = m_pEntries->at(i);
00554                 printf("(%d %d)\n", e.i, e.j);
00555         }
00556 */
00557 
00558         int *Ai = new int[n];
00559         double *Ax = new double[n];
00560 
00561         for( int i = 0; i < n ; i ++ )
00562         {
00563                 _Entry & e = m_pEntries->at(i);
00564                 Ai[i] = e.i;
00565                 Ax[i] = e.val;
00566         }
00567 
00568         int row = GetRows();
00569         int col = GetCols();
00570 
00571 
00572         int *Ap = new int[col+1];
00573 
00574         for( int i = 0; i < col + 1; i ++ )
00575         {
00576                 Ap[i] = 0;
00577         }
00578 
00579         for( int i = 0; i < n ; i ++ )
00580         {
00581                 _Entry & e = m_pEntries->at(i);
00582                 Ap[e.j+1]++;
00583         }
00584 
00585         for( int i = 1; i < col + 1; i ++ )
00586         {
00587                 Ap[i] = Ap[i] + Ap[i-1];
00588         }
00589 
00590         printf("%d - %d\n", Ap[col], n );
00591 
00592         void *Symbolic, *Numeric ;
00593         double *null = (double *) NULL ;
00594         (void) umfpack_di_symbolic (row, col, Ap, Ai, Ax, &Symbolic, null, null) ;
00595         (void) umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, null, null) ;
00596         umfpack_di_free_symbolic (&Symbolic) ;
00597         (void) umfpack_di_solve (UMFPACK_A, Ap, Ai, Ax, x, b, Numeric, null, null) ;
00598         umfpack_di_free_numeric (&Numeric) ;
00599 
00600         delete []Ap;
00601         delete []Ax;
00602         delete []Ai;
00603 
00604         return true;
00605 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Defines