00001 #ifndef VIENNACL_LINALG_ILU_HPP_
00002 #define VIENNACL_LINALG_ILU_HPP_
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00024 #include <vector>
00025 #include <cmath>
00026 #include "viennacl/forwards.h"
00027 #include "viennacl/tools/tools.hpp"
00028
00029 #include <map>
00030
00031 namespace viennacl
00032 {
00033 namespace linalg
00034 {
00035
00038 class ilut_tag
00039 {
00040 public:
00046 ilut_tag(unsigned int entries_per_row = 20,
00047 double drop_tolerance = 1e-4) : _entries_per_row(entries_per_row), _drop_tolerance(drop_tolerance) {};
00048
00049 void set_drop_tolerance(double tol)
00050 {
00051 if (tol > 0)
00052 _drop_tolerance = tol;
00053 }
00054 double get_drop_tolerance() const { return _drop_tolerance; }
00055
00056 void set_entries_per_row(unsigned int e)
00057 {
00058 if (e > 0)
00059 _entries_per_row = e;
00060 }
00061
00062 unsigned int get_entries_per_row() const { return _entries_per_row; }
00063
00064 private:
00065 unsigned int _entries_per_row;
00066 double _drop_tolerance;
00067 };
00068
00069
00077 template <typename T>
00078 void ilut_inc_row_iterator_to_row_index(T & row_iter, unsigned int k)
00079 {
00080 while (row_iter.index1() < k)
00081 ++row_iter;
00082 }
00083
00091 template <typename ScalarType>
00092 void ilut_inc_row_iterator_to_row_index(viennacl::tools::sparse_matrix_adapter<ScalarType> & row_iter, unsigned int k)
00093 {
00094 row_iter += k - row_iter.index1();
00095 }
00096
00104 template <typename ScalarType>
00105 void ilut_inc_row_iterator_to_row_index(viennacl::tools::const_sparse_matrix_adapter<ScalarType> & row_iter, unsigned int k)
00106 {
00107 row_iter += k - row_iter.index1();
00108 }
00109
00110
00119 template<typename MatrixType, typename LUType>
00120 void precondition(MatrixType const & input, LUType & output, ilut_tag const & tag)
00121 {
00122 typedef std::map<unsigned int, double> SparseVector;
00123 typedef typename SparseVector::iterator SparseVectorIterator;
00124 typedef typename MatrixType::const_iterator1 InputRowIterator;
00125 typedef typename MatrixType::const_iterator2 InputColIterator;
00126 typedef typename LUType::iterator1 OutputRowIterator;
00127 typedef typename LUType::iterator2 OutputColIterator;
00128
00129 output.clear();
00130 assert(input.size1() == output.size1());
00131 assert(input.size2() == output.size2());
00132 output.resize(static_cast<unsigned int>(input.size1()), static_cast<unsigned int>(input.size2()), false);
00133 SparseVector w;
00134
00135 std::map<double, unsigned int> temp_map;
00136
00137 for (InputRowIterator row_iter = input.begin1(); row_iter != input.end1(); ++row_iter)
00138 {
00139
00140
00141
00142
00143 w.clear();
00144 for (InputColIterator col_iter = row_iter.begin(); col_iter != row_iter.end(); ++col_iter)
00145 w[static_cast<unsigned int>(col_iter.index2())] = *col_iter;
00146
00147
00148 OutputRowIterator row_iter_out = output.begin1();
00149 for (SparseVectorIterator k = w.begin(); k != w.end();)
00150 {
00151 unsigned int index_k = k->first;
00152 if (index_k >= static_cast<unsigned int>(row_iter.index1()))
00153 break;
00154
00155
00156
00157
00158
00159
00160 ilut_inc_row_iterator_to_row_index(row_iter_out, index_k);
00161
00162
00163 double temp = k->second / output(index_k, index_k);
00164 if (output(index_k, index_k) == 0.0)
00165 {
00166 std::cerr << "ViennaCL: FATAL ERROR in ILUT(): Diagonal entry is zero in row " << index_k << "!" << std::endl;
00167 }
00168
00169
00170 if ( fabs(temp) > tag.get_drop_tolerance())
00171 {
00172
00173 for (OutputColIterator j = row_iter_out.begin(); j != row_iter_out.end(); ++j)
00174 {
00175 if (j.index2() > index_k)
00176 {
00177 w[j.index2()] -= temp * *j;
00178 }
00179 }
00180 ++k;
00181 w[index_k] = temp;
00182 }
00183 else
00184 ++k;
00185 }
00186
00187
00188
00189 temp_map.clear();
00190 for (SparseVectorIterator k = w.begin(); k != w.end(); )
00191 {
00192 if (fabs(k->second) < tag.get_drop_tolerance())
00193 {
00194 long index = k->first;
00195 ++k;
00196 w.erase(index);
00197 }
00198 else
00199 {
00200 double temp = fabs(k->second);
00201 while (temp_map.find(temp) != temp_map.end())
00202 temp *= 1.00000001;
00203 temp_map[temp] = k->first;
00204 ++k;
00205 }
00206 }
00207
00208
00209 unsigned int written_L = 0;
00210 unsigned int written_U = 0;
00211 for (typename std::map<double, unsigned int>::reverse_iterator iter = temp_map.rbegin(); iter != temp_map.rend(); ++iter)
00212 {
00213 if (iter->second > static_cast<unsigned int>(row_iter.index1()))
00214 {
00215 if (written_U < tag.get_entries_per_row())
00216 {
00217 output(static_cast<unsigned int>(row_iter.index1()), iter->second) = static_cast<typename LUType::value_type>(w[iter->second]);
00218 ++written_U;
00219 }
00220 }
00221 else if (iter->second == static_cast<unsigned int>(row_iter.index1()))
00222 {
00223 output(iter->second, iter->second) = static_cast<typename LUType::value_type>(w[static_cast<unsigned int>(row_iter.index1())]);
00224 }
00225 else
00226 {
00227 if (written_L < tag.get_entries_per_row())
00228 {
00229 output(static_cast<unsigned int>(row_iter.index1()), iter->second) = static_cast<typename LUType::value_type>(w[iter->second]);
00230 ++written_L;
00231 }
00232 }
00233 }
00234 }
00235 }
00236
00237
00243 template<typename MatrixType, typename VectorType>
00244 void ilu_inplace_solve(MatrixType const & mat, VectorType & vec, viennacl::linalg::unit_lower_tag)
00245 {
00246 typedef typename MatrixType::const_iterator1 InputRowIterator;
00247 typedef typename MatrixType::const_iterator2 InputColIterator;
00248
00249 for (InputRowIterator row_iter = mat.begin1(); row_iter != mat.end1(); ++row_iter)
00250 {
00251 for (InputColIterator col_iter = row_iter.begin(); col_iter != row_iter.end(); ++col_iter)
00252 {
00253 if (col_iter.index2() < col_iter.index1())
00254 vec[col_iter.index1()] -= *col_iter * vec[col_iter.index2()];
00255 }
00256 }
00257 }
00258
00264 template<typename MatrixType, typename VectorType>
00265 void ilu_inplace_solve(MatrixType const & mat, VectorType & vec, viennacl::linalg::upper_tag)
00266 {
00267 typedef typename MatrixType::const_reverse_iterator1 InputRowIterator;
00268 typedef typename MatrixType::const_iterator2 InputColIterator;
00269 typedef typename VectorType::value_type ScalarType;
00270
00271 ScalarType diagonal_entry = 1.0;
00272
00273 for (InputRowIterator row_iter = mat.rbegin1(); row_iter != mat.rend1(); ++row_iter)
00274 {
00275 for (InputColIterator col_iter = row_iter.begin(); col_iter != row_iter.end(); ++col_iter)
00276 {
00277 if (col_iter.index2() > col_iter.index1())
00278 vec[col_iter.index1()] -= *col_iter * vec[col_iter.index2()];
00279 if (col_iter.index2() == col_iter.index1())
00280 diagonal_entry = *col_iter;
00281 }
00282 vec[row_iter.index1()] /= diagonal_entry;
00283 }
00284 }
00285
00291 template<typename MatrixType, typename VectorType>
00292 void ilu_lu_substitute(MatrixType const & mat, VectorType & vec)
00293 {
00294 ilu_inplace_solve(mat, vec, unit_lower_tag());
00295 ilu_inplace_solve(mat, vec, upper_tag());
00296 }
00297
00298
00301 template <typename MatrixType>
00302 class ilut_precond
00303 {
00304 typedef typename MatrixType::value_type ScalarType;
00305
00306 public:
00307 ilut_precond(MatrixType const & mat, ilut_tag const & tag) : _tag(tag), LU(mat.size1())
00308 {
00309
00310
00311 init(mat);
00312
00313 }
00314
00315 template <typename VectorType>
00316 void apply(VectorType & vec) const
00317 {
00318 viennacl::tools::const_sparse_matrix_adapter<ScalarType> LU_const_adapter(LU);
00319 viennacl::linalg::ilu_lu_substitute(LU_const_adapter, vec);
00320 }
00321
00322 private:
00323 void init(MatrixType const & mat)
00324 {
00325 viennacl::tools::sparse_matrix_adapter<ScalarType> LU_adapter(LU);
00326 viennacl::linalg::precondition(mat, LU_adapter, _tag);
00327 }
00328
00329 ilut_tag const & _tag;
00330 std::vector< std::map<unsigned int, ScalarType> > LU;
00331 };
00332
00333
00338 template <typename ScalarType, unsigned int MAT_ALIGNMENT>
00339 class ilut_precond< compressed_matrix<ScalarType, MAT_ALIGNMENT> >
00340 {
00341 typedef compressed_matrix<ScalarType, MAT_ALIGNMENT> MatrixType;
00342
00343 public:
00344 ilut_precond(MatrixType const & mat, ilut_tag const & tag) : _tag(tag), LU(mat.size1())
00345 {
00346
00347
00348 init(mat);
00349
00350 }
00351
00352 void apply(vector<ScalarType> & vec) const
00353 {
00354 copy(vec, temp_vec);
00355
00356 viennacl::tools::const_sparse_matrix_adapter<ScalarType> LU_const_adapter(LU);
00357 viennacl::linalg::ilu_lu_substitute(LU_const_adapter, temp_vec);
00358
00359 copy(temp_vec, vec);
00360 }
00361
00362 private:
00363 void init(MatrixType const & mat)
00364 {
00365 std::vector< std::map<unsigned int, ScalarType> > temp(mat.size1());
00366
00367
00368
00369 copy(mat, temp);
00370
00371 viennacl::tools::const_sparse_matrix_adapter<ScalarType> temp_adapter(temp);
00372 viennacl::tools::sparse_matrix_adapter<ScalarType> LU_adapter(LU);
00373 viennacl::linalg::precondition(temp_adapter, LU_adapter, _tag);
00374
00375 temp_vec.resize(mat.size1());
00376
00377
00378
00379 }
00380
00381 ilut_tag const & _tag;
00382
00383 std::vector< std::map<unsigned int, ScalarType> > LU;
00384 mutable std::vector<ScalarType> temp_vec;
00385 };
00386
00387 }
00388 }
00389
00390
00391
00392
00393 #endif
00394
00395
00396