00001 #ifndef VIENNACL_LINALG_DETAIL_AMG_AMG_COARSE_HPP
00002 #define VIENNACL_LINALG_DETAIL_AMG_AMG_COARSE_HPP
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00024 #include <cmath>
00025 #include "viennacl/linalg/amg.hpp"
00026
00027 #include <map>
00028 #ifdef _OPENMP
00029 #include <omp.h>
00030 #endif
00031
00032 #include "amg_debug.hpp"
00033
00034 namespace viennacl
00035 {
00036 namespace linalg
00037 {
00038 namespace detail
00039 {
00040 namespace amg
00041 {
00042
00050 template <typename InternalType1, typename InternalType2, typename InternalType3>
00051 void amg_coarse(unsigned int level, InternalType1 & A, InternalType2 & Pointvector, InternalType3 & Slicing, amg_tag & tag)
00052 {
00053 switch (tag.get_coarse())
00054 {
00055 case VIENNACL_AMG_COARSE_RS: amg_coarse_classic (level, A, Pointvector, tag); break;
00056 case VIENNACL_AMG_COARSE_ONEPASS: amg_coarse_classic_onepass (level, A, Pointvector, tag); break;
00057 case VIENNACL_AMG_COARSE_RS0: amg_coarse_rs0 (level, A, Pointvector, Slicing, tag); break;
00058 case VIENNACL_AMG_COARSE_RS3: amg_coarse_rs3 (level, A, Pointvector, Slicing, tag); break;
00059 case VIENNACL_AMG_COARSE_AG: amg_coarse_ag (level, A, Pointvector, tag); break;
00060 }
00061 }
00062
00069 template <typename InternalType1, typename InternalType2>
00070 void amg_influence(unsigned int level, InternalType1 const & A, InternalType2 & Pointvector, amg_tag & tag)
00071 {
00072 typedef typename InternalType1::value_type SparseMatrixType;
00073 typedef typename InternalType2::value_type PointVectorType;
00074 typedef typename SparseMatrixType::value_type ScalarType;
00075 typedef typename SparseMatrixType::value_type ScalarType;
00076 typedef typename SparseMatrixType::const_iterator1 ConstRowIterator;
00077 typedef typename SparseMatrixType::const_iterator2 ConstColIterator;
00078
00079 ScalarType max;
00080 int diag_sign;
00081
00082
00083 #ifdef _OPENMP
00084 #pragma omp parallel for private (max,diag_sign) shared (A,Pointvector)
00085 #endif
00086 for (unsigned int i=0; i<A[level].size1(); ++i)
00087 {
00088 diag_sign = 1;
00089 if (A[level](i,i) < 0)
00090 diag_sign = -1;
00091
00092 ConstRowIterator row_iter = A[level].begin1();
00093 row_iter += i;
00094
00095 max = 0;
00096 for (ConstColIterator col_iter = row_iter.begin(); col_iter != row_iter.end(); ++col_iter)
00097 {
00098 if (i == (unsigned int) col_iter.index2()) continue;
00099 if (diag_sign == 1)
00100 if (max > *col_iter) max = *col_iter;
00101 if (diag_sign == -1)
00102 if (max < *col_iter) max = *col_iter;
00103 }
00104
00105
00106 if (max == 0)
00107 continue;
00108
00109
00110 for (ConstColIterator col_iter = row_iter.begin(); col_iter != row_iter.end(); ++col_iter)
00111 {
00112 unsigned int j = col_iter.index2();
00113 if (i == j) continue;
00114 if (diag_sign * (-*col_iter) >= tag.get_threshold() * (diag_sign * (-max)))
00115 {
00116
00117 Pointvector[level][i]->add_influencing_point(Pointvector[level][j]);
00118 }
00119 }
00120 }
00121
00122 #ifdef DEBUG
00123 std::cout << "Influence Matrix: " << std::endl;
00124 boost::numeric::ublas::matrix<bool> mat;
00125 Pointvector[level].get_influence_matrix(mat);
00126 printmatrix (mat);
00127 #endif
00128
00129
00130 for (typename PointVectorType::iterator iter = Pointvector[level].begin(); iter != Pointvector[level].end(); ++iter)
00131 {
00132 for (typename amg_point::iterator iter2 = (*iter)->begin_influencing(); iter2 != (*iter)->end_influencing(); ++iter2)
00133 {
00134 (*iter2)->add_influenced_point(*iter);
00135 }
00136 }
00137
00138 #ifdef DEBUG
00139 std::cout << "Influence Measures: " << std::endl;
00140 boost::numeric::ublas::vector<unsigned int> temp;
00141 Pointvector[level].get_influence(temp);
00142 printvector (temp);
00143 std::cout << "Point Sorting: " << std::endl;
00144 Pointvector[level].get_sorting(temp);
00145 printvector (temp);
00146 #endif
00147 }
00148
00155 template <typename InternalType1, typename InternalType2>
00156 void amg_coarse_classic_onepass(unsigned int level, InternalType1 & A, InternalType2 & Pointvector, amg_tag & tag)
00157 {
00158 typedef typename InternalType1::value_type SparseMatrixType;
00159 typedef typename InternalType2::value_type PointVectorType;
00160 typedef typename SparseMatrixType::value_type ScalarType;
00161
00162 typedef typename SparseMatrixType::iterator1 InternalRowIterator;
00163 typedef typename SparseMatrixType::iterator2 InternalColIterator;
00164
00165 amg_point* c_point, *point1, *point2;
00166 unsigned int i;
00167
00168
00169 amg_influence (level, A, Pointvector, tag);
00170
00171
00172 #ifdef _OPENMP
00173 #pragma omp parallel for private (i) shared (Pointvector)
00174 #endif
00175 for (i=0; i<Pointvector[level].size(); ++i)
00176 Pointvector[level][i]->calc_influence();
00177
00178
00179 Pointvector[level].sort();
00180
00181
00182 while ((c_point = Pointvector[level].get_nextpoint()) != NULL)
00183 {
00184
00185 Pointvector[level].make_cpoint(c_point);
00186
00187
00188 for (typename amg_point::iterator iter = c_point->begin_influenced(); iter != c_point->end_influenced(); ++iter)
00189 {
00190 point1 = *iter;
00191
00192 if (!point1->is_undecided()) continue;
00193
00194 Pointvector[level].make_fpoint(point1);
00195
00196
00197 for (typename amg_point::iterator iter2 = point1->begin_influencing(); iter2 != point1->end_influencing(); ++iter2)
00198 {
00199 point2 = *iter2;
00200
00201 if (point2->is_undecided())
00202 Pointvector[level].add_influence(point2,1);
00203 }
00204 }
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224 #if defined (DEBUG)// or defined (DEBUGBENCH)
00225 unsigned int c_points = Pointvector[level].get_cpoints();
00226 unsigned int f_points = Pointvector[level].get_fpoints();
00227 std::cout << "1st pass: Level " << level << ": ";
00228 std::cout << "No of C points = " << c_points << ", ";
00229 std::cout << "No of F points = " << f_points << std::endl;
00230 #endif
00231
00232 #ifdef DEBUG
00233 std::cout << "Coarse Points:" << std::endl;
00234 boost::numeric::ublas::vector<bool> C;
00235 Pointvector[level].get_C(C);
00236 printvector (C);
00237 std::cout << "Fine Points:" << std::endl;
00238 boost::numeric::ublas::vector<bool> F;
00239 Pointvector[level].get_F(F);
00240 printvector (F);
00241 #endif
00242 }
00243
00250 template <typename InternalType1, typename InternalType2>
00251 void amg_coarse_classic(unsigned int level, InternalType1 & A, InternalType2 & Pointvector, amg_tag & tag)
00252 {
00253 typedef typename InternalType1::value_type SparseMatrixType;
00254 typedef typename InternalType2::value_type PointVectorType;
00255 typedef typename SparseMatrixType::value_type ScalarType;
00256
00257 typedef typename SparseMatrixType::iterator1 InternalRowIterator;
00258 typedef typename SparseMatrixType::iterator2 InternalColIterator;
00259
00260 bool add_C;
00261 amg_point *c_point, *point1, *point2;
00262
00263
00264 amg_coarse_classic_onepass(level, A, Pointvector, tag);
00265
00266
00267 for (typename PointVectorType::iterator iter = Pointvector[level].begin(); iter != Pointvector[level].end(); ++iter)
00268 {
00269 point1 = *iter;
00270
00271 if (point1->is_fpoint())
00272 {
00273
00274 amg_point::iterator iter2 = point1->begin_influencing();
00275 amg_point::iterator iter3 = point1->begin_influenced();
00276
00277
00278
00279 while(iter2 != point1->end_influencing() || iter3 != point1->end_influenced())
00280 {
00281 if (iter2 == point1->end_influencing())
00282 {
00283 point2 = *iter3;
00284 ++iter3;
00285 }
00286 else if (iter3 == point1->end_influenced())
00287 {
00288 point2 = *iter2;
00289 ++iter2;
00290 }
00291 else
00292 {
00293 if ((*iter2)->get_index() == (*iter3)->get_index())
00294 {
00295 point2 = *iter2;
00296 ++iter2;
00297 ++iter3;
00298 }
00299 else if ((*iter2)->get_index() < (*iter3)->get_index())
00300 {
00301 point2 = *iter2;
00302 ++iter2;
00303 }
00304 else
00305 {
00306 point2 = *iter3;
00307 ++iter3;
00308 }
00309 }
00310
00311 if (point2->get_index() < point1->get_index())
00312 continue;
00313
00314
00315
00316 if (point2->is_cpoint())
00317 continue;
00318
00319 if (point2->is_fpoint())
00320 {
00321 add_C = true;
00322
00323
00324 for (amg_point::iterator iter3 = point1->begin_influencing(); iter3 != point1 -> end_influencing(); ++iter3)
00325 {
00326 c_point = *iter3;
00327
00328 if (c_point->is_cpoint())
00329 {
00330 if (point2->is_influencing(c_point))
00331 {
00332 add_C = false;
00333 break;
00334 }
00335 }
00336 }
00337
00338 if (add_C == true)
00339 Pointvector[level].switch_ftoc(point2);
00340 }
00341 }
00342 }
00343 }
00344
00345 #ifdef DEBUG
00346 std::cout << "After 2nd pass:" << std::endl;
00347 std::cout << "Coarse Points:" << std::endl;
00348 boost::numeric::ublas::vector<bool> C;
00349 Pointvector[level].get_C(C);
00350 printvector (C);
00351 std::cout << "Fine Points:" << std::endl;
00352 boost::numeric::ublas::vector<bool> F;
00353 Pointvector[level].get_F(F);
00354 printvector (F);
00355 #endif
00356
00357 #ifdef DEBUG
00358 #ifdef _OPENMP
00359 #pragma omp critical
00360 #endif
00361 {
00362 std::cout << "No C and no F point: ";
00363 for (typename PointVectorType::iterator iter = Pointvector[level].begin(); iter != Pointvector[level].end(); ++iter)
00364 if ((*iter)->is_undecided())
00365 std::cout << (*iter)->get_index() << " ";
00366 std::cout << std::endl;
00367 }
00368 #endif
00369 }
00370
00378 template <typename InternalType1, typename InternalType2, typename InternalType3>
00379 void amg_coarse_rs0(unsigned int level, InternalType1 & A, InternalType2 & Pointvector, InternalType3 & Slicing, amg_tag & tag)
00380 {
00381 typedef typename InternalType1::value_type SparseMatrixType;
00382 typedef typename InternalType2::value_type PointVectorType;
00383 typedef typename SparseMatrixType::value_type ScalarType;
00384
00385 typedef typename SparseMatrixType::iterator1 InternalRowIterator;
00386 typedef typename SparseMatrixType::iterator2 InternalColIterator;
00387
00388 unsigned int total_points;
00389
00390
00391 Slicing.slice(level, A, Pointvector);
00392
00393
00394 total_points = 0;
00395 #ifdef _OPENMP
00396 #pragma omp parallel for shared (total_points,Slicing,level)
00397 #endif
00398 for (unsigned int i=0; i<Slicing._threads; ++i)
00399 {
00400 amg_coarse_classic(level,Slicing.A_slice[i],Slicing.Pointvector_slice[i],tag);
00401
00402
00403
00404 Slicing.Offset[i+1][level+1] = Slicing.Pointvector_slice[i][level].get_cpoints();
00405 #ifdef _OPENMP
00406 #pragma omp critical
00407 #endif
00408 total_points += Slicing.Pointvector_slice[i][level].get_cpoints();
00409 }
00410
00411
00412 if (total_points != 0)
00413 {
00414 #ifdef _OPENMP
00415 #pragma omp parallel for shared (Slicing)
00416 #endif
00417 for (unsigned int i=0; i<Slicing._threads; ++i)
00418 {
00419
00420 if (Slicing.Offset[i+1][level+1] == 0)
00421 {
00422
00423 for (unsigned int j=0; j<Slicing.A_slice[i][level].size1(); ++j)
00424 Slicing.Pointvector_slice[i][level].make_cpoint(Slicing.Pointvector_slice[i][level][j]);
00425 Slicing.Offset[i+1][level+1] = Slicing.A_slice[i][level].size1();
00426 }
00427 }
00428
00429
00430 for (unsigned int i=2; i<=Slicing._threads; ++i)
00431 Slicing.Offset[i][level+1] += Slicing.Offset[i-1][level+1];
00432
00433
00434 Slicing.join(level, Pointvector);
00435 }
00436
00437
00438 amg_influence(level, A, Pointvector, tag);
00439
00440 #if defined(DEBUG)// or defined (DEBUGBENCH)
00441 for (unsigned int i=0; i<Slicing._threads; ++i)
00442 {
00443 unsigned int c_points = Slicing.Pointvector_slice[i][level].get_cpoints();
00444 unsigned int f_points = Slicing.Pointvector_slice[i][level].get_fpoints();
00445 std::cout << "Thread " << i << ": ";
00446 std::cout << "No of C points = " << c_points << ", ";
00447 std::cout << "No of F points = " << f_points << std::endl;
00448 }
00449 #endif
00450 }
00451
00459 template <typename InternalType1, typename InternalType2, typename InternalType3>
00460 void amg_coarse_rs3(unsigned int level, InternalType1 & A, InternalType2 & Pointvector, InternalType3 & Slicing, amg_tag & tag)
00461 {
00462 typedef typename InternalType1::value_type SparseMatrixType;
00463 typedef typename InternalType2::value_type PointVectorType;
00464 typedef typename SparseMatrixType::value_type ScalarType;
00465
00466 typedef typename SparseMatrixType::iterator1 InternalRowIterator;
00467 typedef typename SparseMatrixType::iterator2 InternalColIterator;
00468
00469 amg_point *c_point, *point1, *point2;
00470 bool add_C;
00471 unsigned int i, j;
00472
00473
00474 amg_coarse_rs0(level, A, Pointvector, Slicing, tag);
00475
00476
00477 boost::numeric::ublas::vector<unsigned int> Offset = boost::numeric::ublas::vector<unsigned int> (Slicing.Offset.size());
00478 for (i=0; i<Slicing.Offset.size(); ++i)
00479 Offset[i] = Slicing.Offset[i][level];
00480
00481
00482 for (i=0; i<Slicing._threads; ++i)
00483 {
00484
00485 for (j=Offset[i]; j<Offset[i+1]; ++j)
00486 {
00487 point1 = Pointvector[level][j];
00488
00489 if (point1->is_fpoint())
00490 {
00491
00492 amg_point::iterator iter2 = point1->begin_influencing();
00493 amg_point::iterator iter3 = point1->begin_influenced();
00494
00495
00496
00497 while(iter2 != point1->end_influencing() || iter3 != point1->end_influenced())
00498 {
00499 if (iter2 == point1->end_influencing())
00500 {
00501 point2 = *iter3;
00502 ++iter3;
00503 }
00504 else if (iter3 == point1->end_influenced())
00505 {
00506 point2 = *iter2;
00507 ++iter2;
00508 }
00509 else
00510 {
00511 if ((*iter2)->get_index() == (*iter3)->get_index())
00512 {
00513 point2 = *iter2;
00514 ++iter2;
00515 ++iter3;
00516 }
00517 else if ((*iter2)->get_index() < (*iter3)->get_index())
00518 {
00519 point2 = *iter2;
00520 ++iter2;
00521 }
00522 else
00523 {
00524 point2 = *iter3;
00525 ++iter3;
00526 }
00527 }
00528
00529
00530 if (point2->get_index() < point1->get_index())
00531 continue;
00532
00533
00534
00535 if (point2->get_index() >= Offset[i] && point2->get_index() < Offset[i+1])
00536 continue;
00537
00538
00539
00540 if (point2->is_cpoint())
00541 continue;
00542
00543 if (point2->is_fpoint())
00544 {
00545 add_C = true;
00546
00547
00548 for (amg_point::iterator iter3 = point1->begin_influencing(); iter3 != point1 -> end_influencing(); ++iter3)
00549 {
00550 c_point = *iter3;
00551
00552 if (c_point->is_cpoint())
00553 {
00554 if (point2->is_influencing(c_point))
00555 {
00556 add_C = false;
00557 break;
00558 }
00559 }
00560 }
00561
00562 if (add_C == true)
00563 {
00564 Pointvector[level].switch_ftoc(point2);
00565
00566 for (unsigned int j=i+1; j<=Slicing._threads; ++j)
00567 Slicing.Offset[j][level+1]++;
00568 }
00569 }
00570 }
00571 }
00572 }
00573 }
00574
00575 #ifdef DEBUG
00576 std::cout << "After 3rd pass:" << std::endl;
00577 std::cout << "Coarse Points:" << std::endl;
00578 boost::numeric::ublas::vector<bool> C;
00579 Pointvector[level].get_C(C);
00580 printvector (C);
00581 std::cout << "Fine Points:" << std::endl;
00582 boost::numeric::ublas::vector<bool> F;
00583 Pointvector[level].get_F(F);
00584 printvector (F);
00585 #endif
00586
00587 #ifdef DEBUG
00588 unsigned int i;
00589 #ifdef _OPENMP
00590 #pragma omp critical
00591 #endif
00592 {
00593 std::cout << "No C and no F point: ";
00594 for (typename PointVectorType::iterator iter = Pointvector[level].begin(); iter != Pointvector[level].end(); ++iter)
00595 if ((*iter)->is_undecided())
00596 std::cout << i << " ";
00597 std::cout << std::endl;
00598 }
00599 #endif
00600 }
00601
00609 template <typename InternalType1, typename InternalType2>
00610 void amg_coarse_ag(unsigned int level, InternalType1 & A, InternalType2 & Pointvector, amg_tag & tag)
00611 {
00612 typedef typename InternalType1::value_type SparseMatrixType;
00613 typedef typename InternalType2::value_type PointVectorType;
00614 typedef typename SparseMatrixType::value_type ScalarType;
00615
00616 typedef typename SparseMatrixType::iterator1 InternalRowIterator;
00617 typedef typename SparseMatrixType::iterator2 InternalColIterator;
00618
00619 unsigned int x,y;
00620 ScalarType diag;
00621 amg_point *pointx, *pointy;
00622
00623
00624 if (A[level].size1() == 1) return;
00625
00626
00627
00628 #ifdef _OPENMP
00629 #pragma omp parallel for private (x,y,diag) shared (A)
00630 #endif
00631 for (x=0; x<A[level].size1(); ++x)
00632 {
00633 InternalRowIterator row_iter = A[level].begin1();
00634 row_iter += x;
00635 diag = A[level](x,x);
00636 for (InternalColIterator col_iter = row_iter.begin(); col_iter != row_iter.end(); ++col_iter)
00637 {
00638 y = col_iter.index2();
00639 if (y == x || (std::abs(*col_iter) >= tag.get_threshold()*pow(0.5,level-1) * sqrt(std::abs(diag*A[level](y,y)))))
00640 {
00641
00642 Pointvector[level][x]->add_influencing_point(Pointvector[level][y]);
00643 }
00644 }
00645 }
00646
00647 #ifdef DEBUG
00648 std::cout << "Neighborhoods:" << std::endl;
00649 boost::numeric::ublas::matrix<bool> mat;
00650 Pointvector[level].get_influence_matrix(mat);
00651 printmatrix (mat);
00652 #endif
00653
00654
00655 for (typename PointVectorType::iterator iter = Pointvector[level].begin(); iter != Pointvector[level].end(); ++iter)
00656 {
00657 pointx = (*iter);
00658
00659 if (pointx->is_undecided())
00660 {
00661
00662 Pointvector[level].make_cpoint(pointx);
00663 pointx->set_aggregate (pointx->get_index());
00664 for (amg_point::iterator iter2 = pointx->begin_influencing(); iter2 != pointx->end_influencing(); ++iter2)
00665 {
00666 pointy = (*iter2);
00667
00668 if (pointy->is_undecided())
00669 {
00670
00671 Pointvector[level].make_fpoint(pointy);
00672 pointy->set_aggregate (pointx->get_index());
00673 }
00674 }
00675 }
00676 }
00677
00678 #ifdef DEBUG
00679 std::cout << "After aggregation:" << std::endl;
00680 std::cout << "Coarse Points:" << std::endl;
00681 boost::numeric::ublas::vector<bool> C;
00682 Pointvector[level].get_C(C);
00683 printvector (C);
00684 std::cout << "Fine Points:" << std::endl;
00685 boost::numeric::ublas::vector<bool> F;
00686 Pointvector[level].get_F(F);
00687 printvector (F);
00688 std::cout << "Aggregates:" << std::endl;
00689 printvector (Aggregates[level]);
00690 #endif
00691 }
00692 }
00693 }
00694 }
00695 }
00696
00697 #endif