#include // #include "hsuPC/include/PCTree.h" // #include "hsuPC/include/PCNode.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ogdf; using std::chrono::time_point; using std::chrono::high_resolution_clock; using std::chrono::duration_cast; using std::chrono::nanoseconds; void planarizePQ(const Graph &G, NodeArray &numbering, List &delEdges) { using PlanarLeafKey = booth_lueker::PlanarLeafKey; NodeArray> inLeaves(G); NodeArray> outLeaves(G); Array table(G.numberOfNodes()+1); for(node v : G.nodes) { for(adjEntry adj : v->adjEntries) { edge e = adj->theEdge(); if (numbering[e->opposite(v)] > numbering[v]) { // sideeffect: ignores selfloops PlanarLeafKey* L = new PlanarLeafKey(e); inLeaves[v].pushFront(L); } } table[numbering[v]] = v; } for(node v : G.nodes) { for (PlanarLeafKey *L : inLeaves[v]) { outLeaves[L->userStructKey()->opposite(v)].pushFront(L); } } SList*> totalEliminatedKeys; PlanarSubgraphPQTree T; T.Initialize(inLeaves[table[1]]); for (int i = 2; i < G.numberOfNodes(); i++) { SList*> eliminatedKeys; // handle key elimination T.Reduction(outLeaves[table[i]], eliminatedKeys); // handle key elimination totalEliminatedKeys.conc(eliminatedKeys); // handle key elimination T.ReplaceRoot(inLeaves[table[i]]); T.emptyAllPertinentNodes(); } // append eliminated edges to delEdges for (PQLeafKey *key : totalEliminatedKeys) { edge e = key->userStructKey(); delEdges.pushBack(e); } //cleanup for(node v : G.nodes) { while (!inLeaves[v].empty()) { PlanarLeafKey *L = inLeaves[v].popFrontRet(); delete L; } } T.Cleanup(); // Explicit call for destructor necessary. This allows to call virtual // function CleanNode for freeing node information class. } template void planarizePC(const Graph &G, const NodeArray &numbering, List &delEdges) { // initialize PCTree instance PCT T; // vector to store nodes of graph in order specified in numbering std::vector order(G.numberOfNodes(), nullptr); for (node n : G.nodes) { order.at(numbering[n] - 1) = n; } // store leaf representations of edges in PCTree std::vector leafRepresentation(G.maxEdgeIndex() + 1, nullptr); // vectors declared for later use std::vector outEdges; std::vector consecutiveLeaves; // iterates over nodes in the 'order' vector for (node n : order) { // quit condition: if current node is last node if (n == order[G.numberOfNodes() - 1]) { break; } // clear both vectors in for each node in iteration consecutiveLeaves.clear(); outEdges.clear(); // leafToEdge // create a map of PCN to edge std::map leafToEdge; // iterate over adjacent entries of current node for (adjEntry adj : n->adjEntries) { // check if opposite node has higher numbering (belong to later node) // add to outEdges if (numbering[adj->theEdge()->opposite(n)] > numbering[n]) { outEdges.push_back(adj->theEdge()); // add to consecutiveLeaves otherwise (declared earlier) // leafRepresentation will be filled later on } else { consecutiveLeaves.push_back(leafRepresentation[adj->theEdge()->index()]); // use leafToEdge to map leafRep object to edge object // then store the edge in a collection // <- insert code here -> leafToEdge[leafRepresentation[adj->theEdge()->index()]] = adj->theEdge(); } } PCN *mergedLeaf; // If first node, new P-node is created if (n == order[0]) { mergedLeaf = T.newNode(PCNT::PNode); // consecutive leaves are merged } else { // T.makeConsecutive // the function returns a boolean for success // I think it checks if its possible to make consecutive // IMPORTANT HERE // here we can identify edges that result in non-planarity if (!T.makeConsecutive(consecutiveLeaves)){ // keep trying different combinations until is passes std::vector goodLeaves; for (PCN* leaf: consecutiveLeaves) { goodLeaves.push_back(leaf); if (T.makeConsecutive(goodLeaves)) { continue; } else { goodLeaves.pop_back(); delEdges.pushBack(leafToEdge[leaf]); } } consecutiveLeaves.clear(); consecutiveLeaves.insert(consecutiveLeaves.end(), goodLeaves.begin(), goodLeaves.end()); // for rejected leaves, // return false; } // remove all consecutive leaves except the first // returns a single leaf // second argument is "assumeConsecutive", which makeConsecutive checks mergedLeaf = T.mergeLeaves(consecutiveLeaves, true); } OGDF_ASSERT(!outEdges.empty()); // if there is more than 1 outEdge if (outEdges.size() > 1) { // clear and re-use consecutiveLeaves variable consecutiveLeaves.clear(); // make a reference variabled std::vector &addedLeaves = consecutiveLeaves; // if mergedLeaf if a P-node // PCTree_construction::insertLeaves if (mergedLeaf->getNodeType() == PCNT::PNode) { T.insertLeaves(outEdges.size(), mergedLeaf, &addedLeaves); // otherwise mergedLeaf is a Leaf node // PCTree_construction::replaceLeaf } else { OGDF_ASSERT(mergedLeaf->getNodeType() == PCNT::Leaf); T.replaceLeaf(outEdges.size(), mergedLeaf, &addedLeaves); } // leaf representations are updated accordingly for (int i = 0; i < outEdges.size(); i++) { leafRepresentation[outEdges[i]->index()] = addedLeaves[i]; } // if there is only 1 edge // first outEdge is updated to mergedLeaf node } else { leafRepresentation[outEdges.front()->index()] = mergedLeaf; } } } int main(int argc, char* argv[]) { string inputFile = argv[1]; string selection = argv[2]; string planarity = argv[3]; Graph G; if (!GraphIO::read(G, inputFile, GraphIO::readGML)) { std::cerr << "Could not read input.gml" << std::endl; return 1; } int b; std::istringstream(planarity) >> b; if (b) { // create map from integer to node // find edge and change its attribute // implicit assumption that nodes retain order as given by input std::unordered_map nodeMap; // Add nodes to the graph and map them to integers int index = 0; for (ogdf::node v : G.nodes) { nodeMap[index] = v; ++index; } // manually add our own random edges int numEdgesToAdd = b; // Number of edges to add int count = 0; std::srand(150); // Seed the random number generator int numNodes = G.numberOfNodes(); while (count < numEdgesToAdd) { int sourceIndex = std::rand() % numNodes; // Random source node index int targetIndex = std::rand() % numNodes; // Random target node index if (sourceIndex == targetIndex) continue; ogdf::edge targetEdge = G.searchEdge(nodeMap[sourceIndex], nodeMap[targetIndex], false); if (targetEdge == nullptr) { G.newEdge(nodeMap[sourceIndex], nodeMap[targetIndex]); std::cout << sourceIndex << ", " << targetIndex << std::endl; ++count; } } } NodeArray numbering(G); // int num = computeSTNumbering(G, numbering, 0); int num = computeSTNumbering(G, numbering, nullptr, nullptr, true); OGDF_ASSERT(num == G.numberOfNodes()); // print after input // graphPrinter(G); std::cout << "G Planarity: " << ogdf::isPlanar(G) << std::endl; std::cout << "Original number of nodes: " << G.numberOfNodes() << std::endl; std::cout << "Original number of edges: " << G.numberOfEdges() << std::endl; // separator for planarization // <--------------> // PQ implementation to make planar subgraph std::cout << "start planarization" << std::endl; List *delEdges = new List; // empty list // changed to PC if (selection == "pc") { planarizePC(G, numbering, *delEdges); } else if (selection == "pq") { planarizePQ(G, numbering, *delEdges); // } else if (selection == "bm") { // SubgraphPlanarizer *crossMin = new SubgraphPlanarizer; // crossMin->call(G) } else if (selection == "fast") { // PlanarSubgraphModule *ps = new PlanarSubgraphFast; // ogdf::MaximalPlanarSubgraphSimple mps(*(new PlanarSubgraphBoyerMyrvold)); ogdf::MaximalPlanarSubgraphSimple mps(*(new PlanarSubgraphFast)); mps.call(G, *delEdges); } else { std::cout << "running maximum" << std::endl; ogdf::MaximumPlanarSubgraph mps; mps.call(G, *delEdges); } std::cout << "Edges removed:" << delEdges->size() << std::endl; // delete removed edges for (edge e: *delEdges) { // print removed edges // std::cout << e->adjSource() << std::endl; G.delEdge(e); } GraphIO::write(G, "output.gml", GraphIO::writeGML); // edgeListPrinter(*delEdges); // std::cout << std::endl; // std::cout << "subG planarity: " << ogdf::isPlanar(subgraph) << std::endl; std::cout << "G planarity: " << ogdf::isPlanar(G) << std::endl; std::cout << "Original number of nodes: " << G.numberOfNodes() << std::endl; std::cout << "Subgraph number of edges: " << G.numberOfEdges() << std::endl; // graphPrinter(G); // std::cout << isPlanarPC(G, numbering) << std::endl; // bool result = isPlanarPC(subG, numbering); // std::cout << result << std::endl; return 0; }