ViennaCL - The Vienna Computing Library  1.4.2
viennacl/misc/gibbs_poole_stockmeyer.hpp
Go to the documentation of this file.
00001 #ifndef VIENNACL_MISC_GIBBS_POOLE_STOCKMEYER_HPP
00002 #define VIENNACL_MISC_GIBBS_POOLE_STOCKMEYER_HPP
00003 
00004 /* =========================================================================
00005    Copyright (c) 2010-2013, 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 
00021 
00028 #include <iostream>
00029 #include <fstream>
00030 #include <string>
00031 #include <algorithm>
00032 #include <map>
00033 #include <vector>
00034 #include <deque>
00035 #include <cmath>
00036 
00037 #include "viennacl/misc/cuthill_mckee.hpp"
00038 
00039 namespace viennacl
00040 {
00041   
00042   namespace detail
00043   {
00044 
00045     // calculates width of a node layering
00046     inline int calc_layering_width(std::vector< std::vector<int> > const & l)
00047     {
00048         int w;
00049         
00050         w = 0;
00051         for (std::size_t i = 0; i < l.size(); i++)
00052         {
00053             w = std::max(w, static_cast<int>(l[i].size()));
00054         }
00055         
00056         return w;
00057     }
00058     
00059     // function to decompose a list of nodes rg into connected components
00060     // sorted by decreasing number of nodes per component
00061     template <typename MatrixType>
00062     std::vector< std::vector<int> > gps_rg_components(MatrixType const & matrix, int n,
00063                                                       std::vector<int> const & rg)
00064     {
00065         std::vector< std::vector<int> > rgc;
00066         std::vector< std::vector<int> > rgc_sorted;
00067         std::vector< std::vector<int> > sort_ind;
00068         std::vector<int> ind(2);
00069         std::vector<int> tmp;
00070         int c;
00071         std::vector<bool> inr(n, true);
00072         std::deque<int> q;
00073         
00074         for (std::size_t i = 0; i < rg.size(); i++)
00075         {
00076             inr[rg[i]] = false;
00077         }
00078         
00079         do
00080         {
00081             for (int i = 0; i < n; i++)
00082             {
00083                 if (!inr[i])
00084                 {
00085                     q.push_front(i);
00086                     break;
00087                 }
00088             }
00089             if (q.size() == 0)
00090             {
00091                 break;
00092             }
00093             
00094             tmp.resize(0);
00095             while (q.size() > 0)
00096             {
00097                 c = q.front();
00098                 q.pop_front();
00099 
00100                 if (!inr[c])
00101                 {
00102                     tmp.push_back(c);
00103                     inr[c] = true;
00104                     
00105                     for (typename MatrixType::value_type::const_iterator it = matrix[c].begin(); it != matrix[c].end(); it++)
00106                     {
00107                         if (it->first == c) continue;
00108                         if (inr[it->first]) continue;
00109                         
00110                         q.push_back(it->first);
00111                     }
00112                 }
00113             }
00114             rgc.push_back(tmp);
00115         } while (true);
00116         
00117         for (std::size_t i = 0; i < rgc.size(); i++)
00118         {
00119             ind[0] = i;
00120             ind[1] = rgc[i].size();
00121             sort_ind.push_back(ind);
00122         }
00123         std::sort(sort_ind.begin(), sort_ind.end(), detail::cuthill_mckee_comp_func);
00124         for (std::size_t i = 0; i < rgc.size(); i++)
00125         {
00126             rgc_sorted.push_back(rgc[sort_ind[rgc.size()-1-i][0]]);
00127         }
00128         
00129         return rgc_sorted;
00130     }
00131     
00132   } // namespace detail
00133   
00134   
00135   struct gibbs_poole_stockmeyer_tag {};
00136   
00137 
00151   template <typename MatrixType>
00152   std::vector<int> reorder(MatrixType const & matrix,
00153                            gibbs_poole_stockmeyer_tag)
00154   {
00155     std::size_t n = matrix.size();
00156     std::vector<int> r;
00157     std::vector< std::vector<int> > rl;
00158     std::size_t l = 0;
00159     int state;
00160     bool state_end;
00161     std::vector< std::vector<int> > nodes;
00162     std::vector<bool> inr(n, false);
00163     std::vector<bool> isn(n, false);
00164     std::vector<int> tmp(2);
00165     int g = 0;
00166     int h = 0;
00167     std::vector< std::vector<int> > lg;
00168     std::vector< std::vector<int> > lh;
00169     std::vector< std::vector<int> > ls;
00170     std::map< int, std::vector<int> > lap;
00171     std::vector<int> rg;
00172     std::vector< std::vector<int> > rgc;
00173     int m;
00174     int m_min;
00175     bool new_g = true;
00176     int k1, k2, k3, k4;
00177     std::vector<int> wvs;
00178     std::vector<int> wvsg;
00179     std::vector<int> wvsh;
00180     int deg_min;
00181     int deg;
00182     int ind_min;
00183     
00184     r.reserve(n);
00185     nodes.reserve(n);
00186     
00187     while (r.size() < n) // for all components of the graph apply GPS algorithm
00188     {
00189         // determine node g with mimimal degree among all nodes which
00190         // are not yet in result array r
00191         deg_min = -1;
00192         for (std::size_t i = 0; i < n; i++)
00193         {
00194             if (!inr[i])
00195             {
00196                 deg = matrix[i].size() - 1; // node degree
00197                 if (deg_min < 0 || deg < deg_min)
00198                 {
00199                     g = i; // node number
00200                     deg_min = deg;
00201                 }
00202             }
00203         }
00204         
00205         // algorithm for determining nodes g, h as endpoints of a pseudo graph diameter
00206         while (new_g) 
00207         {
00208           lg.clear();
00209           detail::generate_layering(matrix, lg, g);
00210             
00211           nodes.resize(0);
00212           for (std::size_t i = 0; i < lg.back().size(); i++)
00213           {
00214               tmp[0] = lg.back()[i];
00215               tmp[1] = matrix[lg.back()[i]].size() - 1;
00216               nodes.push_back(tmp);
00217           }
00218           std::sort(nodes.begin(), nodes.end(), detail::cuthill_mckee_comp_func);
00219           for (std::size_t i = 0; i < nodes.size(); i++)
00220           {
00221               lg.back()[i] = nodes[i][0];
00222           }
00223           
00224           m_min = -1;
00225           new_g = false;
00226           for (std::size_t i = 0; i < lg.back().size(); i++)
00227           {
00228               lh.clear();
00229               detail::generate_layering(matrix, lh, lg.back()[i]);
00230               if (lh.size() > lg.size())
00231               {
00232                   g = lg.back()[i];
00233                   new_g = true;
00234                   break;
00235               }
00236               m = detail::calc_layering_width(lh);
00237               if (m_min < 0 || m < m_min)
00238               {
00239                   m_min = m;
00240                   h = lg.back()[i];
00241               }
00242           }
00243         }
00244         
00245         lh.clear();
00246         detail::generate_layering(matrix, lh, h);
00247         
00248         // calculate ls as layering intersection and rg as remaining
00249         // graph
00250         lap.clear();
00251         for (std::size_t i = 0; i < lg.size(); i++)
00252         {
00253             for (std::size_t j = 0; j < lg[i].size(); j++)
00254             {
00255                 lap[lg[i][j]].resize(2);
00256                 lap[lg[i][j]][0] = i;
00257             }
00258         }
00259         for (std::size_t i = 0; i < lh.size(); i++)
00260         {
00261             for (std::size_t j = 0; j < lh[i].size(); j++)
00262             {
00263                 lap[lh[i][j]][1] = lg.size() - 1 - i;
00264             }
00265         }
00266         rg.clear();
00267         ls.clear();
00268         ls.resize(lg.size());
00269         for (std::map< int, std::vector<int> >::iterator it = lap.begin(); 
00270           it != lap.end(); it++)
00271         {
00272             if ((it->second)[0] == (it->second)[1])
00273             {
00274                 ls[(it->second)[0]].push_back(it->first);
00275             }
00276             else
00277             {
00278                 rg.push_back(it->first);
00279             }
00280         }
00281         // partition remaining graph in connected components 
00282         rgc = detail::gps_rg_components(matrix, n, rg);
00283 
00284         // insert nodes of each component of rgc
00285         k1 = detail::calc_layering_width(lg);
00286         k2 = detail::calc_layering_width(lh);
00287         wvs.resize(ls.size());
00288         wvsg.resize(ls.size());
00289         wvsh.resize(ls.size());
00290         for (std::size_t i = 0; i < rgc.size(); i++)
00291         {
00292             for (std::size_t j = 0; j < ls.size(); j++)
00293             {
00294                 wvs[j] = ls[j].size();
00295                 wvsg[j] = ls[j].size();
00296                 wvsh[j] = ls[j].size();
00297             }
00298             for (std::size_t j = 0; j < rgc[i].size(); j++)
00299             {
00300                 (wvsg[lap[rgc[i][j]][0]])++;
00301                 (wvsh[lap[rgc[i][j]][1]])++;
00302             }
00303             k3 = 0;
00304             k4 = 0;
00305             for (std::size_t j = 0; j < ls.size(); j++)
00306             {
00307                 if (wvsg[j] > wvs[j])
00308                 {
00309                     k3 = std::max(k3, wvsg[j]);
00310                 }
00311                 if (wvsh[j] > wvs[j])
00312                 {
00313                     k4 = std::max(k4, wvsh[j]);
00314                 }
00315             }
00316             if (k3 < k4 || (k3 == k4 && k1 <= k2) )
00317             {
00318                 for (std::size_t j = 0; j < rgc[i].size(); j++)
00319                 {
00320                     ls[lap[rgc[i][j]][0]].push_back(rgc[i][j]);
00321                 }
00322             }
00323             else
00324             {
00325                 for (std::size_t j = 0; j < rgc[i].size(); j++)
00326                 {
00327                     ls[lap[rgc[i][j]][1]].push_back(rgc[i][j]);
00328                 }
00329             }
00330         }
00331         
00332         // renumber nodes in ls
00333         rl.clear();
00334         rl.resize(ls.size());
00335         state = 1;
00336         state_end = false;
00337         while (!state_end)
00338         {
00339             switch(state)
00340             {
00341               case 1:
00342                 l = 0;
00343                 state = 4;
00344                 break;
00345                 
00346               case 2:
00347                 for (std::size_t i = 0; i < rl[l-1].size(); i++)
00348                 {
00349                     isn.assign(n, false);
00350                     for (std::map<int, double>::const_iterator it = matrix[rl[l-1][i]].begin();  
00351                                                                it != matrix[rl[l-1][i]].end();
00352                                                                it++)
00353                     {
00354                         if (it->first == rl[l-1][i]) continue;
00355                         isn[it->first] = true;
00356                     }
00357                     nodes.resize(0);
00358                     for (std::size_t j = 0; j < ls[l].size(); j++)
00359                     {
00360                         if (inr[ls[l][j]]) continue;
00361                         if (!isn[ls[l][j]]) continue;
00362                         tmp[0] = ls[l][j];
00363                         tmp[1] = matrix[ls[l][j]].size() - 1;
00364                         nodes.push_back(tmp);
00365                     }
00366                     std::sort(nodes.begin(), nodes.end(), detail::cuthill_mckee_comp_func);
00367                     for (std::size_t j = 0; j < nodes.size(); j++)
00368                     {
00369                         rl[l].push_back(nodes[j][0]);
00370                         r.push_back(nodes[j][0]);
00371                         inr[nodes[j][0]] = true;
00372                     }
00373                 }
00374                 
00375               case 3:
00376                 for (std::size_t i = 0; i < rl[l].size(); i++)
00377                 {
00378                     isn.assign(n, false);
00379                     for (std::map<int, double>::const_iterator it = matrix[rl[l][i]].begin(); 
00380                                                                it != matrix[rl[l][i]].end();
00381                                                                it++)
00382                     {
00383                         if (it->first == rl[l][i]) continue;
00384                         isn[it->first] = true;
00385                     }
00386                     nodes.resize(0);
00387                     for (std::size_t j = 0; j < ls[l].size(); j++)
00388                     {
00389                         if (inr[ls[l][j]]) continue;
00390                         if (!isn[ls[l][j]]) continue;
00391                         tmp[0] = ls[l][j];
00392                         tmp[1] = matrix[ls[l][j]].size() - 1;
00393                         nodes.push_back(tmp);
00394                     }
00395                     std::sort(nodes.begin(), nodes.end(), detail::cuthill_mckee_comp_func);
00396                     for (std::size_t j = 0; j < nodes.size(); j++)
00397                     {
00398                         rl[l].push_back(nodes[j][0]);
00399                         r.push_back(nodes[j][0]);
00400                         inr[nodes[j][0]] = true;
00401                     }
00402                 }
00403                 
00404               case 4:
00405                 if (rl[l].size() < ls[l].size())
00406                 {
00407                     deg_min = -1;
00408                     for (std::size_t j = 0; j < ls[l].size(); j++)
00409                     {
00410                         if (inr[ls[l][j]]) continue;
00411                         deg = matrix[ls[l][j]].size() - 1;
00412                         if (deg_min < 0 || deg < deg_min)
00413                         {
00414                             ind_min = ls[l][j];
00415                             deg_min = deg;
00416                         }
00417                     }
00418                     rl[l].push_back(ind_min);
00419                     r.push_back(ind_min);
00420                     inr[ind_min] = true;
00421                     state = 3;
00422                     break;
00423                 }
00424                 
00425               case 5:
00426                 l++;
00427                 if (l < ls.size())
00428                 {
00429                     state = 2;
00430                 }
00431                 else
00432                 {
00433                     state_end = true;
00434                 }
00435                 break;
00436                 
00437             default:
00438                 break;
00439             }
00440         }
00441 
00442     }
00443     
00444     return r;
00445   }
00446   
00447   
00448 } //namespace viennacl
00449     
00450 
00451 #endif