• Main Page
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

/data/development/ViennaCL/dev/viennacl/misc/cuthill_mckee.hpp

Go to the documentation of this file.
00001 #ifndef VIENNACL_MISC_CUTHILL_MCKEE_HPP
00002 #define VIENNACL_MISC_CUTHILL_MCKEE_HPP
00003 
00004 /* =========================================================================
00005    Copyright (c) 2010-2011, Institute for Microelectronics,
00006                             Institute for Analysis and Scientific Computing,
00007                             TU Wien.
00008 
00009                             -----------------
00010                   ViennaCL - The Vienna Computing Library
00011                             -----------------
00012 
00013    Project Head:    Karl Rupp                   rupp@iue.tuwien.ac.at
00014                
00015    (A list of authors and contributors can be found in the PDF manual)
00016 
00017    License:         MIT (X11), see file LICENSE in the base directory
00018 ============================================================================= */
00019 
00020 
00027 #include <iostream>
00028 #include <fstream>
00029 #include <string>
00030 #include <algorithm>
00031 #include <map>
00032 #include <vector>
00033 #include <deque>
00034 #include <cmath>
00035 
00036 
00037 namespace viennacl
00038 {
00039   
00040   namespace detail
00041   {
00042     
00043     // function to calculate the increment of combination comb.
00044     // parameters:
00045     // comb: pointer to vector<int> of size m, m <= n
00046     //       1 <= comb[i] <= n for 0 <= i < m
00047     //       comb[i] < comb[i+1] for 0 <= i < m - 1
00048     //       comb represents an unordered selection of m values out of n
00049     // n: int
00050     //    total number of values out of which comb is taken as selection
00051     inline bool comb_inc(std::vector<int> & comb, int n)
00052     {
00053         int m;
00054         int k;
00055         
00056         m = comb.size();
00057         // calculate k as highest possible index such that (*comb)[k-1] can be incremented
00058         k = m;
00059         while ( (k > 0) && ( ((k == m) && (comb[k-1] == n)) || 
00060                             ((k < m) && (comb[k-1] == comb[k] - 1) )) )
00061         {
00062             k--;
00063         }
00064         if (k == 0) // no further increment of comb possible -> return false
00065         {
00066             return false;
00067         }
00068         else
00069         {
00070             (comb[k-1])++; // increment (*comb)[k-1],
00071             for (int i = k; i < m; i++) // and all higher index positions of comb are 
00072             // calculated just as directly following integer values (lowest possible values)
00073             {
00074                 comb[i] = comb[k-1] + (i - k + 1);
00075             }
00076             return true;
00077         }
00078     }
00079 
00080 
00081     // function to generate a node layering as a tree structure rooted at
00082     // node s
00083     template <typename MatrixType>
00084     void generate_layering(MatrixType const & matrix, 
00085                            std::vector< std::vector<int> > & l,
00086                            int s)
00087     {
00088       std::size_t n = matrix.size();
00089       //std::vector< std::vector<int> > l;
00090       std::vector<bool> inr(n, false);
00091       std::vector<int> nlist;
00092       
00093       nlist.push_back(s);
00094       inr[s] = true;
00095       l.push_back(nlist);
00096       
00097       for (;;)
00098       {
00099           nlist.clear();
00100           for (std::vector<int>::iterator it  = l.back().begin(); 
00101                                           it != l.back().end();
00102                                           it++)
00103           {
00104               for (typename MatrixType::value_type::const_iterator it2  = matrix[*it].begin(); 
00105                                                          it2 != matrix[*it].end();
00106                                                          it2++)
00107               {
00108                   if (it2->first == *it) continue;
00109                   if (inr[it2->first]) continue;
00110                   
00111                   nlist.push_back(it2->first);
00112                   inr[it2->first] = true;
00113               }
00114           }
00115           
00116           if (nlist.size() == 0)
00117               break;
00118 
00119           l.push_back(nlist);
00120       }
00121       
00122     }
00123 
00124     
00125     // comparison function for comparing two vector<int> values by their 
00126     // [1]-element
00127     inline bool cuthill_mckee_comp_func(std::vector<int> const & a,
00128                                         std::vector<int> const & b)
00129     {
00130         return (a[1] < b[1]);
00131     }
00132     
00133   }
00134   
00135   //
00136   // Part 1: The original Cuthill-McKee algorithm
00137   //
00138   
00139   
00140   struct cuthill_mckee_tag {};
00141   
00156   template <typename MatrixType>
00157   std::vector<int> reorder(MatrixType const & matrix, cuthill_mckee_tag)
00158   {
00159     std::size_t n = matrix.size();
00160     std::vector<int> r;
00161     std::vector<bool> inr(n, false); // status array which remembers which nodes have been added to r
00162     std::deque<int> q;
00163     std::vector< std::vector<int> > nodes;
00164     std::vector<int> tmp(2);
00165     int p = 0;
00166     int c;
00167     
00168     int deg;
00169     int deg_min;
00170     
00171     r.reserve(n);
00172     nodes.reserve(n);
00173     
00174     do
00175     {
00176         // under all nodes not yet in r determine one with minimal degree
00177         deg_min = -1;
00178         for (std::size_t i = 0; i < n; i++)
00179         {
00180             if (!inr[i])
00181             {
00182                 deg = matrix[i].size() - 1; // node degree
00183                 if (deg_min < 0 || deg < deg_min)
00184                 {
00185                     p = i; // node number
00186                     deg_min = deg;
00187                 }
00188             }
00189         }
00190         q.push_back(p); // push that node p with minimal degree on q
00191         
00192         do
00193         {
00194             c = q.front();
00195             q.pop_front();
00196             if (!inr[c])
00197             {
00198                 r.push_back(c);
00199                 inr[c] = true;
00200                 
00201                 // add all neighbouring nodes of c which are not yet in r to nodes
00202                 nodes.resize(0);
00203                 for (typename MatrixType::value_type::const_iterator it =  matrix[c].begin(); it != matrix[c].end(); it++)
00204                 {
00205                     if (it->first == c) continue;
00206                     if (inr[it->first]) continue;
00207                     
00208                     tmp[0] = it->first;
00209                     tmp[1] = matrix[it->first].size() - 1;
00210                     nodes.push_back(tmp);
00211                 }
00212                 
00213                 // sort nodes by node degree
00214                 std::sort(nodes.begin(), nodes.end(), detail::cuthill_mckee_comp_func);
00215                 for (std::vector< std::vector<int> >::iterator it = nodes.begin(); it != nodes.end(); it++)
00216                 {
00217                     q.push_back((*it)[0]);
00218                 }
00219             }
00220         } while (q.size() != 0);
00221     } while (r.size() < n);
00222     
00223     return r;
00224   }
00225   
00226   
00227   //
00228   // Part 2: Advanced Cuthill McKee
00229   //
00230 
00232   class advanced_cuthill_mckee_tag
00233   {
00234     public:
00253       advanced_cuthill_mckee_tag(double a = 0.0, std::size_t gmax = 1) : starting_node_param_(a), max_root_nodes_(gmax) {}
00254       
00255       double starting_node_param() const { return starting_node_param_;}
00256       void starting_node_param(double a) { if (a >= 0) starting_node_param_ = a; }
00257       
00258       std::size_t max_root_nodes() const { return max_root_nodes_; }
00259       void max_root_nodes(std::size_t gmax) { max_root_nodes_ = gmax; }      
00260       
00261     private:
00262       double starting_node_param_;
00263       std::size_t max_root_nodes_;
00264   };
00265   
00266 
00267 
00276   template <typename MatrixType>
00277   std::vector<int> reorder(MatrixType const & matrix,
00278                            advanced_cuthill_mckee_tag const & tag)
00279   {
00280     std::size_t n = matrix.size();
00281     double a = tag.starting_node_param();
00282     std::size_t gmax = tag.max_root_nodes();
00283     std::vector<int> r;
00284     std::vector<int> r_tmp;
00285     std::vector<int> r_best;
00286     std::vector<int> r2(n);
00287     std::vector<bool> inr(n, false);
00288     std::vector<bool> inr_tmp(n);
00289     std::vector<bool> inr_best(n);
00290     std::deque<int> q;
00291     std::vector< std::vector<int> > nodes;
00292     std::vector<int> nodes_p;
00293     std::vector<int> tmp(2);
00294     std::vector< std::vector<int> > l;
00295     int deg_min;
00296     int deg_max;
00297     int deg_a;
00298     int deg;
00299     int bw;
00300     int bw_best;
00301     std::vector<int> comb;
00302     std::size_t g;
00303     int c;
00304     
00305     r.reserve(n);
00306     r_tmp.reserve(n);
00307     r_best.reserve(n);
00308     nodes.reserve(n);
00309     nodes_p.reserve(n);
00310     comb.reserve(n);
00311     
00312     do
00313     {   
00314         // add to nodes_p all nodes not yet in r which are candidates for the root node layer  
00315         // search unnumbered node and generate layering 
00316         for (std::size_t i = 0; i < n; i++)
00317         {
00318             if (!inr[i])
00319             {
00320                 detail::generate_layering(matrix, l, i);
00321                 break;
00322             }
00323         }
00324         nodes.resize(0);
00325         for (std::vector< std::vector<int> >::iterator it = l.begin();
00326           it != l.end(); it++)
00327         {
00328             for (std::vector<int>::iterator it2 = it->begin();
00329               it2 != it->end(); it2++)
00330             {
00331                 tmp[0] = *it2;
00332                 tmp[1] = matrix[*it2].size() - 1;
00333                 nodes.push_back(tmp);
00334             }
00335         }
00336         // determine minimum and maximum node degree
00337         deg_min = -1;
00338         deg_max = -1;
00339         for (std::vector< std::vector<int> >::iterator it = nodes.begin(); 
00340           it != nodes.end(); it++)
00341         {
00342             deg = (*it)[1];
00343             if (deg_min < 0 || deg < deg_min)
00344             {
00345                 deg_min = deg;
00346             }
00347             if (deg_max < 0 || deg > deg_max)
00348             {
00349                 deg_max = deg;
00350             }
00351         }
00352         deg_a = deg_min + (int) (a * (deg_max - deg_min));
00353         nodes_p.resize(0);
00354         for (std::vector< std::vector<int> >::iterator it = nodes.begin(); 
00355           it != nodes.end(); it++)
00356         {
00357             if ((*it)[1] <= deg_a)
00358             {
00359                 nodes_p.push_back((*it)[0]);
00360             }
00361         }
00362         
00363         inr_tmp = inr;
00364         g = 1;
00365         comb.resize(1);
00366         comb[0] = 1;
00367         bw_best = -1;
00368         
00369         for (;;) // for all combinations of g <= gmax root nodes repeat
00370         {
00371             inr = inr_tmp;
00372             r_tmp.resize(0);
00373             
00374             // add the selected root nodes according to actual combination comb to q
00375             for (std::vector<int>::iterator it = comb.begin(); 
00376               it != comb.end(); it++)
00377             {
00378                 q.push_back(nodes_p[(*it)-1]);
00379             }
00380   
00381             do // perform normal CutHill-McKee algorithm for given root nodes with 
00382             // resulting numbering stored in r_tmp
00383             {
00384                 c = q.front();
00385                 q.pop_front();
00386                 if (!inr[c])
00387                 {
00388                     r_tmp.push_back(c);
00389                     inr[c] = true;
00390                     
00391                     nodes.resize(0);
00392                     for (typename MatrixType::value_type::const_iterator it = matrix[c].begin(); it != matrix[c].end(); it++)
00393                     {
00394                         if (it->first == c) continue;
00395                         if (inr[it->first]) continue;
00396                         
00397                         tmp[0] = it->first;
00398                         tmp[1] = matrix[it->first].size() - 1;
00399                         nodes.push_back(tmp);
00400                     }
00401                     std::sort(nodes.begin(), nodes.end(), detail::cuthill_mckee_comp_func);
00402                     for (std::vector< std::vector<int> >::iterator it = 
00403                       nodes.begin(); it != nodes.end(); it++)
00404                     {
00405                         q.push_back((*it)[0]);
00406                     }
00407                 }
00408             } while (q.size() != 0);
00409             
00410             // calculate resulting bandwith for root node combination
00411             // comb for current numbered component of the node graph
00412             for (std::size_t i = 0; i < r_tmp.size(); i++)
00413             {
00414                 r2[r_tmp[i]] = r.size() + i;
00415             }
00416             bw = 0;
00417             for (std::size_t i = 0; i < r_tmp.size(); i++)
00418             {
00419                 for (typename MatrixType::value_type::const_iterator it  = matrix[r_tmp[i]].begin(); 
00420                                                                      it != matrix[r_tmp[i]].end();
00421                                                                      it++)
00422                 {
00423                     bw = std::max(bw, std::abs(static_cast<int>(r.size() + i) - r2[it->first]));
00424                 }
00425             }
00426             
00427             // remember ordering r_tmp in r_best for smallest bandwith
00428             if (bw_best < 0 || bw < bw_best)
00429             {
00430                 r_best = r_tmp;
00431                 bw_best = bw;
00432                 inr_best = inr;
00433             }
00434             
00435             // calculate next combination comb, if not existing
00436             // increment g if g stays <= gmax, or else terminate loop
00437             if (!detail::comb_inc(comb, nodes_p.size()))
00438             {
00439                 g++;
00440                 if ( (gmax > 0 && g > gmax) || g > nodes_p.size())
00441                 {
00442                     break;
00443                 }
00444                 comb.resize(g);
00445                 for (std::size_t i = 0; i < g; i++)
00446                 {
00447                     comb[i] = i + 1;
00448                 }
00449             }
00450         }
00451         
00452         // store best order r_best in result array r
00453         for (std::vector<int>::iterator it = r_best.begin(); 
00454           it != r_best.end(); it++)
00455         {
00456             r.push_back((*it));
00457         }
00458         inr = inr_best;
00459         
00460     } while (r.size() < n);
00461     
00462     return r;
00463   }
00464   
00465 } //namespace viennacl
00466     
00467 
00468 #endif

Generated on Fri Dec 30 2011 23:20:43 for ViennaCL - The Vienna Computing Library by  doxygen 1.7.1