All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
amg_coarse.hpp
Go to the documentation of this file.
#ifndef VIENNACL_LINALG_DETAIL_AMG_AMG_COARSE_HPP
#define VIENNACL_LINALG_DETAIL_AMG_AMG_COARSE_HPP
/* =========================================================================
Copyright (c) 2010-2014, Institute for Microelectronics,
Institute for Analysis and Scientific Computing,
TU Wien.
Portions of this software are copyright by UChicago Argonne, LLC.
-----------------
ViennaCL - The Vienna Computing Library
-----------------
Project Head: Karl Rupp rupp@iue.tuwien.ac.at
(A list of authors and contributors can be found in the PDF manual)
License: MIT (X11), see file LICENSE in the base directory
============================================================================= */
#include <cmath>
#include "viennacl/linalg/detail/amg/amg_base.hpp"
#include <map>
#ifdef VIENNACL_WITH_OPENMP
#include <omp.h>
#endif
#include "viennacl/linalg/detail/amg/amg_debug.hpp"
namespace viennacl
{
namespace linalg
{
namespace detail
{
namespace amg
{
template<typename InternalT1, typename InternalT2, typename InternalT3>
void amg_coarse(unsigned int level, InternalT1 & A, InternalT2 & pointvector, InternalT3 & slicing, amg_tag & tag)
{
switch (tag.get_coarse())
{
case VIENNACL_AMG_COARSE_RS: amg_coarse_classic(level, A, pointvector, tag); break;
case VIENNACL_AMG_COARSE_ONEPASS: amg_coarse_classic_onepass(level, A, pointvector, tag); break;
case VIENNACL_AMG_COARSE_RS0: amg_coarse_rs0(level, A, pointvector, slicing, tag); break;
case VIENNACL_AMG_COARSE_RS3: amg_coarse_rs3(level, A, pointvector, slicing, tag); break;
case VIENNACL_AMG_COARSE_AG: amg_coarse_ag(level, A, pointvector, tag); break;
}
}
template<typename InternalT1, typename InternalT2>
void amg_influence(unsigned int level, InternalT1 const & A, InternalT2 & pointvector, amg_tag & tag)
{
typedef typename InternalT1::value_type SparseMatrixType;
typedef typename InternalT2::value_type PointVectorType;
typedef typename SparseMatrixType::value_type ScalarType;
typedef typename SparseMatrixType::const_iterator1 ConstRowIterator;
typedef typename SparseMatrixType::const_iterator2 ConstColIterator;
#ifdef VIENNACL_WITH_OPENMP
#pragma omp parallel for
#endif
for (long i=0; i<static_cast<long>(A[level].size1()); ++i)
{
int diag_sign = 1;
if (A[level](static_cast<unsigned int>(i),static_cast<unsigned int>(i)) < 0)
diag_sign = -1;
ConstRowIterator row_iter = A[level].begin1();
row_iter += static_cast<unsigned int>(i);
// Find greatest non-diagonal negative value (positive if diagonal is negative) in row
ScalarType max = 0;
for (ConstColIterator col_iter = row_iter.begin(); col_iter != row_iter.end(); ++col_iter)
{
if (i == (unsigned int) col_iter.index2()) continue;
if (diag_sign == 1)
if (max > *col_iter) max = *col_iter;
if (diag_sign == -1)
if (max < *col_iter) max = *col_iter;
}
// If maximum is 0 then the row is independent of the others
if (std::fabs(max) <= 0)
continue;
// Find all points that strongly influence current point (Yang, p.5)
for (ConstColIterator col_iter = row_iter.begin(); col_iter != row_iter.end(); ++col_iter)
{
unsigned int j = static_cast<unsigned int>(col_iter.index2());
if (i == j)
continue;
if (ScalarType(diag_sign) * (-*col_iter) >= tag.get_threshold() * (ScalarType(diag_sign) * (-max)))
{
// Strong influence from j to i found, save information
pointvector[level][static_cast<unsigned int>(i)]->add_influencing_point(pointvector[level][static_cast<unsigned int>(j)]);
}
}
}
#ifdef VIENNACL_AMG_DEBUG
std::cout << "Influence Matrix: " << std::endl;
boost::numeric::ublas::matrix<bool> mat;
Pointvector[level].get_influence_matrix(mat);
printmatrix (mat);
#endif
// Save influenced points
for (typename PointVectorType::iterator iter = pointvector[level].begin(); iter != pointvector[level].end(); ++iter)
for (typename amg_point::iterator iter2 = (*iter)->begin_influencing(); iter2 != (*iter)->end_influencing(); ++iter2)
(*iter2)->add_influenced_point(*iter);
#ifdef VIENNACL_AMG_DEBUG
std::cout << "Influence Measures: " << std::endl;
boost::numeric::ublas::vector<unsigned int> temp;
pointvector[level].get_influence(temp);
printvector(temp);
std::cout << "Point Sorting: " << std::endl;
Pointvector[level].get_sorting(temp);
printvector (temp);
#endif
}
template<typename InternalT1, typename InternalT2>
void amg_coarse_classic_onepass(unsigned int level, InternalT1 & A, InternalT2 & pointvector, amg_tag & tag)
{
amg_point* c_point, *point1, *point2;
// Check and save all strong influences
amg_influence(level, A, pointvector, tag);
// Traverse through points and calculate initial influence measure
#ifdef VIENNACL_WITH_OPENMP
#pragma omp parallel for
#endif
for (long i=0; i<static_cast<long>(pointvector[level].size()); ++i)
pointvector[level][static_cast<unsigned int>(i)]->calc_influence();
// Do initial sorting
pointvector[level].sort();
// Get undecided point with highest influence measure
while ((c_point = pointvector[level].get_nextpoint()) != NULL)
{
// Make this point C point
pointvector[level].make_cpoint(c_point);
// All strongly influenced points become F points
for (typename amg_point::iterator iter = c_point->begin_influenced(); iter != c_point->end_influenced(); ++iter)
{
point1 = *iter;
// Found strong influence from C point (c_point influences point1), check whether point is still undecided, otherwise skip
if (!point1->is_undecided()) continue;
// Make this point F point if it is still undecided point
pointvector[level].make_fpoint(point1);
// Add +1 to influence measure for all undecided points that strongly influence new F point
for (typename amg_point::iterator iter2 = point1->begin_influencing(); iter2 != point1->end_influencing(); ++iter2)
{
point2 = *iter2;
// Found strong influence to F point (point2 influences point1)
if (point2->is_undecided())
pointvector[level].add_influence(point2,1);
}
}
}
// If a point is neither C nor F point but is nevertheless influenced by other points make it F point
// (this situation can happen when this point does not influence other points and the points that influence this point became F points already)
/*#pragma omp parallel for private (i,point1)
for (long i=0; i<static_cast<long>(Pointvector[level].size()); ++i)
{
point1 = pointvector[level][i];
if (point1->is_undecided())
{
// Undecided point found. Check whether it is influenced by other point and if so: Make it F point.
if (point1->number_influencing() > 0)
{
#pragma omp critical
pointvector[level].make_fpoint(point1);
}
}
}*/
#if defined (VIENNACL_AMG_DEBUG)// or defined (VIENNACL_AMG_DEBUGBENCH)
unsigned int c_points = pointvector[level].get_cpoints();
unsigned int f_points = pointvector[level].get_fpoints();
std::cout << "1st pass: Level " << level << ": ";
std::cout << "No of C points = " << c_points << ", ";
std::cout << "No of F points = " << f_points << std::endl;
#endif
#ifdef VIENNACL_AMG_DEBUG
std::cout << "Coarse Points:" << std::endl;
boost::numeric::ublas::vector<bool> C;
pointvector[level].get_C(C);
printvector(C);
std::cout << "Fine Points:" << std::endl;
boost::numeric::ublas::vector<bool> F;
pointvector[level].get_F(F);
printvector(F);
#endif
}
template<typename InternalT1, typename InternalT2>
void amg_coarse_classic(unsigned int level, InternalT1 & A, InternalT2 & pointvector, amg_tag & tag)
{
typedef typename InternalT2::value_type PointVectorType;
bool add_C;
amg_point *c_point, *point1, *point2;
// Use one-pass-coarsening as first pass.
amg_coarse_classic_onepass(level, A, pointvector, tag);
// 2nd pass: Add more C points if F-F connection does not have a common C point.
for (typename PointVectorType::iterator iter = pointvector[level].begin(); iter != pointvector[level].end(); ++iter)
{
point1 = *iter;
// If point is F point, check for strong connections.
if (point1->is_fpoint())
{
// Check for strong connections from influencing and influenced points.
amg_point::iterator iter2 = point1->begin_influencing();
amg_point::iterator iter3 = point1->begin_influenced();
// Iterate over both lists at once. This makes sure that points are no checked twice when influence relation is symmetric (which is often the case).
// Note: Only works because influencing and influenced lists are sorted by point-index.
while (iter2 != point1->end_influencing() || iter3 != point1->end_influenced())
{
if (iter2 == point1->end_influencing())
{
point2 = *iter3;
++iter3;
}
else if (iter3 == point1->end_influenced())
{
point2 = *iter2;
++iter2;
}
else
{
if ((*iter2)->get_index() == (*iter3)->get_index())
{
point2 = *iter2;
++iter2;
++iter3;
}
else if ((*iter2)->get_index() < (*iter3)->get_index())
{
point2 = *iter2;
++iter2;
}
else
{
point2 = *iter3;
++iter3;
}
}
// Only check points with higher index as points with lower index have been checked already.
if (point2->get_index() < point1->get_index())
continue;
// If there is a strong connection then it has to either be a C point or a F point with common C point.
// C point? Then skip as everything is ok.
if (point2->is_cpoint())
continue;
// F point? Then check whether F points point1 and point2 have a common C point.
if (point2->is_fpoint())
{
add_C = true;
// C point is common for two F points if they are both strongly influenced by that C point.
// Compare strong influences for point1 and point2.
for (amg_point::iterator iter4 = point1->begin_influencing(); iter4 != point1 -> end_influencing(); ++iter4)
{
c_point = *iter4;
// Stop search when strong common influence is found via c_point.
if (c_point->is_cpoint())
{
if (point2->is_influencing(c_point))
{
add_C = false;
break;
}
}
}
// No common C point found? Then make second F point to C point.
if (add_C == true)
pointvector[level].switch_ftoc(point2);
}
}
}
}
#ifdef VIENNACL_AMG_DEBUG
std::cout << "After 2nd pass:" << std::endl;
std::cout << "Coarse Points:" << std::endl;
boost::numeric::ublas::vector<bool> C;
pointvector[level].get_C(C);
printvector(C);
std::cout << "Fine Points:" << std::endl;
boost::numeric::ublas::vector<bool> F;
pointvector[level].get_F(F);
printvector(F);
#endif
#ifdef VIENNACL_AMG_DEBUG
#ifdef VIENNACL_WITH_OPENMP
#pragma omp critical
#endif
{
std::cout << "No C and no F point: ";
for (typename PointVectorType::iterator iter = pointvector[level].begin(); iter != pointvector[level].end(); ++iter)
if ((*iter)->is_undecided())
std::cout << (*iter)->get_index() << " ";
std::cout << std::endl;
}
#endif
}
template<typename InternalT1, typename InternalT2, typename InternalT3>
void amg_coarse_rs0(unsigned int level, InternalT1 & A, InternalT2 & pointvector, InternalT3 & slicing, amg_tag & tag)
{
unsigned int total_points;
// Slice matrix into parts such that points are distributed among threads
slicing.slice(level, A, pointvector);
// Run classical coarsening in parallel
total_points = 0;
#ifdef VIENNACL_WITH_OPENMP
#pragma omp parallel for
#endif
for (long i2=0; i2<static_cast<long>(slicing.threads_); ++i2)
{
std::size_t i = static_cast<std::size_t>(i2);
amg_coarse_classic(level, slicing.A_slice_[i], slicing.pointvector_slice_[i],tag);
// Save C points (using Slicing.Offset on the next level as temporary memory)
// Note: Number of C points for point i is saved in i+1!! (makes it easier later to compute offset)
slicing.offset_[i+1][level+1] = slicing.pointvector_slice_[i][level].get_cpoints();
#ifdef VIENNACL_WITH_OPENMP
#pragma omp critical
#endif
total_points += slicing.pointvector_slice_[i][level].get_cpoints();
}
// If no coarser level can be found on any level then resume and coarsening will stop in amg_coarse()
if (total_points != 0)
{
#ifdef VIENNACL_WITH_OPENMP
#pragma omp parallel for
#endif
for (long i2=0; i2<static_cast<long>(slicing.threads_); ++i2)
{
std::size_t i = static_cast<std::size_t>(i2);
// If no higher coarse level can be found on slice i (saved in Slicing.Offset[i+1][level+1]) then pull C point(s) to the next level
if (slicing.offset_[i+1][level+1] == 0)
{
// All points become C points
for (unsigned int j=0; j<slicing.A_slice_[i][level].size1(); ++j)
slicing.pointvector_slice_[i][level].make_cpoint(slicing.pointvector_slice_[i][level][j]);
slicing.offset_[i+1][level+1] = static_cast<unsigned int>(slicing.A_slice_[i][level].size1());
}
}
// Build slicing offset from number of C points (offset = total sum of C points on threads with lower number)
for (unsigned int i2=2; i2<=slicing.threads_; ++i2)
{
std::size_t i = static_cast<std::size_t>(i2);
slicing.offset_[i][level+1] += slicing.offset_[i-1][level+1];
}
// Join C and F points
slicing.join(level, pointvector);
}
// Calculate global influence measures for interpolation and/or RS3.
amg_influence(level, A, pointvector, tag);
#if defined(VIENNACL_AMG_DEBUG)// or defined (VIENNACL_AMG_DEBUGBENCH)
for (unsigned int i=0; i<slicing._threads; ++i)
{
unsigned int c_points = slicing.pointvector_slice_[i][level].get_cpoints();
unsigned int f_points = slicing.pointvector_slice_[i][level].get_fpoints();
std::cout << "Thread " << i << ": ";
std::cout << "No of C points = " << c_points << ", ";
std::cout << "No of F points = " << f_points << std::endl;
}
#endif
}
template<typename InternalT1, typename InternalT2, typename InternalT3>
void amg_coarse_rs3(unsigned int level, InternalT1 & A, InternalT2 & pointvector, InternalT3 & slicing, amg_tag & tag)
{
amg_point *c_point, *point1, *point2;
bool add_C;
unsigned int i, j;
// Run RS0 first (parallel).
amg_coarse_rs0(level, A, pointvector, slicing, tag);
// Save slicing offset
boost::numeric::ublas::vector<unsigned int> offset = boost::numeric::ublas::vector<unsigned int> (slicing.offset_.size());
for (i=0; i<slicing.offset_.size(); ++i)
offset[i] = slicing.offset_[i][level];
// Correct the coarsening with a third pass: Don't allow strong F-F connections without common C point
for (i=0; i<slicing.threads_; ++i)
{
//for (j=Slicing.Offset[i][level]; j<Slicing.Offset[i+1][level]; ++j)
for (j=offset[i]; j<offset[i+1]; ++j)
{
point1 = pointvector[level][j];
// If point is F point, check for strong connections.
if (point1->is_fpoint())
{
// Check for strong connections from influencing and influenced points.
amg_point::iterator iter2 = point1->begin_influencing();
amg_point::iterator iter3 = point1->begin_influenced();
// Iterate over both lists at once. This makes sure that points are no checked twice when influence relation is symmetric (which is often the case).
// Note: Only works because influencing and influenced lists are sorted by point-index.
while (iter2 != point1->end_influencing() || iter3 != point1->end_influenced())
{
if (iter2 == point1->end_influencing())
{
point2 = *iter3;
++iter3;
}
else if (iter3 == point1->end_influenced())
{
point2 = *iter2;
++iter2;
}
else
{
if ((*iter2)->get_index() == (*iter3)->get_index())
{
point2 = *iter2;
++iter2;
++iter3;
}
else if ((*iter2)->get_index() < (*iter3)->get_index())
{
point2 = *iter2;
++iter2;
}
else
{
point2 = *iter3;
++iter3;
}
}
// Only check points with higher index as points with lower index have been checked already.
if (point2->get_index() < point1->get_index())
continue;
// Only check points that are outside the slicing boundaries (interior F-F connections have already been checked in second pass)
//if (point2->get_index() >= Slicing.Offset[i][level] || point2->get_index() < Slicing.Offset[i+1][level])
if (point2->get_index() >= offset[i] && point2->get_index() < offset[i+1])
continue;
// If there is a strong connection then it has to either be a C point or a F point with common C point.
// C point? Then skip as everything is ok.
if (point2->is_cpoint())
continue;
// F point? Then check whether F points point1 and point2 have a common C point.
if (point2->is_fpoint())
{
add_C = true;
// C point is common for two F points if they are both strongly influenced by that C point.
// Compare strong influences for point1 and point2.
for (amg_point::iterator iter4 = point1->begin_influencing(); iter4 != point1 -> end_influencing(); ++iter4)
{
c_point = *iter4;
// Stop search when strong common influence is found via c_point.
if (c_point->is_cpoint())
{
if (point2->is_influencing(c_point))
{
add_C = false;
break;
}
}
}
// No common C point found? Then make second F point to C point.
if (add_C == true)
{
pointvector[level].switch_ftoc(point2);
// Add +1 to offsets as one C point has been added.
for (unsigned int k=i+1; k<=slicing.threads_; ++k)
slicing.offset_[k][level+1]++;
}
}
}
}
}
}
#ifdef VIENNACL_AMG_DEBUG
std::cout << "After 3rd pass:" << std::endl;
std::cout << "Coarse Points:" << std::endl;
boost::numeric::ublas::vector<bool> C;
pointvector[level].get_C(C);
printvector (C);
std::cout << "Fine Points:" << std::endl;
boost::numeric::ublas::vector<bool> F;
pointvector[level].get_F(F);
printvector (F);
#endif
}
template<typename InternalT1, typename InternalT2>
void amg_coarse_ag(unsigned int level, InternalT1 & A, InternalT2 & pointvector, amg_tag & tag)
{
typedef typename InternalT1::value_type SparseMatrixType;
typedef typename InternalT2::value_type PointVectorType;
typedef typename SparseMatrixType::value_type ScalarType;
typedef typename SparseMatrixType::iterator1 InternalRowIterator;
typedef typename SparseMatrixType::iterator2 InternalColIterator;
amg_point *pointx, *pointy;
// Cannot determine aggregates if size == 1 as then a new aggregate would always consist of this point (infinite loop)
if (A[level].size1() == 1)
return;
// SA algorithm (Vanek et al. p.6)
// Build neighborhoods
#ifdef VIENNACL_WITH_OPENMP
#pragma omp parallel for
#endif
for (long x=0; x<static_cast<long>(A[level].size1()); ++x)
{
InternalRowIterator row_iter = A[level].begin1();
row_iter += std::size_t(x);
ScalarType diag = A[level](static_cast<unsigned int>(x),static_cast<unsigned int>(x));
for (InternalColIterator col_iter = row_iter.begin(); col_iter != row_iter.end(); ++col_iter)
{
long y = static_cast<long>(col_iter.index2());
if (y == x || (std::fabs(*col_iter) >= tag.get_threshold()*pow(0.5, static_cast<double>(level-1)) * std::sqrt(std::fabs(diag*A[level](static_cast<unsigned int>(y),static_cast<unsigned int>(y))))))
{
// Neighborhood x includes point y
pointvector[level][static_cast<unsigned int>(x)]->add_influencing_point(pointvector[level][static_cast<unsigned int>(y)]);
}
}
}
#ifdef VIENNACL_AMG_DEBUG
std::cout << "Neighborhoods:" << std::endl;
boost::numeric::ublas::matrix<bool> mat;
pointvector[level].get_influence_matrix(mat);
printmatrix(mat);
#endif
// Build aggregates from neighborhoods
for (typename PointVectorType::iterator iter = pointvector[level].begin(); iter != pointvector[level].end(); ++iter)
{
pointx = (*iter);
if (pointx->is_undecided())
{
// Make center of aggregate to C point and include it to aggregate x.
pointvector[level].make_cpoint(pointx);
pointx->set_aggregate (pointx->get_index());
for (amg_point::iterator iter2 = pointx->begin_influencing(); iter2 != pointx->end_influencing(); ++iter2)
{
pointy = (*iter2);
if (pointy->is_undecided())
{
// Make neighbor y to F point and include it to aggregate x.
pointvector[level].make_fpoint(pointy);
pointy->set_aggregate(pointx->get_index());
}
}
}
}
#ifdef VIENNACL_AMG_DEBUG
std::cout << "After aggregation:" << std::endl;
std::cout << "Coarse Points:" << std::endl;
boost::numeric::ublas::vector<bool> C;
pointvector[level].get_C(C);
printvector(C);
std::cout << "Fine Points:" << std::endl;
boost::numeric::ublas::vector<bool> F;
pointvector[level].get_F(F);
printvector(F);
std::cout << "Aggregates:" << std::endl;
printvector(Aggregates[level]);
#endif
}
} //namespace amg
} //namespace detail
} //namespace linalg
} //namespace viennacl
#endif
viennacl::linalg::detail::amg::amg_coarse_rs3
void amg_coarse_rs3(unsigned int level, InternalT1 &A, InternalT2 &pointvector, InternalT3 &slicing, amg_tag &tag)
RS3 coarsening. Single-Threaded! (VIENNACL_AMG_COARSE_RS3)
Definition: amg_coarse.hpp:443
amg_debug.hpp
Debug functionality for AMG. To be removed.
viennacl::linalg::detail::amg::amg_point::set_aggregate
void set_aggregate(unsigned int aggregate)
Definition: amg_base.hpp:866
viennacl::linalg::detail::amg::amg_tag::get_threshold
double get_threshold() const
Definition: amg_base.hpp:96
viennacl::linalg::detail::amg::amg_coarse_classic
void amg_coarse_classic(unsigned int level, InternalT1 &A, InternalT2 &pointvector, amg_tag &tag)
Classical (RS) two-pass coarsening. Single-Threaded! (VIENNACL_AMG_COARSE_CLASSIC) ...
Definition: amg_coarse.hpp:240
viennacl::linalg::detail::amg::amg_point
A class for the AMG points. Saves point index and influence measure Holds information whether point i...
Definition: amg_base.hpp:827
VIENNACL_AMG_COARSE_RS
#define VIENNACL_AMG_COARSE_RS
Definition: amg_base.hpp:41
viennacl::linalg::detail::amg::amg_point::is_cpoint
bool is_cpoint() const
Definition: amg_base.hpp:869
viennacl::traits::size1
vcl_size_t size1(MatrixType const &mat)
Generic routine for obtaining the number of rows of a matrix (ViennaCL, uBLAS, etc.)
Definition: size.hpp:216
VIENNACL_AMG_COARSE_RS3
#define VIENNACL_AMG_COARSE_RS3
Definition: amg_base.hpp:44
viennacl::linalg::detail::amg::amg_point::switch_ftoc
void switch_ftoc()
Definition: amg_base.hpp:915
viennacl::linalg::detail::amg::amg_point::make_cpoint
void make_cpoint()
Definition: amg_base.hpp:901
viennacl::linalg::detail::amg::amg_coarse_classic_onepass
void amg_coarse_classic_onepass(unsigned int level, InternalT1 &A, InternalT2 &pointvector, amg_tag &tag)
Classical (RS) one-pass coarsening. Single-Threaded! (VIENNACL_AMG_COARSE_CLASSIC_ONEPASS) ...
Definition: amg_coarse.hpp:153
viennacl::linalg::detail::amg::amg_point::is_fpoint
bool is_fpoint() const
Definition: amg_base.hpp:870
viennacl::linalg::detail::max
T max(const T &lhs, const T &rhs)
Maximum.
Definition: util.hpp:59
VIENNACL_AMG_COARSE_RS0
#define VIENNACL_AMG_COARSE_RS0
Definition: amg_base.hpp:43
VIENNACL_AMG_COARSE_AG
#define VIENNACL_AMG_COARSE_AG
Definition: amg_base.hpp:45
viennacl::linalg::detail::amg::amg_point::begin_influenced
iterator begin_influenced()
Definition: amg_base.hpp:922
viennacl::linalg::detail::amg::amg_point::is_influencing
bool is_influencing(amg_point *point) const
Definition: amg_base.hpp:876
viennacl::linalg::detail::amg::amg_tag
A tag for algebraic multigrid (AMG). Used to transport information from the user to the implementatio...
Definition: amg_base.hpp:61
viennacl::linalg::detail::amg::amg_point::begin_influencing
iterator begin_influencing()
Definition: amg_base.hpp:918
viennacl::diag
vector_expression< const matrix_base< NumericT >, const int, op_matrix_diag > diag(const matrix_base< NumericT > &A, int k=0)
Definition: matrix.hpp:838
viennacl::linalg::detail::amg::printvector
void printvector(VectorT const &)
Definition: amg_debug.hpp:80
viennacl::linalg::detail::amg::amg_point::is_undecided
bool is_undecided() const
Definition: amg_base.hpp:871
viennacl::linalg::detail::amg::amg_coarse
void amg_coarse(unsigned int level, InternalT1 &A, InternalT2 &pointvector, InternalT3 &slicing, amg_tag &tag)
Calls the right coarsening procedure.
Definition: amg_coarse.hpp:52
viennacl::linalg::detail::amg::amg_tag::get_coarse
unsigned int get_coarse() const
Definition: amg_base.hpp:90
viennacl::linalg::detail::amg::amg_coarse_ag
void amg_coarse_ag(unsigned int level, InternalT1 &A, InternalT2 &pointvector, amg_tag &tag)
AG (aggregation based) coarsening. Single-Threaded! (VIENNACL_AMG_COARSE_SA)
Definition: amg_coarse.hpp:572
VIENNACL_AMG_COARSE_ONEPASS
#define VIENNACL_AMG_COARSE_ONEPASS
Definition: amg_base.hpp:42
viennacl::linalg::detail::amg::amg_coarse_rs0
void amg_coarse_rs0(unsigned int level, InternalT1 &A, InternalT2 &pointvector, InternalT3 &slicing, amg_tag &tag)
Parallel classical RS0 coarsening. Multi-Threaded! (VIENNACL_AMG_COARSE_RS0 || VIENNACL_AMG_COARSE_RS...
Definition: amg_coarse.hpp:363
ScalarType
float ScalarType
Definition: fft_1d.cpp:42
viennacl::linalg::detail::amg::amg_sparsevector_iterator
Defines an iterator for the sparse vector type.
Definition: amg_base.hpp:209
viennacl::linalg::detail::amg::amg_point::end_influenced
iterator end_influenced()
Definition: amg_base.hpp:923
viennacl::linalg::detail::amg::amg_point::get_index
unsigned int get_index() const
Definition: amg_base.hpp:864
amg_base.hpp
Helper classes and functions for the AMG preconditioner. Experimental.
viennacl::linalg::detail::amg::amg_point::end_influencing
iterator end_influencing()
Definition: amg_base.hpp:919
viennacl::linalg::detail::amg::printmatrix
void printmatrix(MatrixT &, int)
Definition: amg_debug.hpp:77
viennacl::linalg::detail::amg::amg_point::make_fpoint
void make_fpoint()
Definition: amg_base.hpp:908
viennacl::linalg::detail::amg::amg_influence
void amg_influence(unsigned int level, InternalT1 const &A, InternalT2 &pointvector, amg_tag &tag)
Determines strong influences in system matrix, classical approach (RS). Multithreaded! ...
Definition: amg_coarse.hpp:71