ViennaCL - The Vienna Computing Library  1.5.0
viennacl/linalg/detail/ilu/ilut.hpp
Go to the documentation of this file.
00001 #ifndef VIENNACL_LINALG_DETAIL_ILUT_HPP_
00002 #define VIENNACL_LINALG_DETAIL_ILUT_HPP_
00003 
00004 /* =========================================================================
00005    Copyright (c) 2010-2013, Institute for Microelectronics,
00006                             Institute for Analysis and Scientific Computing,
00007                             TU Wien.
00008    Portions of this software are copyright by UChicago Argonne, LLC.
00009 
00010                             -----------------
00011                   ViennaCL - The Vienna Computing Library
00012                             -----------------
00013 
00014    Project Head:    Karl Rupp                   rupp@iue.tuwien.ac.at
00015 
00016    (A list of authors and contributors can be found in the PDF manual)
00017 
00018    License:         MIT (X11), see file LICENSE in the base directory
00019 ============================================================================= */
00020 
00025 #include <vector>
00026 #include <cmath>
00027 #include <iostream>
00028 #include "viennacl/forwards.h"
00029 #include "viennacl/tools/tools.hpp"
00030 
00031 #include "viennacl/linalg/detail/ilu/common.hpp"
00032 #include "viennacl/compressed_matrix.hpp"
00033 
00034 #include "viennacl/linalg/host_based/common.hpp"
00035 
00036 #include <map>
00037 
00038 namespace viennacl
00039 {
00040   namespace linalg
00041   {
00042 
00045     class ilut_tag
00046     {
00047       public:
00054         ilut_tag(unsigned int entries_per_row = 20,
00055                  double drop_tolerance = 1e-4,
00056                  bool with_level_scheduling = false) : entries_per_row_(entries_per_row), drop_tolerance_(drop_tolerance), use_level_scheduling_(with_level_scheduling) {}
00057 
00058         void set_drop_tolerance(double tol)
00059         {
00060           if (tol > 0)
00061             drop_tolerance_ = tol;
00062         }
00063         double get_drop_tolerance() const { return drop_tolerance_; }
00064 
00065         void set_entries_per_row(unsigned int e)
00066         {
00067           if (e > 0)
00068             entries_per_row_ = e;
00069         }
00070 
00071         unsigned int get_entries_per_row() const { return entries_per_row_; }
00072 
00073         bool use_level_scheduling() const { return use_level_scheduling_; }
00074         void use_level_scheduling(bool b) { use_level_scheduling_ = b; }
00075 
00076       private:
00077         unsigned int entries_per_row_;
00078         double drop_tolerance_;
00079         bool use_level_scheduling_;
00080     };
00081 
00082 
00084     template <typename ScalarType, typename SizeType, typename SparseVector>
00085     ScalarType setup_w(viennacl::compressed_matrix<ScalarType> const & A,
00086                        SizeType row,
00087                        SparseVector & w)
00088     {
00089       assert( (A.handle1().get_active_handle_id() == viennacl::MAIN_MEMORY) && bool("System matrix must reside in main memory for ILU0") );
00090       assert( (A.handle2().get_active_handle_id() == viennacl::MAIN_MEMORY) && bool("System matrix must reside in main memory for ILU0") );
00091       assert( (A.handle().get_active_handle_id() == viennacl::MAIN_MEMORY) && bool("System matrix must reside in main memory for ILU0") );
00092 
00093       ScalarType   const * elements   = viennacl::linalg::host_based::detail::extract_raw_pointer<ScalarType>(A.handle());
00094       unsigned int const * row_buffer = viennacl::linalg::host_based::detail::extract_raw_pointer<unsigned int>(A.handle1());
00095       unsigned int const * col_buffer = viennacl::linalg::host_based::detail::extract_raw_pointer<unsigned int>(A.handle2());
00096 
00097       SizeType row_i_begin = static_cast<SizeType>(row_buffer[row]);
00098       SizeType row_i_end   = static_cast<SizeType>(row_buffer[row+1]);
00099       ScalarType row_norm = 0;
00100       for (SizeType buf_index_i = row_i_begin; buf_index_i < row_i_end; ++buf_index_i) //Note: We do not assume that the column indices within a row are sorted
00101       {
00102         ScalarType entry = elements[buf_index_i];
00103         w[col_buffer[buf_index_i]] = entry;
00104         row_norm += entry * entry;
00105       }
00106       return std::sqrt(row_norm);
00107     }
00108 
00110     template <typename ScalarType, typename SizeType, typename SparseVector>
00111     ScalarType setup_w(std::vector< std::map<SizeType, ScalarType> > const & A,
00112                        SizeType row,
00113                        SparseVector & w)
00114     {
00115       ScalarType row_norm = 0;
00116       w = A[row];
00117       for (typename std::map<SizeType, ScalarType>::const_iterator iter_w  = w.begin(); iter_w != w.end(); ++iter_w)
00118         row_norm += iter_w->second * iter_w->second;
00119 
00120       return std::sqrt(row_norm);
00121     }
00122 
00123 
00132     template<typename SparseMatrixType, typename ScalarType, typename SizeType>
00133     void precondition(SparseMatrixType const & A,
00134                       std::vector< std::map<SizeType, ScalarType> > & output,
00135                       ilut_tag const & tag)
00136     {
00137       typedef std::map<SizeType, ScalarType>          SparseVector;
00138       typedef typename SparseVector::iterator         SparseVectorIterator;
00139       typedef typename std::map<SizeType, ScalarType>::const_iterator   OutputRowConstIterator;
00140       typedef std::multimap<ScalarType, std::pair<SizeType, ScalarType> >  TemporarySortMap;
00141 
00142       assert(viennacl::traits::size1(A) == output.size() && bool("Output matrix size mismatch") );
00143 
00144       SparseVector w;
00145       TemporarySortMap temp_map;
00146 
00147       for (SizeType i=0; i<viennacl::traits::size1(A); ++i)  // Line 1
00148       {
00149     /*    if (i%10 == 0)
00150       std::cout << i << std::endl;*/
00151 
00152         //line 2: set up w
00153         ScalarType row_norm = setup_w(A, i, w);
00154         ScalarType tau_i = static_cast<ScalarType>(tag.get_drop_tolerance()) * row_norm;
00155 
00156         //line 3:
00157         for (SparseVectorIterator w_k = w.begin(); w_k != w.end(); ++w_k)
00158         {
00159           SizeType k = w_k->first;
00160           if (k >= i)
00161             break;
00162 
00163           //line 4:
00164           ScalarType a_kk = output[k][k];
00165           if (a_kk == 0)
00166           {
00167             std::cerr << "ViennaCL: FATAL ERROR in ILUT(): Diagonal entry is zero in row " << k
00168                       << " while processing line " << i << "!" << std::endl;
00169             throw "ILUT zero diagonal!";
00170           }
00171 
00172           ScalarType w_k_entry = w_k->second / a_kk;
00173           w_k->second = w_k_entry;
00174 
00175           //line 5: (dropping rule to w_k)
00176           if ( std::fabs(w_k_entry) > tau_i)
00177           {
00178             //line 7:
00179             for (OutputRowConstIterator u_k = output[k].begin(); u_k != output[k].end(); ++u_k)
00180             {
00181               if (u_k->first > k)
00182                 w[u_k->first] -= w_k_entry * u_k->second;
00183             }
00184           }
00185           //else
00186           //  w.erase(k);
00187 
00188         } //for w_k
00189 
00190         //Line 10: Apply a dropping rule to w
00191         //Sort entries which are kept
00192         temp_map.clear();
00193         for (SparseVectorIterator w_k = w.begin(); w_k != w.end(); ++w_k)
00194         {
00195           SizeType k = w_k->first;
00196           ScalarType w_k_entry = w_k->second;
00197 
00198           ScalarType abs_w_k = std::fabs(w_k_entry);
00199           if ( (abs_w_k > tau_i) || (k == i) )//do not drop diagonal element!
00200           {
00201 
00202             if (abs_w_k == 0) // this can only happen for diagonal entry
00203               throw "Triangular factor in ILUT singular!";
00204 
00205             temp_map.insert(std::make_pair(abs_w_k, std::make_pair(k, w_k_entry)));
00206           }
00207         }
00208 
00209         //Lines 10-12: write the largest p values to L and U
00210         SizeType written_L = 0;
00211         SizeType written_U = 0;
00212         for (typename TemporarySortMap::reverse_iterator iter = temp_map.rbegin(); iter != temp_map.rend(); ++iter)
00213         {
00214           std::map<SizeType, ScalarType> & row_i = output[i];
00215           SizeType j = (iter->second).first;
00216           ScalarType w_j_entry = (iter->second).second;
00217 
00218           if (j < i) // Line 11: entry for L
00219           {
00220             if (written_L < tag.get_entries_per_row())
00221             {
00222               row_i[j] = w_j_entry;
00223               ++written_L;
00224             }
00225           }
00226           else if (j == i)  // Diagonal entry is always kept
00227           {
00228             row_i[j] = w_j_entry;
00229           }
00230           else //Line 12: entry for U
00231           {
00232             if (written_U < tag.get_entries_per_row())
00233             {
00234               row_i[j] = w_j_entry;
00235               ++written_U;
00236             }
00237           }
00238         }
00239 
00240         w.clear(); //Line 13
00241 
00242       } //for i
00243     }
00244 
00245 
00248     template <typename MatrixType>
00249     class ilut_precond
00250     {
00251       typedef typename MatrixType::value_type      ScalarType;
00252 
00253       public:
00254         ilut_precond(MatrixType const & mat, ilut_tag const & tag) : tag_(tag), LU(mat.size1(), mat.size2())
00255         {
00256           //initialize preconditioner:
00257           //std::cout << "Start CPU precond" << std::endl;
00258           init(mat);
00259           //std::cout << "End CPU precond" << std::endl;
00260         }
00261 
00262         template <typename VectorType>
00263         void apply(VectorType & vec) const
00264         {
00265           //Note: Since vec can be a rather arbitrary vector type, we call the more generic version in the backend manually:
00266           unsigned int const * row_buffer = viennacl::linalg::host_based::detail::extract_raw_pointer<unsigned int>(LU.handle1());
00267           unsigned int const * col_buffer = viennacl::linalg::host_based::detail::extract_raw_pointer<unsigned int>(LU.handle2());
00268           ScalarType   const * elements   = viennacl::linalg::host_based::detail::extract_raw_pointer<ScalarType>(LU.handle());
00269 
00270           viennacl::linalg::host_based::detail::csr_inplace_solve<ScalarType>(row_buffer, col_buffer, elements, vec, LU.size2(), unit_lower_tag());
00271           viennacl::linalg::host_based::detail::csr_inplace_solve<ScalarType>(row_buffer, col_buffer, elements, vec, LU.size2(), upper_tag());
00272         }
00273 
00274       private:
00275         void init(MatrixType const & mat)
00276         {
00277           viennacl::context host_context(viennacl::MAIN_MEMORY);
00278           viennacl::compressed_matrix<ScalarType> temp;
00279           viennacl::switch_memory_context(temp, host_context);
00280 
00281           viennacl::copy(mat, temp);
00282 
00283           std::vector< std::map<unsigned int, ScalarType> > LU_temp(mat.size1());
00284 
00285           viennacl::linalg::precondition(temp, LU_temp, tag_);
00286 
00287           viennacl::switch_memory_context(LU, host_context);
00288           viennacl::copy(LU_temp, LU);
00289         }
00290 
00291         ilut_tag const & tag_;
00292         viennacl::compressed_matrix<ScalarType> LU;
00293     };
00294 
00295 
00300     template <typename ScalarType, unsigned int MAT_ALIGNMENT>
00301     class ilut_precond< compressed_matrix<ScalarType, MAT_ALIGNMENT> >
00302     {
00303       typedef compressed_matrix<ScalarType, MAT_ALIGNMENT>   MatrixType;
00304 
00305       public:
00306         ilut_precond(MatrixType const & mat, ilut_tag const & tag) : tag_(tag), LU(mat.size1(), mat.size2())
00307         {
00308           //initialize preconditioner:
00309           //std::cout << "Start GPU precond" << std::endl;
00310           init(mat);
00311           //std::cout << "End GPU precond" << std::endl;
00312         }
00313 
00314         void apply(vector<ScalarType> & vec) const
00315         {
00316           if (vec.handle().get_active_handle_id() != viennacl::MAIN_MEMORY)
00317           {
00318             if (tag_.use_level_scheduling())
00319             {
00320               //std::cout << "Using multifrontal on GPU..." << std::endl;
00321               detail::level_scheduling_substitute(vec,
00322                                                   multifrontal_L_row_index_arrays_,
00323                                                   multifrontal_L_row_buffers_,
00324                                                   multifrontal_L_col_buffers_,
00325                                                   multifrontal_L_element_buffers_,
00326                                                   multifrontal_L_row_elimination_num_list_);
00327 
00328               vec = viennacl::linalg::element_div(vec, multifrontal_U_diagonal_);
00329 
00330               detail::level_scheduling_substitute(vec,
00331                                                   multifrontal_U_row_index_arrays_,
00332                                                   multifrontal_U_row_buffers_,
00333                                                   multifrontal_U_col_buffers_,
00334                                                   multifrontal_U_element_buffers_,
00335                                                   multifrontal_U_row_elimination_num_list_);
00336             }
00337             else
00338             {
00339               viennacl::context host_context(viennacl::MAIN_MEMORY);
00340               viennacl::context old_context = viennacl::traits::context(vec);
00341               viennacl::switch_memory_context(vec, host_context);
00342               viennacl::linalg::inplace_solve(LU, vec, unit_lower_tag());
00343               viennacl::linalg::inplace_solve(LU, vec, upper_tag());
00344               viennacl::switch_memory_context(vec, old_context);
00345             }
00346           }
00347           else //apply ILUT directly:
00348           {
00349             viennacl::linalg::inplace_solve(LU, vec, unit_lower_tag());
00350             viennacl::linalg::inplace_solve(LU, vec, upper_tag());
00351           }
00352         }
00353 
00354       private:
00355         void init(MatrixType const & mat)
00356         {
00357           viennacl::context host_context(viennacl::MAIN_MEMORY);
00358           viennacl::switch_memory_context(LU, host_context);
00359 
00360           std::vector< std::map<unsigned int, ScalarType> > LU_temp(mat.size1());
00361 
00362           if (viennacl::traits::context(mat).memory_type() == viennacl::MAIN_MEMORY)
00363           {
00364             viennacl::linalg::precondition(mat, LU_temp, tag_);
00365           }
00366           else //we need to copy to CPU
00367           {
00368             viennacl::compressed_matrix<ScalarType> cpu_mat(mat.size1(), mat.size2());
00369             viennacl::switch_memory_context(cpu_mat, host_context);
00370 
00371             cpu_mat = mat;
00372 
00373             viennacl::linalg::precondition(cpu_mat, LU_temp, tag_);
00374           }
00375 
00376           viennacl::copy(LU_temp, LU);
00377 
00378           if (!tag_.use_level_scheduling())
00379             return;
00380 
00381           //
00382           // multifrontal part:
00383           //
00384 
00385           viennacl::switch_memory_context(multifrontal_U_diagonal_, host_context);
00386           multifrontal_U_diagonal_.resize(LU.size1(), false);
00387           host_based::detail::row_info(LU, multifrontal_U_diagonal_, viennacl::linalg::detail::SPARSE_ROW_DIAGONAL);
00388 
00389           detail::level_scheduling_setup_L(LU,
00390                                            multifrontal_U_diagonal_, //dummy
00391                                            multifrontal_L_row_index_arrays_,
00392                                            multifrontal_L_row_buffers_,
00393                                            multifrontal_L_col_buffers_,
00394                                            multifrontal_L_element_buffers_,
00395                                            multifrontal_L_row_elimination_num_list_);
00396 
00397 
00398           detail::level_scheduling_setup_U(LU,
00399                                            multifrontal_U_diagonal_,
00400                                            multifrontal_U_row_index_arrays_,
00401                                            multifrontal_U_row_buffers_,
00402                                            multifrontal_U_col_buffers_,
00403                                            multifrontal_U_element_buffers_,
00404                                            multifrontal_U_row_elimination_num_list_);
00405 
00406           //
00407           // Bring to device if necessary:
00408           //
00409 
00410           // L:
00411 
00412           for (typename std::list< viennacl::backend::mem_handle >::iterator it  = multifrontal_L_row_index_arrays_.begin();
00413                                                                              it != multifrontal_L_row_index_arrays_.end();
00414                                                                            ++it)
00415             viennacl::backend::switch_memory_context<unsigned int>(*it, viennacl::traits::context(mat));
00416 
00417           for (typename std::list< viennacl::backend::mem_handle >::iterator it  = multifrontal_L_row_buffers_.begin();
00418                                                                              it != multifrontal_L_row_buffers_.end();
00419                                                                            ++it)
00420             viennacl::backend::switch_memory_context<unsigned int>(*it, viennacl::traits::context(mat));
00421 
00422           for (typename std::list< viennacl::backend::mem_handle >::iterator it  = multifrontal_L_col_buffers_.begin();
00423                                                                              it != multifrontal_L_col_buffers_.end();
00424                                                                            ++it)
00425             viennacl::backend::switch_memory_context<unsigned int>(*it, viennacl::traits::context(mat));
00426 
00427           for (typename std::list< viennacl::backend::mem_handle >::iterator it  = multifrontal_L_element_buffers_.begin();
00428                                                                              it != multifrontal_L_element_buffers_.end();
00429                                                                            ++it)
00430             viennacl::backend::switch_memory_context<ScalarType>(*it, viennacl::traits::context(mat));
00431 
00432 
00433           // U:
00434 
00435           viennacl::switch_memory_context(multifrontal_U_diagonal_, viennacl::traits::context(mat));
00436 
00437           for (typename std::list< viennacl::backend::mem_handle >::iterator it  = multifrontal_U_row_index_arrays_.begin();
00438                                                                              it != multifrontal_U_row_index_arrays_.end();
00439                                                                            ++it)
00440             viennacl::backend::switch_memory_context<unsigned int>(*it, viennacl::traits::context(mat));
00441 
00442           for (typename std::list< viennacl::backend::mem_handle >::iterator it  = multifrontal_U_row_buffers_.begin();
00443                                                                              it != multifrontal_U_row_buffers_.end();
00444                                                                            ++it)
00445             viennacl::backend::switch_memory_context<unsigned int>(*it, viennacl::traits::context(mat));
00446 
00447           for (typename std::list< viennacl::backend::mem_handle >::iterator it  = multifrontal_U_col_buffers_.begin();
00448                                                                              it != multifrontal_U_col_buffers_.end();
00449                                                                            ++it)
00450             viennacl::backend::switch_memory_context<unsigned int>(*it, viennacl::traits::context(mat));
00451 
00452           for (typename std::list< viennacl::backend::mem_handle >::iterator it  = multifrontal_U_element_buffers_.begin();
00453                                                                              it != multifrontal_U_element_buffers_.end();
00454                                                                            ++it)
00455             viennacl::backend::switch_memory_context<ScalarType>(*it, viennacl::traits::context(mat));
00456 
00457 
00458         }
00459 
00460         ilut_tag const & tag_;
00461         viennacl::compressed_matrix<ScalarType> LU;
00462 
00463         std::list< viennacl::backend::mem_handle > multifrontal_L_row_index_arrays_;
00464         std::list< viennacl::backend::mem_handle > multifrontal_L_row_buffers_;
00465         std::list< viennacl::backend::mem_handle > multifrontal_L_col_buffers_;
00466         std::list< viennacl::backend::mem_handle > multifrontal_L_element_buffers_;
00467         std::list< vcl_size_t > multifrontal_L_row_elimination_num_list_;
00468 
00469         viennacl::vector<ScalarType> multifrontal_U_diagonal_;
00470         std::list< viennacl::backend::mem_handle > multifrontal_U_row_index_arrays_;
00471         std::list< viennacl::backend::mem_handle > multifrontal_U_row_buffers_;
00472         std::list< viennacl::backend::mem_handle > multifrontal_U_col_buffers_;
00473         std::list< viennacl::backend::mem_handle > multifrontal_U_element_buffers_;
00474         std::list< vcl_size_t > multifrontal_U_row_elimination_num_list_;
00475     };
00476 
00477   }
00478 }
00479 
00480 
00481 
00482 
00483 #endif
00484 
00485 
00486