SCC.cpp

Go to the documentation of this file.
00001 
00024 //************************** System Include Files ***************************
00025 
00026 #include <cassert>
00027 
00028 #include <map>
00029 #include <set>
00030 #include <stack>
00031 
00032 //*************************** User Include Files ****************************
00033 
00034 #include <OpenAnalysis/Utils/SCC.hpp>
00035 #include <OpenAnalysis/Utils/Util.hpp>
00036 
00037 //*************************** Forward Declarations **************************
00038 
00039 //------------------------------------------------------------------------
00040 // LowLinkState is a private data structure used for finding SCC
00041 // components.
00042 //------------------------------------------------------------------------
00043 
00044 namespace OA {
00045 
00046 class LowLinkState {
00047 public:
00048   LowLinkState(OA::OA_ptr<OA::RIFG> rifg_) : rifg(rifg_), mCount(1) { 
00049     unsigned int sz = rifg->getHighWaterMarkNodeId() + 1;
00050     mNodeStatus = new SCCNodeStatus[sz];
00051   }
00052   
00053   ~LowLinkState() { 
00054     delete[] mNodeStatus;
00055   }
00056   
00057   // Mark methods
00058   void Mark(OA::RIFG::NodeId nid) 
00059     { mOld.insert(nid); }
00060   unsigned int IsMarked(OA::RIFG::NodeId nid) { 
00061     MyNodeIdSet::const_iterator it = mOld.find(nid);
00062     return (it != mOld.end()); 
00063   }
00064 
00065   // Lowlink and depth-first methods
00066   unsigned int& LOWLINK(OA::RIFG::NodeId nid) 
00067     { return mNodeStatus[nid].lowlink; }
00068 
00069   unsigned int& DFNUMBER(OA::RIFG::NodeId nid) 
00070     { return mNodeStatus[nid].dfnumber; }
00071   
00072   unsigned int& Count() 
00073     { return mCount; }
00074   
00075   // Stack methods
00076   void Push(OA_ptr<DGraph::Interface::Node> node, OA::RIFG::NodeId nid) {
00077     mNodeStatus[nid].inStack = true;
00078     mNodeStack.push(node);
00079   }
00080   
00081   OA_ptr<DGraph::Interface::Node> Top()
00082     { return mNodeStack.top(); }
00083 
00084   OA_ptr<DGraph::Interface::Node> Pop() {
00085     OA_ptr<DGraph::Interface::Node> node = mNodeStack.top();
00086     OA::RIFG::NodeId nid = rifg->getNodeId(node);
00087     mNodeStack.pop();
00088     mNodeStatus[nid].inStack = false;
00089     return node; 
00090   }
00091   
00092   bool IsOnStack(OA::RIFG::NodeId nid) 
00093     { return mNodeStatus[nid].inStack; }
00094 
00095 private:
00096   
00097   // SCCNodeStatus is a data structure to describe the current status
00098   // of a SCC node.
00099   class SCCNodeStatus {
00100   public:
00101     SCCNodeStatus(unsigned int l=0, unsigned int d=0, bool i=false)
00102       : lowlink(l), dfnumber(d), inStack(i) { }
00103     
00104     unsigned int lowlink;
00105     unsigned int dfnumber;
00106     bool inStack;
00107   };
00108 
00109   typedef std::set<OA::RIFG::NodeId> MyNodeIdSet;
00110 
00111   typedef std::stack<OA_ptr<DGraph::Interface::Node> > MyNodeStack;
00112   
00113 private:
00114   OA::OA_ptr<OA::RIFG> rifg;
00115 
00116   unsigned int mCount;
00117   SCCNodeStatus* mNodeStatus; // indexed by OA::RIFG::NodeId
00118   MyNodeIdSet mOld;
00119   MyNodeStack mNodeStack;
00120 };
00121 
00122 } // end of namespace OA
00123 
00124 
00125 //*************************** Forward Declarations **************************
00126 
00127 static void 
00128 CreateHelper(OA::SCCSet* sccSet, 
00129              OA::OA_ptr<OA::RIFG> rifg,
00130              OA::OA_ptr<OA::DGraph::Interface::Node> v, 
00131              OA::RIFG::NodeId vid,
00132              OA::LowLinkState* state);
00133 
00134 
00135 //***************************************************************************
00136 
00137 
00138 //***************************************************************************
00139 // SCCSet
00140 //***************************************************************************
00141 
00142 namespace OA {
00143 
00144 SCCSet::SCCSet() 
00145 {
00146 }
00147 
00148 
00149 SCCSet::SCCSet(OA_ptr<DGraph::Interface> graph,
00150                OA_ptr<RIFG> rifg) 
00151 {
00152   if (rifg.ptrEqual(0)) {
00153     rifg = new OA::RIFG(graph, RIFG::getSourceNode(graph), 
00154                         RIFG::getSinkNode(graph));
00155   }
00156   // assert(rifg->getGraph() == graph);
00157   Create(graph, rifg);
00158 }
00159 
00160 
00161 void
00162 SCCSet::Create(OA_ptr<DGraph::Interface> graph,
00163                OA_ptr<RIFG> rifg)
00164 {
00165   // Note: We use a RIFG in order to get dense node ids between 1 and n.
00166   LowLinkState *state = new LowLinkState(rifg);
00167   //LowLinkState *state = &ST;
00168   
00169   // if there exists a node not marked yet, visit it.
00170   OA_ptr<DGraph::Interface::NodesIterator> it = graph->getNodesIterator();
00171   for (; it->isValid(); ++(*it)) {
00172     OA_ptr<DGraph::Interface::Node> node = it->current();
00173     OA::RIFG::NodeId nid = rifg->getNodeId(node);
00174     if ( !state->IsMarked(nid) ) {
00175       CreateHelper(this, rifg, node, nid, state);
00176     }
00177   }
00178 }
00179 
00180 
00181 SCCSet::~SCCSet()
00182 {
00183   Destroy();
00184 }
00185 
00186 
00187 void
00188 SCCSet::Destroy()
00189 {
00190   this->clear();
00191 }
00192 
00193 
00194 OA_ptr<SCCNodeSet> 
00195 SCCSet::NodeToSCC(const OA_ptr<DGraph::Interface::Node> node)
00196 {
00197   // N.B.: The implementation is a linear search and direct
00198   // translation from the DSystem code.  However, if this is going to
00199   // be used a lot, we should probably create a map.
00200   for (self_t::const_iterator it = this->begin(); it != this->end(); ++it) {
00201     OA_ptr<SCCNodeSet> scc = *it;
00202     if (scc->find(node) != scc->end()) {
00203       return scc;
00204     }
00205   }
00206   assert(false);               // every node should be in a set
00207   return OA_ptr<SCCNodeSet>(); // never reached!
00208 }
00209 
00210 
00211 void 
00212 SCCSet::dump(std::ostream& os)
00213 {
00214   using std::endl;
00215 
00216   os << "{ SCCSet: num SCC sets: " << this->size() << endl;
00217   for (self_t::iterator it = this->begin(); it != this->end(); ++it) {
00218     OA_ptr<SCCNodeSet> scc = *it;
00219     
00220     os << "  { SCC: ";
00221     SCCNodeSet::iterator sccIt = scc->begin();
00222     for ( ; sccIt != scc->end(); ++sccIt) {
00223       OA_ptr<DGraph::Interface::Node> node = *sccIt;
00224       os << node->getId() << " ";
00225     }
00226     os << "}" << endl;
00227   } 
00228 }
00229 
00230 
00231 } // end of namespace OA
00232 
00233 
00234 //***************************************************************************
00235 // SCCSet helpers
00236 //***************************************************************************
00237 
00238 static void 
00239 CreateHelper(OA::SCCSet* sccSet, 
00240              OA::OA_ptr<OA::RIFG> rifg,
00241              OA::OA_ptr<OA::DGraph::Interface::Node> v, 
00242              OA::RIFG::NodeId vid,
00243              OA::LowLinkState* state)
00244 {
00245   using namespace OA;
00246   
00247   state->Mark(vid);                           // mark v
00248   state->DFNUMBER(vid) = state->Count();      // set dfnumber
00249   state->Count()++;                           // increment count by 1
00250   state->LOWLINK(vid) = state->DFNUMBER(vid); // set lowlink number
00251   state->Push(v, vid);                        // push v into stack
00252   
00253   // for each w which is on the adjacency list of v, there is an edge v->w
00254   OA::OA_ptr<OA::DGraph::Interface::NodesIterator> it = 
00255     v->getSinkNodesIterator();
00256   for (; it->isValid(); ++(*it)) {
00257     OA_ptr<DGraph::Interface::Node> w = it->current();
00258     OA::RIFG::NodeId wid = rifg->getNodeId(w);
00259     
00260     // if w is not marked yet
00261     if (!state->IsMarked(wid)) { 
00262       CreateHelper(sccSet, rifg, w, wid, state); 
00263       state->LOWLINK(vid) = OA_MIN(state->LOWLINK(vid), state->LOWLINK(wid));
00264     } 
00265     // w is already marked
00266     else {
00267       if ( state->DFNUMBER(wid) < state->DFNUMBER(vid) && 
00268            state->IsOnStack(wid) ) {
00269         state->LOWLINK(vid) = OA_MIN(state->DFNUMBER(wid), 
00270                                      state->LOWLINK(vid));
00271       }
00272     }
00273   }
00274 
00275   // if lowlink[v] == DFNumber[v], the current Node in stack above
00276   // v form a SCC. 
00277   if ( state->LOWLINK(vid) == state->DFNUMBER(vid) ) {
00278     OA_ptr<SCCNodeSet> scc; scc = new SCCNodeSet;
00279     
00280     // pop x from top of stack, until x == v
00281     OA_ptr<DGraph::Interface::Node> x;
00282     do {
00283       x = state->Pop();
00284       scc->insert(x);
00285     } while (x != v);
00286 
00287     // the SCC is complete now, add it to sccSet.
00288     sccSet->insert(scc);
00289   }
00290 }
00291 

Generated on Fri Nov 7 05:21:52 2008 for OpenAnalysis by  doxygen 1.5.5