bool FeasibleUpwardPlanarSubgraph::constructMergeGraph( GraphCopy &M, adjEntry adj_orig, const List<edge> &orig_edges) { CombinatorialEmbedding Beta(M); //set ext. face of Beta adjEntry ext_adj = M.copy(adj_orig->theEdge())->adjSource(); Beta.setExternalFace(Beta.rightFace(ext_adj)); FaceSinkGraph fsg(Beta, M.copy(adj_orig->theNode())); SList<node> aug_nodes; SList<edge> aug_edges; SList<face> fList; fsg.possibleExternalFaces(fList); // use this method to call the methode checkForest() node v_ext = fsg.faceNodeOf(Beta.externalFace()); OGDF_ASSERT(v_ext != 0); fsg.stAugmentation(v_ext, M, aug_nodes, aug_edges); //add the deleted edges for(edge eOrig: orig_edges) { node a = M.copy(eOrig->source()); node b = M.copy(eOrig->target()); M.newEdge(a, b); } return (isAcyclic(M)); }
void SubgraphUpwardPlanarizer::constructComponentGraphs(BCTree &BC, NodeArray<GraphCopy> &biComps) { NodeArray<int> constructed(BC.originalGraph(), -1); const Graph &bcTree = BC.bcTree(); int i = 0; // comp. number for(node v : bcTree.nodes) { if (BC.typeOfBNode(v) == BCTree::CComp) continue; const SList<edge> &edges_comp = BC.hEdges(v); //bicomp edges List<edge> edges_orig; for(edge e : edges_comp) edges_orig.pushBack(BC.original(e)); GraphCopy GC; GC.createEmpty(BC.originalGraph()); // construct i-th component graph for(edge eOrig : edges_orig) { node srcOrig = eOrig->source(); node tgtOrig = eOrig->target(); if (constructed[srcOrig] != i) { constructed[srcOrig] = i; GC.newNode(srcOrig); } if (constructed[tgtOrig] != i) { constructed[tgtOrig] = i; GC.newNode(tgtOrig); } GC.newEdge(eOrig); } biComps[v] = GC; i++; } }
Module::ReturnType FeasibleUpwardPlanarSubgraph::call( const Graph &G, GraphCopy &FUPS, adjEntry &extFaceHandle, List<edge> &delEdges, bool multisources) { FUPS = GraphCopy(G); delEdges.clear(); node s_orig; hasSingleSource(G, s_orig); List<edge> nonTreeEdges_orig; getSpanTree(FUPS, nonTreeEdges_orig, true, multisources); CombinatorialEmbedding Gamma(FUPS); nonTreeEdges_orig.permute(); // random order //insert nonTreeEdges while (!nonTreeEdges_orig.empty()) { // make identical copy GC of Fups //and insert e_orig in GC GraphCopy GC = FUPS; edge e_orig = nonTreeEdges_orig.popFrontRet(); //node a = GC.copy(e_orig->source()); //node b = GC.copy(e_orig->target()); GC.newEdge(e_orig); if (UpwardPlanarity::upwardPlanarEmbed_singleSource(GC)) { //upward embedded the fups and check feasibility CombinatorialEmbedding Beta(GC); //choose a arbitrary feasibel ext. face FaceSinkGraph fsg(Beta, GC.copy(s_orig)); SList<face> ext_faces; fsg.possibleExternalFaces(ext_faces); OGDF_ASSERT(!ext_faces.empty()); Beta.setExternalFace(ext_faces.front()); GraphCopy M = GC; // use a identical copy of GC to constrcut the merge graph of GC adjEntry extFaceHandle_cur = getAdjEntry(Beta, GC.copy(s_orig), Beta.externalFace()); adjEntry adj_orig = GC.original(extFaceHandle_cur->theEdge())->adjSource(); if (constructMergeGraph(M, adj_orig, nonTreeEdges_orig)) { FUPS = GC; extFaceHandle = FUPS.copy(GC.original(extFaceHandle_cur->theEdge()))->adjSource(); continue; } else { //Beta is not feasible delEdges.pushBack(e_orig); } } else { // not ok, GC is not feasible delEdges.pushBack(e_orig); } } return Module::retFeasible; }
void UpwardPlanarSubgraphSimple::call(GraphCopy &GC, List<edge> &delEdges) { const Graph &G = GC.original(); delEdges.clear(); // We construct an auxiliary graph H which represents the current upward // planar subgraph. Graph H; NodeArray<node> mapToH(G,nullptr); NodeArray<node> mapToG(H,nullptr); for(node v : G.nodes) mapToG[ mapToH[v] = H.newNode() ] = v; // We currently support only single-source acyclic digraphs ... node s; hasSingleSource(G,s); OGDF_ASSERT(s != 0); OGDF_ASSERT(isAcyclic(G)); // We start with a spanning tree of G rooted at the single source. NodeArray<bool> visitedNode(G,false); SListPure<edge> treeEdges; dfsBuildSpanningTree(s,treeEdges,visitedNode); // Mark all edges in the spanning tree so they can be skipped in the // loop below and add (copies of) them to H. EdgeArray<bool> visitedEdge(G,false); SListConstIterator<edge> it; for(it = treeEdges.begin(); it.valid(); ++it) { edge eG = *it; visitedEdge[eG] = true; H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); } // Add subsequently the remaining edges to H and test if the resulting // graph is still upward planar. If not, remove the edge again from H // and add it to delEdges. SList<Tuple2<node,node> > augmented; GraphCopySimple graphAcyclicTest(G); for(edge eG : G.edges) { // already treated ? if(visitedEdge[eG] == true) continue; // insert edge into H edge eH = H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); node superSink; SList<edge> augmentedEdges; if (UpwardPlanarity::upwardPlanarAugment_singleSource(H,superSink,augmentedEdges) == false) { // if H is no longer upward planar, remove eG from subgraph H.delEdge(eH); delEdges.pushBack(eG); } else { // add augmented edges as node-pair to tmpAugmented and remove // all augmented edges from H again SList<Tuple2<node,node> > tmpAugmented; SListConstIterator<edge> it; for(it = augmentedEdges.begin(); it.valid(); ++it) { node v = mapToG[(*it)->source()]; node w = mapToG[(*it)->target()]; if (v && w) tmpAugmented.pushBack(Tuple2<node,node>(v,w)); H.delEdge(*it); } if (mapToG[superSink] == nullptr) H.delNode(superSink); //**************************************************************** // The following is a simple workaround to assure the following // property of the upward planar subgraph: // The st-augmented upward planar subgraph plus the edges not // in the subgraph must be acyclic. (This is a special property // of the embedding, not the augmentation.) // The upward-planar embedding function gives us ANY upward-planar // embedding. We check if the property above holds with this // embedding. If it doesn't, we have actually no idea if another // embedding would do. // The better solution would be to incorporate the acyclicity // property into the upward-planarity test, but this is compicated. //**************************************************************** // test if original graph plus augmented edges is still acyclic if(checkAcyclic(graphAcyclicTest,tmpAugmented) == true) { augmented = tmpAugmented; } else { // if not, remove eG from subgraph H.delEdge(eH); delEdges.pushBack(eG); } } } // remove edges not in the subgraph from GC ListConstIterator<edge> itE; for(itE = delEdges.begin(); itE.valid(); ++itE) GC.delEdge(GC.copy(*itE)); // add augmented edges to GC SListConstIterator<Tuple2<node,node> > itP; for(itP = augmented.begin(); itP.valid(); ++itP) { node v = (*itP).x1(); node w = (*itP).x2(); GC.newEdge(GC.copy(v),GC.copy(w)); } // add super sink to GC node sGC = nullptr; SList<node> sinks; for(node v : GC.nodes) { if(v->indeg() == 0) sGC = v; if(v->outdeg() == 0) sinks.pushBack(v); } node superSinkGC = GC.newNode(); SListConstIterator<node> itV; for(itV = sinks.begin(); itV.valid(); ++itV) GC.newEdge(*itV,superSinkGC); // add st-edge to GC, so that we now have a planar st-digraph GC.newEdge(sGC,superSinkGC); OGDF_ASSERT(isAcyclic(GC)); OGDF_ASSERT(isPlanar(GC)); }
bool FUPSSimple::constructMergeGraph(GraphCopy &M, adjEntry adj_orig, const List<edge> &orig_edges) { CombinatorialEmbedding Beta(M); //set ext. face of Beta adjEntry ext_adj = M.copy(adj_orig->theEdge())->adjSource(); Beta.setExternalFace(Beta.rightFace(ext_adj)); //*************************** debug ******************************** /* cout << endl << "FUPS : " << endl; for(face ff : Beta.faces) { cout << "face " << ff->index() << ": "; adjEntry adjNext = ff->firstAdj(); do { cout << adjNext->theEdge() << "; "; adjNext = adjNext->faceCycleSucc(); } while(adjNext != ff->firstAdj()); cout << endl; } if (Beta.externalFace() != 0) cout << "ext. face of the graph is: " << Beta.externalFace()->index() << endl; else cout << "no ext. face set." << endl; */ FaceSinkGraph fsg(Beta, M.copy(adj_orig->theNode())); SList<node> aug_nodes; SList<edge> aug_edges; SList<face> fList; fsg.possibleExternalFaces(fList); // use this method to call the methode checkForest() node v_ext = fsg.faceNodeOf(Beta.externalFace()); OGDF_ASSERT(v_ext != 0); fsg.stAugmentation(v_ext, M, aug_nodes, aug_edges); /* //------------------------------------debug GraphAttributes AG(M, GraphAttributes::nodeGraphics| GraphAttributes::edgeGraphics| GraphAttributes::nodeColor| GraphAttributes::edgeColor| GraphAttributes::nodeLabel| GraphAttributes::edgeLabel ); // label the nodes with their index for(node v : AG.constGraph().nodes) { AG.label(v) = to_string(v->index()); } AG.writeGML("c:/temp/MergeFUPS.gml"); */ OGDF_ASSERT(isStGraph(M)); //add the deleted edges for(edge eOrig : orig_edges) { node a = M.copy(eOrig->source()); node b = M.copy(eOrig->target()); M.newEdge(a, b); } return (isAcyclic(M)); }
/* * Construct the realiszer and the Tree T * rValues = realizer value * T = Tree */ void SchnyderLayout::realizer( GraphCopy& G, const List<node>& L, node a, node b, node c, EdgeArray<int>& rValues, GraphCopy& T) { int i = 0; edge e; NodeArray<int> ord(G, 0); // ordering: b,c,L,a ord[b] = i++; ord[c] = i++; for(node v : L) { ord[v] = i++; // enumerate V(G) } ord[a] = i++; // remove all edges (they will be re-added later with different orientation) while (T.numberOfEdges() > 0) { e = T.firstEdge(); T.delEdge(e); } for(node v : L) { node u = T.copy(G.original(v)); // u is copy of v in T adjEntry adj = nullptr; for(adjEntry adjRun : v->adjEdges) { if (ord[adjRun->twinNode()] > ord[v]) { adj = adjRun; break; } } adjEntry adj1 = adj; while (ord[adj1->twinNode()] > ord[v]) { adj1 = adj1->cyclicSucc(); } e = T.newEdge(T.copy(G.original(adj1->twinNode())), u); rValues[e] = 2; adjEntry adj2 = adj; while (ord[adj2->twinNode()] > ord[v]) { adj2 = adj2->cyclicPred(); } e = T.newEdge(T.copy(G.original(adj2->twinNode())), u); rValues[e] = 3; for (adj = adj1->cyclicSucc(); adj != adj2; adj = adj->cyclicSucc()) { e = T.newEdge(u, T.copy(G.original(adj->twinNode()))); rValues[e] = 1; } } // special treatement of a,b,c node a_in_T = T.copy(G.original(a)); node b_in_T = T.copy(G.original(b)); node c_in_T = T.copy(G.original(c)); // all edges to node a get realizer value 1 for(adjEntry adj : a->adjEdges) { e = T.newEdge(a_in_T, T.copy(G.original(adj->twinNode()))); rValues[e] = 1; } // rest of outer triangle (reciprocal linked, realizer values 2 and 3) e = T.newEdge(b_in_T, a_in_T); rValues[e] = 2; e = T.newEdge(b_in_T, c_in_T); rValues[e] = 2; e = T.newEdge(c_in_T, a_in_T); rValues[e] = 3; e = T.newEdge(c_in_T, b_in_T); rValues[e] = 3; }