benchmark_mps/make_planar/make_planar.cpp

331 lines
11 KiB
C++

#include <PCTree/PCTree.h>
// #include "hsuPC/include/PCTree.h"
// #include "hsuPC/include/PCNode.h"
#include <ogdf/basic/STNumbering.h>
#include <ogdf/basic/graph_generators.h>
#include <ogdf/basic/GraphCopy.h>
#include <ogdf/fileformats/GraphIO.h>
#include <ogdf/planarity/BoothLueker.h>
#include <ogdf/planarity/BoyerMyrvold.h>
#include <ogdf/basic/extended_graph_alg.h>
#include <ogdf/planarity/booth_lueker/IndInfo.h>
#include <ogdf/planarity/booth_lueker/PlanarPQTree.h>
#include <ogdf/planarity/planar_subgraph_fast/PlanarSubgraphPQTree.h>
#include <ogdf/planarity/PlanarSubgraphFast.h>
#include <ogdf/planarity/PlanarSubgraphBoyerMyrvold.h>
#include <ogdf/planarity/PlanarSubgraphPC.h>
#include <ogdf/planarity/MaximumPlanarSubgraph.h>
#include <ogdf/planarity/MaximalPlanarSubgraphSimple.h>
#include <iostream>
#include <map>
#include <chrono>
#include <getopt.h>
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<int> &numbering, List<edge> &delEdges) {
using PlanarLeafKey = booth_lueker::PlanarLeafKey<whaInfo*>;
NodeArray<SListPure<PlanarLeafKey*>> inLeaves(G);
NodeArray<SListPure<PlanarLeafKey*>> outLeaves(G);
Array<node> 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<PQLeafKey<edge,whaInfo*,bool>*> totalEliminatedKeys;
PlanarSubgraphPQTree T;
T.Initialize(inLeaves[table[1]]);
for (int i = 2; i < G.numberOfNodes(); i++) {
SList<PQLeafKey<edge,whaInfo*,bool>*> 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<edge, whaInfo*, bool> *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<typename PCT, typename PCN, typename PCNT>
void planarizePC(const Graph &G, const NodeArray<int> &numbering, List<edge> &delEdges) {
// initialize PCTree instance
PCT T;
// vector to store nodes of graph in order specified in numbering
std::vector<node> order(G.numberOfNodes(), nullptr);
for (node n : G.nodes) {
order.at(numbering[n] - 1) = n;
}
// store leaf representations of edges in PCTree
std::vector<PCN *> leafRepresentation(G.maxEdgeIndex() + 1, nullptr);
// vectors declared for later use
std::vector<edge> outEdges;
std::vector<PCN *> 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<PCN *, edge> 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<PCN *> 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<PCN *> &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<int, ogdf::node> 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<int> 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<edge> *delEdges = new List<edge>; // empty list
// changed to PC
if (selection == "pc") {
planarizePC<pc_tree::PCTree, pc_tree::PCNode, pc_tree::PCNodeType>(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<int> *ps = new PlanarSubgraphFast<int>;
// ogdf::MaximalPlanarSubgraphSimple<int> mps(*(new PlanarSubgraphBoyerMyrvold));
ogdf::MaximalPlanarSubgraphSimple<int> mps(*(new PlanarSubgraphFast<int>));
mps.call(G, *delEdges);
} else {
std::cout << "running maximum" << std::endl;
ogdf::MaximumPlanarSubgraph<int> 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<pc_tree::hsu::PCTree, pc_tree::hsu::PCNode, pc_tree::hsu::PCTree::PCNodeType>(G, numbering) << std::endl;
// bool result = isPlanarPC<pc_tree::PCTree, pc_tree::PCNode, pc_tree::PCNodeType>(subG, numbering);
// std::cout << result << std::endl;
return 0;
}