computation/interfaces/direct/SuperLU.cxx

00001 // Copyright (C) 2003-2009 Marc Duruflé
00002 //
00003 // This file is part of the linear-algebra library Seldon,
00004 // http://seldon.sourceforge.net/.
00005 //
00006 // Seldon is free software; you can redistribute it and/or modify it under the
00007 // terms of the GNU Lesser General Public License as published by the Free
00008 // Software Foundation; either version 2.1 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public License
00017 // along with Seldon. If not, see http://www.gnu.org/licenses/.
00018 
00019 
00020 #ifndef SELDON_FILE_SUPERLU_CXX
00021 
00022 #include "SuperLU.hxx"
00023 
00024 // The function comes from the Matlab interface to SuperLU. It is part of
00025 // SuperLU package. Its copyright is held by University of California
00026 // Berkeley, Xerox Palo Alto Research Center and Lawrence Berkeley National
00027 // Lab. It is released under a license compatible with the GNU LGPL.
00028 void LUextract(SuperMatrix *L, SuperMatrix *U, double *Lval, int *Lrow,
00029                int *Lcol, double *Uval, int *Urow, int *Ucol, int *snnzL,
00030                int *snnzU)
00031 {
00032   int         i, j, k;
00033   int         upper;
00034   int         fsupc, istart, nsupr;
00035   int         lastl = 0, lastu = 0;
00036   SCformat    *Lstore;
00037   NCformat    *Ustore;
00038   double      *SNptr;
00039 
00040   Lstore = static_cast<SCformat*>(L->Store);
00041   Ustore = static_cast<NCformat*>(U->Store);
00042   Lcol[0] = 0;
00043   Ucol[0] = 0;
00044 
00045   /* for each supernode */
00046   for (k = 0; k <= Lstore->nsuper; ++k) {
00047 
00048     fsupc = L_FST_SUPC(k);
00049     istart = L_SUB_START(fsupc);
00050     nsupr = L_SUB_START(fsupc+1) - istart;
00051     upper = 1;
00052 
00053     /* for each column in the supernode */
00054     for (j = fsupc; j < L_FST_SUPC(k+1); ++j) {
00055       SNptr = &(static_cast<double*>(Lstore->nzval))[L_NZ_START(j)];
00056 
00057       /* Extract U */
00058       for (i = U_NZ_START(j); i < U_NZ_START(j+1); ++i) {
00059         Uval[lastu] = (static_cast<double*>(Ustore->nzval))[i];
00060         Urow[lastu++] = U_SUB(i);
00061       }
00062       for (i = 0; i < upper; ++i) { /* upper triangle in the supernode */
00063         Uval[lastu] = SNptr[i];
00064         Urow[lastu++] = L_SUB(istart+i);
00065       }
00066       Ucol[j+1] = lastu;
00067 
00068       /* Extract L */
00069       Lval[lastl] = 1.0; /* unit diagonal */
00070       Lrow[lastl++] = L_SUB(istart + upper - 1);
00071       for (i = upper; i < nsupr; ++i) {
00072         Lval[lastl] = SNptr[i];
00073         Lrow[lastl++] = L_SUB(istart+i);
00074       }
00075       Lcol[j+1] = lastl;
00076 
00077       ++upper;
00078 
00079     } /* for j ... */
00080 
00081   } /* for k ... */
00082 
00083   *snnzL = lastl;
00084   *snnzU = lastu;
00085 }
00086 
00087 
00088 namespace Seldon
00089 {
00091   template<class T>
00092   MatrixSuperLU_Base<T>::MatrixSuperLU_Base()
00093   {
00094     n = 0;
00095     permc_spec = COLAMD;
00096     Lstore = NULL;
00097     Ustore = NULL;
00098     StatInit(&stat);
00099     set_default_options(&options);
00100     ShowMessages();
00101     display_info = false;
00102     info_facto = 0;
00103   }
00104 
00105 
00107   template<class T>
00108   MatrixSuperLU_Base<T>::~MatrixSuperLU_Base()
00109   {
00110     Clear();
00111   }
00112 
00113 
00115 
00124   template<class T>
00125   template<class Prop, class Allocator>
00126   void MatrixSuperLU_Base<T>
00127   ::GetLU(Matrix<double, Prop, ColSparse, Allocator>& Lmat,
00128           Matrix<double, Prop, ColSparse, Allocator>& Umat,
00129           bool permuted)
00130   {
00131     Lstore = static_cast<SCformat*>(L.Store);
00132     Ustore = static_cast<NCformat*>(U.Store);
00133 
00134     int Lnnz = Lstore->nnz;
00135     int Unnz = Ustore->nnz;
00136 
00137     int m = U.nrow;
00138     int n = U.ncol;
00139 
00140     Vector<double, VectFull, Allocator> Lval(Lnnz);
00141     Vector<int, VectFull, CallocAlloc<int> > Lrow(Lnnz);
00142     Vector<int, VectFull, CallocAlloc<int> > Lcol(n + 1);
00143 
00144     Vector<double, VectFull, Allocator> Uval(Unnz);
00145     Vector<int, VectFull, CallocAlloc<int> > Urow(Unnz);
00146     Vector<int, VectFull, CallocAlloc<int> > Ucol(n + 1);
00147 
00148     int Lsnnz;
00149     int Usnnz;
00150     LUextract(&L, &U, Lval.GetData(), Lrow.GetData(), Lcol.GetData(),
00151               Uval.GetData(), Urow.GetData(), Ucol.GetData(), &Lsnnz, &Usnnz);
00152 
00153     Lmat.SetData(m, n, Lval, Lcol, Lrow);
00154     Umat.SetData(m, n, Uval, Ucol, Urow);
00155 
00156     if (!permuted)
00157       {
00158         Vector<int> row_perm_orig = perm_r;
00159         Vector<int> col_perm_orig = perm_c;
00160 
00161         Vector<int> row_perm(n);
00162         Vector<int> col_perm(n);
00163         row_perm.Fill();
00164         col_perm.Fill();
00165 
00166         Sort(row_perm_orig, row_perm);
00167         Sort(col_perm_orig, col_perm);
00168 
00169         ApplyInversePermutation(Lmat, row_perm, col_perm);
00170         ApplyInversePermutation(Umat, row_perm, col_perm);
00171       }
00172   }
00173 
00174 
00176 
00187   template<class T>
00188   template<class Prop, class Allocator>
00189   void MatrixSuperLU_Base<T>
00190   ::GetLU(Matrix<double, Prop, RowSparse, Allocator>& Lmat,
00191           Matrix<double, Prop, RowSparse, Allocator>& Umat,
00192           bool permuted)
00193   {
00194     Lmat.Clear();
00195     Umat.Clear();
00196 
00197     Matrix<double, Prop, ColSparse, Allocator> Lmat_col;
00198     Matrix<double, Prop, ColSparse, Allocator> Umat_col;
00199     GetLU(Lmat_col, Umat_col, permuted);
00200 
00201     Copy(Lmat_col, Lmat);
00202     Lmat_col.Clear();
00203     Copy(Umat_col, Umat);
00204     Umat_col.Clear();
00205   }
00206 
00207 
00209 
00215   template<class T>
00216   const Vector<int>& MatrixSuperLU_Base<T>::GetRowPermutation() const
00217   {
00218     return perm_r;
00219   }
00220 
00221 
00223 
00229   template<class T>
00230   const Vector<int>& MatrixSuperLU_Base<T>::GetColPermutation() const
00231   {
00232     return perm_c;
00233   }
00234 
00235 
00236   template<class T>
00237   void MatrixSuperLU_Base<T>::SelectOrdering(colperm_t type)
00238   {
00239     permc_spec = type;
00240   }
00241 
00242 
00243   template<class T>
00244   void MatrixSuperLU_Base<T>::SetPermutation(const IVect& permut)
00245   {
00246     permc_spec = MY_PERMC;
00247     perm_c = permut;
00248     perm_r = permut;
00249   }
00250 
00251 
00253   template<class T>
00254   void MatrixSuperLU_Base<T>::Clear()
00255   {
00256     if (n > 0)
00257       {
00258         // SuperLU objects are cleared
00259         Destroy_SuperMatrix_Store(&B);
00260         Destroy_SuperNode_Matrix(&L);
00261         Destroy_CompCol_Matrix(&U);
00262         perm_r.Clear();
00263         perm_c.Clear();
00264         n = 0;
00265       }
00266   }
00267 
00268 
00270   template<class T>
00271   void MatrixSuperLU_Base<T>::HideMessages()
00272   {
00273     display_info = false;
00274   }
00275 
00276 
00278   template<class T>
00279   void MatrixSuperLU_Base<T>::ShowMessages()
00280   {
00281     display_info = true;
00282   }
00283 
00284 
00285   template<class T>
00286   int MatrixSuperLU_Base<T>::GetInfoFactorization() const
00287   {
00288     return info_facto;
00289   }
00290 
00291 
00293   template<class Prop, class Storage, class Allocator>
00294   void MatrixSuperLU<double>::
00295   FactorizeMatrix(Matrix<double, Prop, Storage, Allocator> & mat,
00296                   bool keep_matrix)
00297   {
00298     // clearing previous factorization
00299     Clear();
00300 
00301     // conversion in CSC format
00302     n = mat.GetN();
00303     Matrix<double, General, ColSparse> Acsr;
00304     Copy(mat, Acsr);
00305     if (!keep_matrix)
00306       mat.Clear();
00307 
00308     SuperMatrix A, AA;
00309     int nnz = Acsr.GetDataSize();
00310     dCreate_CompCol_Matrix(&AA, n, n, nnz, Acsr.GetData(), Acsr.GetInd(),
00311                            Acsr.GetPtr(), SLU_NC, SLU_D, SLU_GE);
00312 
00313     // we get renumbering vectors perm_r and perm_c
00314     options.ColPerm = permc_spec;
00315     if (permc_spec != MY_PERMC)
00316       {
00317         perm_r.Reallocate(n);
00318         perm_c.Reallocate(n);
00319         perm_r.Fill();
00320         perm_c.Fill();
00321 
00322         get_perm_c(permc_spec, &AA, perm_c.GetData());
00323       }
00324 
00325     // Original matrix AA is permuted to obtain matrix A.
00326     Vector<int> etree(n);
00327     sp_preorder(&options, &AA, perm_c.GetData(), etree.GetData(), &A);
00328 
00329     int panel_size = sp_ienv(1);
00330     int relax = sp_ienv(2);
00331     int lwork = 0;
00332 
00333     // Then calling factorization on permuted matrix.
00334     dgstrf(&options, &A, relax, panel_size, etree.GetData(),
00335            NULL, lwork, perm_c.GetData(), perm_r.GetData(), &L, &U, &stat,
00336            &info_facto);
00337 
00338     // Clearing matrices.
00339     Destroy_CompCol_Permuted(&A);
00340     Destroy_CompCol_Matrix(&AA);
00341 
00342     if (info_facto == 0 && display_info)
00343       {
00344         mem_usage_t mem_usage;
00345         Lstore = (SCformat *) L.Store;
00346         Ustore = (NCformat *) U.Store;
00347         cout << "Number of nonzeros in factor L = " << Lstore->nnz << endl;
00348         cout << "Number of nonzeros in factor U = " << Ustore->nnz << endl;
00349         cout << "Number of nonzeros in L+U     = "
00350              << Lstore->nnz + Ustore->nnz << endl;
00351         dQuerySpace(&L, &U, &mem_usage);
00352         cout << "Memory used for factorization in MB: "
00353              << mem_usage.total_needed / (1024. * 1024.) << endl;
00354       }
00355 
00356     Acsr.Nullify();
00357   }
00358 
00359 
00361   template<class Allocator2>
00362   void MatrixSuperLU<double>::Solve(Vector<double, VectFull, Allocator2>& x)
00363   {
00364     trans_t trans = NOTRANS;
00365     int nb_rhs = 1, info;
00366     // Putting right hand side on SuperLU structure.
00367     dCreate_Dense_Matrix(&B, x.GetM(), nb_rhs,
00368                          x.GetData(), x.GetM(), SLU_DN, SLU_D, SLU_GE);
00369 
00370     SuperLUStat_t stat;
00371     StatInit(&stat);
00372     // Solving A x = b.
00373     dgstrs(trans, &L, &U, perm_r.GetData(),
00374            perm_c.GetData(), &B, &stat, &info);
00375   }
00376 
00377 
00379   template<class TransStatus, class Allocator2>
00380   void MatrixSuperLU<double>::Solve(const TransStatus& TransA,
00381                                     Vector<double, VectFull, Allocator2>& x)
00382   {
00383     if (TransA.NoTrans())
00384       {
00385         Solve(x);
00386         return;
00387       }
00388 
00389     trans_t trans = TRANS;
00390     int nb_rhs = 1, info;
00391     // Putting right hand side on SuperLU structure.
00392     dCreate_Dense_Matrix(&B, x.GetM(), nb_rhs,
00393                          x.GetData(), x.GetM(), SLU_DN, SLU_D, SLU_GE);
00394 
00395     SuperLUStat_t stat;
00396     StatInit(&stat);
00397     // Solving A^T x = b.
00398     dgstrs(trans, &L, &U, perm_r.GetData(),
00399            perm_c.GetData(), &B, &stat, &info);
00400   }
00401 
00402 
00404   template<class Prop, class Storage, class Allocator>
00405   void MatrixSuperLU<complex<double> >::
00406   FactorizeMatrix(Matrix<complex<double>, Prop, Storage, Allocator> & mat,
00407                   bool keep_matrix)
00408   {
00409     // clearing previous factorization
00410     Clear();
00411 
00412     // conversion in CSR format
00413     n = mat.GetN();
00414     Matrix<complex<double>, General, ColSparse> Acsr;
00415     Copy(mat, Acsr);
00416     if (!keep_matrix)
00417       mat.Clear();
00418 
00419     SuperMatrix AA, A;
00420     int nnz = Acsr.GetDataSize();
00421     zCreate_CompCol_Matrix(&AA, n, n, nnz,
00422                            reinterpret_cast<doublecomplex*>(Acsr.GetData()),
00423                            Acsr.GetInd(), Acsr.GetPtr(),
00424                            SLU_NC, SLU_Z, SLU_GE);
00425 
00426     // We get renumbering vectors perm_r and perm_c.
00427     options.ColPerm = permc_spec;
00428     if (permc_spec != MY_PERMC)
00429       {
00430         perm_r.Reallocate(n);
00431         perm_c.Reallocate(n);
00432         perm_r.Fill();
00433         perm_c.Fill();
00434 
00435         get_perm_c(permc_spec, &AA, perm_c.GetData());
00436       }
00437 
00438     // Permuting matrix.
00439     Vector<int> etree(n);
00440     sp_preorder(&options, &AA, perm_c.GetData(), etree.GetData(), &A);
00441 
00442     int panel_size = sp_ienv(1);
00443     int relax = sp_ienv(2);
00444     int lwork = 0;
00445 
00446     // Factorization.
00447     zgstrf(&options, &A, relax, panel_size, etree.GetData(),
00448            NULL, lwork, perm_c.GetData(), perm_r.GetData(), &L, &U, &stat,
00449            &info_facto);
00450 
00451     // Clearing matrices.
00452     Destroy_CompCol_Permuted(&A);
00453     Destroy_CompCol_Matrix(&AA);
00454 
00455     if (info_facto == 0 && display_info)
00456       {
00457         mem_usage_t mem_usage;
00458         Lstore = (SCformat *) L.Store;
00459         Ustore = (NCformat *) U.Store;
00460         cout << "Number of nonzeros in factor L = " << Lstore->nnz<<endl;
00461         cout << "Number of nonzeros in factor U = " << Ustore->nnz<<endl;
00462         cout << "Number of nonzeros in L+U     = "
00463              << Lstore->nnz + Ustore->nnz<<endl;
00464         zQuerySpace(&L, &U, &mem_usage);
00465         cout << "Memory used for factorization in MB: "
00466              << mem_usage.total_needed / (1024. * 1024.) << endl;
00467       }
00468 
00469     Acsr.Nullify();
00470   }
00471 
00472 
00474   template<class Allocator2>
00475   void MatrixSuperLU<complex<double> >::
00476   Solve(Vector<complex<double>, VectFull, Allocator2>& x)
00477   {
00478     trans_t trans = NOTRANS;
00479     int nb_rhs = 1, info;
00480     zCreate_Dense_Matrix(&B, x.GetM(), nb_rhs,
00481                          reinterpret_cast<doublecomplex*>(x.GetData()),
00482                          x.GetM(), SLU_DN, SLU_Z, SLU_GE);
00483 
00484     zgstrs(trans, &L, &U, perm_c.GetData(),
00485            perm_r.GetData(), &B, &stat, &info);
00486   }
00487 
00488 
00490   template<class TransStatus, class Allocator2>
00491   void MatrixSuperLU<complex<double> >::
00492   Solve(const TransStatus& TransA,
00493         Vector<complex<double>, VectFull, Allocator2>& x)
00494   {
00495     if (TransA.NoTrans())
00496       {
00497         Solve(x);
00498         return;
00499       }
00500 
00501     trans_t trans = TRANS;
00502     int nb_rhs = 1, info;
00503     zCreate_Dense_Matrix(&B, x.GetM(), nb_rhs,
00504                          reinterpret_cast<doublecomplex*>(x.GetData()),
00505                          x.GetM(), SLU_DN, SLU_Z, SLU_GE);
00506 
00507     zgstrs(trans, &L, &U, perm_c.GetData(),
00508            perm_r.GetData(), &B, &stat, &info);
00509   }
00510 
00511 
00512   template<class T, class Prop, class Storage, class Allocator>
00513   void GetLU(Matrix<T, Prop, Storage, Allocator>& A, MatrixSuperLU<T>& mat_lu,
00514              bool keep_matrix = false)
00515   {
00516     mat_lu.FactorizeMatrix(A, keep_matrix);
00517   }
00518 
00519 
00520   template<class T, class Allocator>
00521   void SolveLU(MatrixSuperLU<T>& mat_lu, Vector<T, VectFull, Allocator>& x)
00522   {
00523     mat_lu.Solve(x);
00524   }
00525 
00526 
00527   template<class T, class Allocator>
00528   void SolveLU(const SeldonTranspose& TransA,
00529                MatrixSuperLU<T>& mat_lu, Vector<T, VectFull, Allocator>& x)
00530   {
00531     mat_lu.Solve(TransA, x);
00532   }
00533 
00534 }
00535 
00536 #define SELDON_FILE_SUPERLU_CXX
00537 #endif