Zoltan2
Zoltan2_AlgSerialGreedy.hpp
Go to the documentation of this file.
00001 // @HEADER
00002 //
00003 // ***********************************************************************
00004 //
00005 //   Zoltan2: A package of combinatorial algorithms for scientific computing
00006 //                  Copyright 2012 Sandia Corporation
00007 //
00008 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00009 // the U.S. Government retains certain rights in this software.
00010 //
00011 // Redistribution and use in source and binary forms, with or without
00012 // modification, are permitted provided that the following conditions are
00013 // met:
00014 //
00015 // 1. Redistributions of source code must retain the above copyright
00016 // notice, this list of conditions and the following disclaimer.
00017 //
00018 // 2. Redistributions in binary form must reproduce the above copyright
00019 // notice, this list of conditions and the following disclaimer in the
00020 // documentation and/or other materials provided with the distribution.
00021 //
00022 // 3. Neither the name of the Corporation nor the names of the
00023 // contributors may be used to endorse or promote products derived from
00024 // this software without specific prior written permission.
00025 //
00026 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00027 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00029 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00030 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00031 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00032 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00033 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00034 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00035 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00036 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037 //
00038 // Questions? Contact Karen Devine      (kddevin@sandia.gov)
00039 //                    Erik Boman        (egboman@sandia.gov)
00040 //                    Siva Rajamanickam (srajama@sandia.gov)
00041 //
00042 // ***********************************************************************
00043 //
00044 // @HEADER
00045 #ifndef _ZOLTAN2_ALGSERIALGREEDY_HPP_
00046 #define _ZOLTAN2_ALGSERIALGREEDY_HPP_
00047 
00048 #include <Zoltan2_Algorithm.hpp>
00049 #include <Zoltan2_GraphModel.hpp>
00050 #include <Zoltan2_ColoringSolution.hpp>
00051 
00055 
00056 namespace Zoltan2{
00057 
00058 template <typename Adapter>
00059 class AlgSerialGreedy : public Algorithm<Adapter>
00060 {
00061   private:
00062     typedef typename Adapter::lno_t lno_t;
00063     typedef typename Adapter::gno_t gno_t;
00064     typedef typename Adapter::scalar_t scalar_t;
00065     // Class member variables
00066     RCP<GraphModel<typename Adapter::base_adapter_t> > model_;
00067     RCP<Teuchos::ParameterList> pl_;
00068     RCP<Environment> env_;
00069     RCP<Teuchos::Comm<int> > comm_;
00070   
00071   public:
00072   AlgSerialGreedy(
00073     const RCP<GraphModel<typename Adapter::base_adapter_t> > &model,
00074     const RCP<Teuchos::ParameterList> &pl,
00075     const RCP<Environment> &env,
00076     const RCP<Teuchos::Comm<int> > &comm
00077   ) : model_(model), pl_(pl), env_(env), comm_(comm)
00078   {
00079   }
00080 
00081   // Main entry point for graph coloring.
00082   void color(
00083     const RCP<ColoringSolution<Adapter> > &solution
00084   )
00085   {
00086     HELLO;
00087   
00088     // Color local graph. Global coloring is supported in Zoltan (not Zoltan2).
00089     // Get local graph.
00090     ArrayView<const lno_t> edgeIds;
00091     ArrayView<const lno_t> offsets;
00092     ArrayView<StridedData<lno_t, scalar_t> > wgts; // Not used; needed by getLocalEdgeList
00093   
00094     const lno_t nVtx = model_->getLocalNumVertices(); // Assume (0,nvtx-1)
00095     model_->getLocalEdgeList(edgeIds, offsets, wgts); // Don't need wgts
00096   
00097 #if 0
00098     // Debug
00099     cout << "Debug: Local graph from getLocalEdgeList" << endl;
00100     cout << "rank " << comm_->getRank() << ": nVtx= " << nVtx << endl;
00101     cout << "rank " << comm_->getRank() << ": edgeIds: " << edgeIds << endl;
00102     cout << "rank " << comm_->getRank() << ": offsets: " << offsets << endl;
00103 #endif
00104 
00105     // Get color array to fill.
00106     // TODO: Allow user to input an old coloring.
00107     ArrayRCP<int> colors = solution->getColorsRCP();
00108     for (lno_t i=0; i<nVtx; i++){
00109       colors[i] = 0;
00110     }
00111 
00112     // Let colorCrsGraph do the real work.
00113     env_->timerStart(MACRO_TIMERS, "Coloring algorithm");
00114     colorCrsGraph(nVtx, edgeIds, offsets, colors);
00115     env_->timerStop(MACRO_TIMERS, "Coloring algorithm");
00116     return;
00117   }
00118   
00119   // Color graph given by two arrays. API may change. Expert users only!
00120   void colorCrsGraph(
00121     const lno_t nVtx,
00122     ArrayView<const lno_t> edgeIds,
00123     ArrayView<const lno_t> offsets,
00124     ArrayRCP<int> colors
00125   )
00126   {
00127     HELLO;
00128   
00129     // Find max degree, since (max degree)+1 is an upper bound.
00130     lno_t maxDegree = 0; 
00131     for (lno_t i=0; i<nVtx; i++){
00132       if (offsets[i+1]-offsets[i] > maxDegree)
00133         maxDegree = offsets[i+1]-offsets[i];
00134     }
00135 
00136     // Greedy coloring.
00137     // Use natural order for now. 
00138     // TODO: Support better orderings (e.g., Smallest-Last)
00139     int maxColor = 0;
00140  
00141     // array of size #colors: forbidden[i]=v means color[v]=i so i is forbidden
00142     Teuchos::Array<int> forbidden(maxDegree+2, 0);
00143       
00144     // LeastUsed: need array of size #colors
00145     Teuchos::Array<lno_t> numVerticesWithColor(maxDegree+2, 0);
00146 
00147     for (lno_t i=0; i<nVtx; i++){
00148       //std::cout << "Debug: i= " << i << std::endl;
00149       lno_t v=i; // TODO: Use ordering here.
00150       for (lno_t j=offsets[v]; j<offsets[v+1]; j++){
00151         lno_t nbor = edgeIds[j];
00152         //std::cout << "Debug: nbor= " << nbor << ", color= " << colors[nbor] << std::endl;
00153         if (colors[nbor] > 0){
00154           // Neighbors' colors are forbidden
00155           forbidden[colors[nbor]] = v;
00156         }
00157       }
00158 
00159       // Pick color for v
00160       std::string colorChoice = "FirstFit"; // TODO make parameter!
00161 
00162       // Keep colors[v] if possible, otherwise find valid color.
00163       if ((colors[v]==0) || ((colors[v]>0) && forbidden[colors[v]] == v)){
00164 
00165         if (colorChoice.compare("FirstFit")){
00166           // Pick first (smallest) available color > 0
00167           for (int c=1; c <= maxColor+1; c++){
00168             if (forbidden[c] != v){ 
00169               colors[v] = c;
00170               break;
00171             }
00172           }
00173         }
00174         else if (colorChoice.compare("Random")){
00175           // Pick random available color.
00176           // This is slow, please consider RandomFast instead.
00177           int numAvail = 0;
00178           Teuchos::Array<int> avail(maxColor+1);
00179           for (int c=1; c < maxColor+1; c++){
00180             if (forbidden[c] != v){ 
00181               avail[numAvail++] = c;
00182             }
00183           }
00184           if (numAvail==0)
00185             colors[v] = maxColor+1;
00186           else
00187             colors[v] = avail[rand()%numAvail];
00188         }
00189         else if (colorChoice.compare("RandomFast")){
00190           // Pick random color, then find first available color after that.
00191           bool foundColor = false;
00192           int r = (rand() % maxColor) +1;
00193           for (int c=r; c <= maxColor; c++){
00194             if (forbidden[c] != v){ 
00195               colors[v] = c;
00196               foundColor = true;
00197               break;
00198             }
00199           }
00200           if (!foundColor){ // Look for colors in [1, r)
00201             for (int c=1; c < r; c++){
00202               if (forbidden[c] != v){ 
00203                 colors[v] = c;
00204                 foundColor = true;
00205                 break;
00206               }
00207             }
00208           }
00209           if (!foundColor) colors[v] = maxColor+1;
00210         }
00211         else if (colorChoice.compare("LeastUsed")){
00212           // Pick least used available color.
00213           // Simple linear algorithm; could maintain a priority queue but not sure any faster?
00214           int leastUsedColor = 1;
00215           lno_t leastUsedNumber = numVerticesWithColor[1];
00216           for (int c=1; c <= maxColor; c++){
00217             if (forbidden[c] != v){
00218               if (numVerticesWithColor[c] < leastUsedColor){
00219                 leastUsedColor = c;
00220                 leastUsedNumber = numVerticesWithColor[c];
00221               }
00222             }
00223           }
00224           colors[v] = leastUsedColor;
00225 
00226           // Update color counts
00227           numVerticesWithColor[colors[v]]++;
00228         }
00229   
00230         if ((v==0) && colors[v]==0) colors[v]=1; // Corner case for first vertex
00231         
00232         // If we used a new color, increase maxColor.
00233         if (colors[v] > maxColor){
00234           maxColor = colors[v];
00235         }
00236       }
00237     }
00238   
00239     return;
00240   }
00241   
00242 };
00243 }
00244 #endif