ViennaCL - The Vienna Computing Library
1.5.2
|
00001 #ifndef VIENNACL_LINALG_DETAIL_ILUT_HPP_ 00002 #define VIENNACL_LINALG_DETAIL_ILUT_HPP_ 00003 00004 /* ========================================================================= 00005 Copyright (c) 2010-2014, 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