//================================================================= bool BiconnectedTest::compute(const tlp::Graph* graph) { if(graph->numberOfNodes() == 0) { return true; } if (resultsBuffer.find(graph)!=resultsBuffer.end()) return resultsBuffer[graph]; MutableContainer<bool> mark; mark.setAll(false); MutableContainer<unsigned int> low; MutableContainer<unsigned int> dfsNumber; MutableContainer<node> supergraph; unsigned int count = 1; bool result = false; Iterator<node> *it=graph->getNodes(); if (it->hasNext()) result=(biconnectedTest(graph,it->next(),mark,low,dfsNumber,supergraph,count)); delete it; if (count!=graph->numberOfNodes()+1) { result=false; } //connected test resultsBuffer[graph]=result; graph->addListener(this); return result; }
/* * Returns in sortedNodes the nodes n of g sorted in increasing * order by value[n]. * Precondition: * - value[n] <= numberOfNodes for all nodes n of g, where n is * the number of * nodes in g */ void PlanarityTestImpl::sortNodesIncreasingOrder(Graph *g, MutableContainer<int> &value, vector<node> &sortedNodes) { // Counting sort; int numberOfNodes = g->numberOfNodes(); // array<int, numberOfNodes + 1> c; vector<int> c(numberOfNodes + 1); for (int i = 1; i <= numberOfNodes; ++i) c[i] = 0; // array<node, numberOfNodes + 1> a; vector<node> a(numberOfNodes + 1); int j = 0; // forall_nodes(n, g) for (auto n : g->nodes()) { a[++j] = n; } for (int i = 1; i <= numberOfNodes; ++i) { unsigned int tmp = value.get(a[i].id); ++c[tmp]; } for (int i = 2; i <= numberOfNodes; ++i) c[i] += c[i - 1]; for (int i = numberOfNodes; i > 0; i--) { sortedNodes[c[value.get(a[i].id)]] = a[i]; c[value.get(a[i].id)]--; } }
unsigned int getDist(Graph *g, node n1, node n2) { vector<node> nextNodes; TLP_HASH_MAP<node, unsigned int> nodeDepth; MutableContainer<bool> alreadyTreated; bool found = false; alreadyTreated.setAll(false); nextNodes.push_back(n1); nodeDepth[n1] = 0; alreadyTreated.set(n1.id, true); for (unsigned int i = 0; !found && i < nextNodes.size(); ++i) { node current = nextNodes[i]; for (auto v : g->getInOutNodes(current)) { if (alreadyTreated.get(v.id)) continue; alreadyTreated.set(v.id, true); nextNodes.push_back(v); nodeDepth[v] = nodeDepth[current] + 1; if (v == n2) { found = true; break; } } } return nodeDepth[n2]; }
//================================================================= list<edge> posDFS(Graph *sG, MutableContainer<int> &dfsPos) { list<edge> dfsEdges; MutableContainer<int> dfsPre; dfsPre.setAll(0); unsigned int preCount = 0; unsigned int postCount = 0; for (auto n : sG->nodes()) { if (dfsPre.get(n.id) == 0) dfsAux(sG, n, dfsPre, dfsPos, dfsEdges, preCount, postCount); } return dfsEdges; }
//================================================================= static void dfsAux(Graph *sG, node n, MutableContainer<int> &dfsPre, MutableContainer<int> &dfsPos, list<edge> &dfsEdges, unsigned int &preCount, unsigned int &postCount) { dfsPre.set(n.id, ++preCount); for (auto e : sG->getOutEdges(n)) { node target = sG->target(e); if (dfsPre.get(target.id) == 0) { dfsEdges.push_back(e); dfsAux(sG, target, dfsPre, dfsPos, dfsEdges, preCount, postCount); } } dfsPos.set(n.id, ++postCount); }
// Determines if the given graph is topologically a tree bool TreeTest::isFreeTree(const Graph *graph, node curRoot) { // do a dfs traversal from curRoot; MutableContainer<bool> visited; visited.setAll(false); stack<dfsFreeTreeStruct> dfsLevels; dfsFreeTreeStruct curParams(curRoot, curRoot, graph->getInOutNodes(curRoot)); dfsLevels.push(curParams); while (!dfsLevels.empty()) { curParams = dfsLevels.top(); curRoot = curParams.curRoot; node cameFrom = curParams.cameFrom; Iterator<node> *neighbours = curParams.neighbours; // set neighbours member to nullptr // to avoid twice deletion on exit curParams.neighbours = nullptr; if (!neighbours->hasNext()) { dfsLevels.pop(); } else { visited.set(curRoot.id, true); // loop on remaining neighbours while (neighbours->hasNext()) { node curNode = neighbours->next(); // check self loop if (curNode == curRoot) { return false; } if (curNode != cameFrom) { if (visited.get(curNode.id)) { return false; } // go deeper in the dfs exploration curParams.curRoot = curNode; curParams.cameFrom = curRoot; curParams.neighbours = graph->getInOutNodes(curNode); dfsLevels.push(curParams); break; } } } } return true; } // end isFreeTree
//==================================================== void EdgeExtremityGlyphManager::initGlyphList(Graph **graph, GlGraphInputData* glGraphInputData, MutableContainer< EdgeExtremityGlyph *>& glyphs) { GlyphContext gc = GlyphContext(graph, glGraphInputData); glyphs.setAll(0); static std::list<std::string> plugins = PluginLister::instance()->availablePlugins<EdgeExtremityGlyph>(); for(std::list<std::string>::const_iterator it = plugins.begin(); it != plugins.end(); ++it) { string glyphName = *it; EdgeExtremityGlyph *newGlyph = PluginLister::instance()->getPluginObject<EdgeExtremityGlyph>(glyphName, &gc); glyphs.set(PluginLister::pluginInformation(glyphName).id(), newGlyph); } }
void EdgeExtremityGlyphManager::clearGlyphList(Graph **, GlGraphInputData*, MutableContainer<EdgeExtremityGlyph *>& glyphs) { static std::list<std::string> plugins = PluginLister::instance()->availablePlugins<EdgeExtremityGlyph>(); for(std::list<std::string>::const_iterator it = plugins.begin(); it != plugins.end(); ++it) { string glyphName = *it; delete glyphs.get(PluginLister::pluginInformation(glyphName).id()); } }
//================================================================= list<edge> posDFS(Graph *sG, MutableContainer<int> &dfsPos) { list<edge> dfsEdges; MutableContainer<int> dfsPre; dfsPre.setAll(0); preCount = postCount = 1; StableIterator<node> it(sG->getNodes()); while (it.hasNext()) { node n = it.next(); if (dfsPre.get(n.id) == 0) dfsAux(sG, n, dfsPre, dfsPos, dfsEdges); } return dfsEdges; }
void dfsAux(Graph *sG, node n, MutableContainer<int>& dfsPre, MutableContainer<int>& dfsPos, list<edge>& dfsEdges) { dfsPre.set(n.id, preCount++); StableIterator<edge> it(sG->getOutEdges(n)); while (it.hasNext()) { edge e = it.next(); node target = sG->target(e); if (dfsPre.get(target.id) == 0) { dfsEdges.push_back(e); dfsAux(sG, target, dfsPre, dfsPos, dfsEdges); } } dfsPos.set(n.id, postCount++); }
PosibErr<void> itemize (ParmString s, MutableContainer & d) { ItemizeTokenizer els(s); ItemizeItem li; while (li = els.next(), li.name != 0) { switch (li.action) { case '+': RET_ON_ERR(d.add(li.name)); break; case '-': RET_ON_ERR(d.remove(li.name)); break; case '!': RET_ON_ERR(d.clear()); break; default: abort(); } } return no_err; }
/** * \brief Set the ordering of edges around n according to their order in v. */ void GraphStorage::setEdgeOrder(const node n, const std::vector<edge> &v ) { if (v.empty()) return; MutableContainer<int> isEle; isEle.setAll(0); for (std::vector<edge>::const_iterator it=v.begin(); it!=v.end(); ++it) { isEle.add(it->id, 1); } std::vector<edge>::const_iterator it2=v.begin(); EdgeVector& currentOrder = nodes[n.id].edges; for (unsigned int i=0; i<currentOrder.size(); ++i) { if ( isEle.get(currentOrder[i].id)>0 ) { isEle.add(currentOrder[i].id, -1); currentOrder[i] = *it2; ++it2; } } }
//================================================================= node PlanarityTestImpl::lcaBetween(node n1, node n2, const MutableContainer<node> &p) { if (isCNode(n1)) { node n = activeCNodeOf(false, n1); n1 = p.get(n.id); } if (isCNode(n2)) { node n = activeCNodeOf(false, n2); n2 = p.get(n.id); } if (dfsPosNum.get(n1.id) > dfsPosNum.get(n2.id)) swapNode(n1, n2); list<node> nl; while (dfsPosNum.get(n1.id) < dfsPosNum.get(n2.id)) { nl.push_front(n1); n1 = p.get(n1.id); } node u = NULL_NODE; if (nl.size() > 0) { u = nl.front(); nl.pop_front(); } while (n2 != u && n2 != n1 && dfsPosNum.get(n2.id) < dfsPosNum.get(n1.id)) { nl.push_front(n2); n2 = p.get(n2.id); } if (n2 == u || n2 == n1) return n2; return nl.front(); }
/* * Returns in sortedNodes the nodes n of g sorted in increasing * order by value[n]. * Precondition: * - value[n] <= numberOfNodes for all nodes n of g, where n is * the number of * nodes in g */ void PlanarityTestImpl::sortNodesIncreasingOrder(Graph *g, MutableContainer<int> &value, vector<node> &sortedNodes) { // Counting sort; int numberOfNodes = g->numberOfNodes(); //array<int, numberOfNodes + 1> c; vector<int> c(numberOfNodes + 1); for (int i = 1 ; i <= numberOfNodes ; i++) c[i] = 0; //array<node, numberOfNodes + 1> a; vector<node> a(numberOfNodes + 1); int j = 0; node n; // forall_nodes(n, g) Iterator<node> *it = g->getNodes(); while (it->hasNext()) { //a[++j] = n; a[++j] = it->next(); } delete it; for (int i = 1 ; i <= numberOfNodes ; i++) { unsigned int tmp = value.get(a[i].id); c[tmp]++; } for (int i = 2 ; i <= numberOfNodes ; i++) c[i] += c[i-1]; for (int i = numberOfNodes ; i > 0 ; i--) { sortedNodes[c[value.get(a[i].id)]] = a[i]; c[value.get(a[i].id)]--; } }
bool run() { result->setAllNodeValue(0.0); result->setAllEdgeValue(0.0); bool directed = false; bool norm = false; if ( dataSet!=NULL ) { dataSet->get("directed",directed); dataSet->get("norm", norm); } //Metric is 0 in this case if(graph->numberOfNodes()<=2) return true; Iterator<node> *it = graph->getNodes(); unsigned int count = 0; while(it->hasNext()) { if (pluginProgress->progress(count++,graph->numberOfNodes())!=TLP_CONTINUE) break; node s = it->next(); stack<node> S; TLP_HASH_MAP<node, list<node> > P; MutableContainer<int> sigma; sigma.setAll(0); sigma.set(s.id,1); MutableContainer<int> d; d.setAll(-1); d.set(s.id, 0); queue<node> Q; Q.push(s); while(!Q.empty()) { node v = Q.front(); Q.pop(); S.push(v); Iterator<node> *it2; if (directed) it2 = graph->getOutNodes(v); else it2 = graph->getInOutNodes(v); while (it2->hasNext()) { node w = it2->next(); if (d.get(w.id)<0) { Q.push(w); d.set(w.id, d.get(v.id)+1); } if (d.get(w.id) == d.get(v.id)+1) { sigma.add(w.id, sigma.get(v.id)); P[w].push_back(v); } } delete it2; } MutableContainer<double> delta; delta.setAll(0.0); while(!S.empty()) { node w = S.top(); S.pop(); list<node>::const_iterator itn = P[w].begin(); for (; itn!=P[w].end(); ++itn) { node v = *itn; delta.add(v.id, (double(sigma.get(v.id)) / double(sigma.get(w.id)) * (1.0 + delta.get(w.id)))); edge e = graph->existEdge(v,w,directed); if(e.isValid()) result->setEdgeValue(e, result->getEdgeValue(e) + double(sigma.get(v.id)) / double(sigma.get(w.id)) * (1.0 + delta.get(w.id))); } if (w != s) result->setNodeValue(w, result->getNodeValue(w) + delta.get(w.id)); } } delete it; //Normalization if(norm || !directed) { double n = graph->numberOfNodes(); it = graph->getNodes(); while(it->hasNext()) { node s = it->next(); //In the undirected case, the metric must be divided by two, then if(norm) result->setNodeValue(s,result->getNodeValue(s)/((n-1.0)*(n-2.0))); if(!directed) result->setNodeValue(s,result->getNodeValue(s)/2.0); } delete it; Iterator<edge> *itE = graph->getEdges(); while(itE->hasNext()) { edge e = itE->next(); if(norm) result->setEdgeValue(e,4.0*result->getEdgeValue(e)/(n*n)); if(!directed) result->setEdgeValue(e,result->getEdgeValue(e)/(2.0)); } delete itE; } return pluginProgress->state()!=TLP_CANCEL; }
//================================================================= bool biconnectedTest(const Graph *graph, node v, MutableContainer<bool> &mark, MutableContainer<unsigned int> &low, MutableContainer<unsigned int> &dfsNumber, MutableContainer<node> &supergraph, unsigned int &count) { mark.set(v.id,true); dfsNumber.set(v.id,count); low.set(v.id,count); ++count; Iterator<node> *it=graph->getInOutNodes(v); while (it->hasNext()) { node w=it->next(); if (!mark.get(w.id)) { if (dfsNumber.get(v.id)==1) { if (count != 2) { delete it; return false; } } supergraph.set(w.id,v); if (!biconnectedTest(graph,w,mark,low,dfsNumber,supergraph,count)) { delete it; return false; } if (dfsNumber.get(v.id)!=1) { if (low.get(w.id)>=dfsNumber.get(v.id)) { delete it; return false; } else low.set(v.id, std::min(low.get(v.id), low.get(w.id))); } } else if (supergraph.get(v.id)!=w) { low.set(v.id, std::min(low.get(v.id), dfsNumber.get(w.id))); } } delete it; return true; }
static void makeBiconnectedDFS(Graph *graph, vector<edge> &addedEdges) { // the graph is already connected // so get any node to begin node from = graph->getOneNode(); if (!from.isValid()) return; MutableContainer<int> low; MutableContainer<int> depth; depth.setAll(-1); MutableContainer<node> supergraph; supergraph.setAll(node()); // dfs loop stack<dfsBiconnectStruct> dfsLevels; dfsBiconnectStruct dfsParams(graph, from); dfsLevels.push(dfsParams); depth.set(from.id, 0); low.set(from.id, 0); while(!dfsLevels.empty()) { dfsParams = dfsLevels.top(); from = dfsParams.from; node u = dfsParams.first; //for every node connected to from Iterator<node>* itN = dfsParams.inOutNodes; while (itN->hasNext()) { node to = itN->next(); //if there is a loop, ignore it if (from == to) { continue; } if (!u.isValid()) { dfsLevels.top().first = u = to; } //if the destination node has not been visited, visit it if (depth.get(to.id) == -1) { supergraph.set(to.id, from); dfsParams.from = to; dfsParams.first = node(); dfsParams.u = u; unsigned int currentDepth = dfsParams.depth + 1; dfsParams.depth = currentDepth; depth.set(to.id, currentDepth); low.set(to.id, currentDepth); dfsParams.inOutNodes = new StableIterator<node>(graph->getInOutNodes(to)); break; } else { low.set(from.id, std::min(low.get(from.id), depth.get(to.id))); } } if (from != dfsParams.from) { dfsLevels.push(dfsParams); continue; } delete itN; // pop the current dfsParams node to = dfsParams.from; from = supergraph.get(to.id); u = dfsParams.u; if (low.get(to.id) == depth.get(from.id)) { if (to == u && supergraph.get(from.id).isValid()) addedEdges.push_back(graph->addEdge(to, supergraph.get(from.id))); if (to != u) addedEdges.push_back(graph->addEdge(u, to)); } low.set(from.id, std::min(low.get(from.id), low.get(to.id))); dfsLevels.pop(); } }
/* * Algebric criteria to check the plane map... */ bool PlanarityTestImpl::isPlanarEmbedding(Graph *sG) { int n = sG->numberOfNodes(); if (n == 1) return true; int m = sG->numberOfEdges(); unsigned int count = 0; MutableContainer<char> considered; MutableContainer<bool> sens; considered.setAll(0); sens.setAll(false); int fc = 0; // displayMap(sG); for (int k=0; k<2; ++k) { Iterator<edge> *it = sG->getEdges(); while (it->hasNext()) { edge e = it->next(); if (considered.get(e.id)<2) { count = 0; // cerr << "Face : " << fc << " start edge:" << e.id << endl; edge e1 = e; node n, n_tmp; if (sens.get(e.id)) n = sG->target(e1); else n = sG->source(e1); // cerr << "-(" << e1.id << ")->" << n.id << flush; n_tmp = n; do { considered.add(e1.id, 1); EdgeMapIterator it(sG, e1, n); e1 = it.next(); n = sG->opposite(e1,n); if (sG->source(e1) == n) sens.set(e1.id,true); // cerr << "-(" << e1.id << ")->" << n.id << flush; ++count; if (count > sG->numberOfEdges() +1) break; } while ((e1 != e)||(n != n_tmp)); fc++; // cerr << endl; } } delete it; } if (fc != m - n + 2) { //cerr << __PRETTY_FUNCTION__ << " : not ok :( nb faces :" << fc << "!=" << m - n +2 << endl; return false; } return true; }
void makeBiconnectedDFS(Graph *graph, node from, MutableContainer<int> &low, MutableContainer<int> &depth, MutableContainer<node> &supergraph, unsigned int ¤tDepth, vector<edge> &addedEdges) { node u; depth.set(from.id, currentDepth++); low.set(from.id, depth.get(from.id)); //for every node connected to this one, call this function so it runs on every node. StableIterator<node> itN(graph->getInOutNodes(from)); while (itN.hasNext()) { node to = itN.next(); //if there is a loop, ignore it if (from == to) { continue; } if (!u.isValid()) { u = to; } //if the destination node has not been visited, visit it if (depth.get(to.id) == -1) { supergraph.set(to.id, from); makeBiconnectedDFS(graph, to, low, depth, supergraph, currentDepth, addedEdges); if (low.get(to.id) == depth.get(from.id)) { if (to == u && supergraph.get(from.id).isValid()) addedEdges.push_back(graph->addEdge(to, supergraph.get(from.id))); if (to != u) addedEdges.push_back(graph->addEdge(u, to)); } low.set(from.id, std::min(low.get(from.id), low.get(to.id))); } else { low.set(from.id, std::min(low.get(from.id), depth.get(to.id))); } } }
/** * update is_selectable_visited and is_selectable */ void Ordering::updateNewSelectableNodes(node node_f, node no_tmp2 ,edge, node node_last, vector<Face> v_faces, bool one_face,bool was_visited, bool selection_face) { MutableContainer<bool> tried; tried.setAll(false); node n = node_f; node tmp = no_tmp2; node tmp2 = node() ; unsigned int lim = v_faces.size(); while(n != node_last) { tmp2 = n; if(Gp->deg(n) > 2 && isSelectable(n)) { if(visitedNodes.get(n.id)) is_selectable_visited.set(n.id,true); else is_selectable.set(n.id,true); } else { is_selectable_visited.set(n.id,false); is_selectable.set(n.id,false); } tried.set(n.id,true); n = tmp; tmp = right.get(n.id); } if(Gp->deg(n) > 2 && isSelectable(n)) is_selectable_visited.set(n.id,true); else { is_selectable_visited.set(n.id,false); is_selectable.set(n.id,false); } if(one_face) { if(tmp2 == node()) tmp2 = node_f; Iterator<node> * it_no = Gp->getFaceNodes(Gp->getFaceContaining(tmp2,node_last)); while(it_no->hasNext()) { node no_tmp = it_no->next(); if(!tried.get(no_tmp.id)) { bool on_c = contour.get(no_tmp.id); if(on_c) { bool sel = isSelectable(no_tmp); if(sel) if(visitedNodes.get(no_tmp.id)) is_selectable_visited.set(no_tmp.id,true); else is_selectable.set(no_tmp.id, true); else { is_selectable_visited.set(no_tmp.id,false); is_selectable_visited.set(no_tmp.id,false); } } tried.set(no_tmp.id,true); } } delete it_no; lim--; } if((selection_face && was_visited) || !selection_face) for(unsigned int i = 0; i < lim; ++i) { bool face_sel = false; Face f_tmp = v_faces[i]; if(is_selectable_face.get(f_tmp.id) || is_selectable_visited_face.get(f_tmp.id)) face_sel = true; Iterator<node> * itn = Gp->getFaceNodes(f_tmp); if(face_sel) while(itn->hasNext()) { node no_tmp = itn->next(); is_selectable.set(no_tmp.id,false); is_selectable_visited.set(no_tmp.id,false); tried.set(no_tmp.id,true); } else { while(itn->hasNext()) { node no_tmp = itn->next(); if(!tried.get(no_tmp.id) && (is_selectable_visited.get(no_tmp.id) || is_selectable.get(no_tmp.id))) { if(!isSelectable(no_tmp)) { is_selectable_visited.set(no_tmp.id,false); is_selectable.set(no_tmp.id,false); } } tried.set(no_tmp.id,true); } } delete itn; } }
//#include <tulip/GraphImpl.h> int PlanarityTestImpl::sortBackEdgesByDfs(Graph *sG, node, node repr, list<edge>& listBackEdges, vector<edge>& backEdge) { // constructs a DFS tree of T_v^* to sort back-edges to embed; // cerr << __PRETTY_FUNCTION__ << endl; Graph *D = tlp::newGraph(); list<node> listNodes, listCNodes; //map<node, node> nodeInD, nodeInG; map<node,node> nodeInD, nodeInG; nodeInD[repr] = D->addNode(); nodeInG[nodeInD[repr]] = repr; // forall(e, listBackEdges) for (list<edge>::iterator it = listBackEdges.begin(); it != listBackEdges.end(); it++) { edge e = *it; node u = sG->source(e); node predU = NULL_NODE; while (state.get(u.id) == NOT_VISITED) { if (isCNode(u)) { u = activeCNodeOf(false, u); if (state.get(u.id) == NOT_VISITED) listCNodes.push_back(u); } if (state.get(u.id) == NOT_VISITED) { state.set(u.id, VISITED); listNodes.push_back(u); nodeInD[u] = D->addNode(); nodeInG[nodeInD[u]] = u; } if (predU != NULL_NODE) D->addEdge(nodeInD[u], nodeInD[predU]); predU = u; u = parent.get(u.id); } if (predU != NULL_NODE) D->addEdge(nodeInD[u], nodeInD[predU]); } //forall(v, listNodes) for (list<node>::iterator it = listNodes.begin() ; it != listNodes.end() ; it++) state.set((*it).id, NOT_VISITED); // creates edges from c-nodes; map<node, bool> isInD; //forall(v, listCNodes) for (list<node>::iterator it = listCNodes.begin(); it != listCNodes.end(); it++) { node v = *it; // node u; BmdListIt<node> bmItn(RBC[v]); while(bmItn.hasNext()) isInD[bmItn.next()] = false; list<edge> el; StableIterator<edge> stableEdgeIt(D->getOutEdges(nodeInD[v])); while (stableEdgeIt.hasNext()) { edge e = stableEdgeIt.next(); isInD[nodeInG[D->target(e)]] = true; el.push_back(e); } //D.del_edges(el); for (list<edge>::iterator edgeIt = el.begin() ; edgeIt != el.end() ; ++edgeIt) D->delEdge(*edgeIt); BmdListRevIt<node> itR(RBC[v]); while (itR.hasNext()) { node u = itR.next(); if(isInD[u]) D->addEdge(nodeInD[v], nodeInD[u]); } } // orders back-edges by DFS number; //node_array<int> dfspos(D, 0); MutableContainer<int> dfsPos; dfsPos.setAll(0); posDFS(D, dfsPos); int tot = D->numberOfNodes(); backEdge.resize(tot + 1); //Warning backEdge[0] = NULL_EDGE; for (int i = 1 ; i <= tot ; i++) backEdge[i] = NULL_EDGE; //forall(e, listBackEdges) for (list<edge>::iterator it = listBackEdges.begin() ; it != listBackEdges.end() ; ++it) { edge e = *it; node v = sG->source(e); // cout << v.id << endl; // cout << "nodeInD[v].id = " << nodeInD.get(v.id).id << endl; // cout << "dfsPos.get(nodeInD[v].id) = " << dfsPos.get(nodeInD.get(v.id).id) << endl; backEdge[dfsPos.get(nodeInD[v].id)] = e; } delete D; return tot; }
//********************************************************************** bool AcyclicTest::acyclicTest(const Graph *graph, vector<edge> *obstructionEdges) { MutableContainer<bool> visited; MutableContainer<bool> finished; visited.setAll(false); finished.setAll(false); bool result = true; // do a dfs traversal Iterator<node> *it = graph->getNodes(); while (it->hasNext()) { node curNode = it->next(); if (!visited.get(curNode.id)) { stack<node> nodesToVisit; nodesToVisit.push(curNode); stack<Iterator<edge>*> neighboursToVisit; neighboursToVisit.push(graph->getOutEdges(curNode)); while(!nodesToVisit.empty()) { curNode = nodesToVisit.top(); Iterator<edge> *ite = neighboursToVisit.top(); // check if dfs traversal of curNode neighbours is finished if (!ite->hasNext()) { // unstack curNode nodesToVisit.pop(); // delete & unstack neightbours iterator delete neighboursToVisit.top(); neighboursToVisit.pop(); // mark curNode as to be skipped // during further exploration finished.set(curNode.id, true); } else { visited.set(curNode.id, true); // loop on remaining neighbours while (ite->hasNext()) { edge tmp = ite->next(); node neighbour = graph->target(tmp); // check if we are already in the exploration // of the neighbours of neighbour if (visited.get(neighbour.id)) { if (!finished.get(neighbour.id)) { // found a cycle result = false; if (obstructionEdges != NULL) obstructionEdges->push_back(tmp); else { // it is finished if we don't need // to collect obstruction edges break; } } } else { // found a new neighbour to explore // go deeper in our dfs traversal nodesToVisit.push(neighbour); neighboursToVisit.push(graph->getOutEdges(neighbour)); break; } } // it may be finished if we don't need // to collect obstruction edges if ((!result) && (obstructionEdges == NULL)) break; } } // it may be finished if we don't need // to collect obstruction edges if ((!result) && (obstructionEdges == NULL)) { // don't froget to delete remaining iterators while(!neighboursToVisit.empty()) { delete neighboursToVisit.top(); neighboursToVisit.pop(); } break; } } } delete it; return result; }