diff --git a/deferred_planarity_test/include/mps.h b/deferred_planarity_test/include/mps.h index 4a99594..ce2ebb7 100644 --- a/deferred_planarity_test/include/mps.h +++ b/deferred_planarity_test/include/mps.h @@ -10,9 +10,12 @@ #include #include #include +#include #include #include +#include #include +#include using namespace std; @@ -57,16 +60,19 @@ public: void set_adj_list(vector vec); void DFS_visit(vector &dfsList, int &index); void guided_DFS_visit(vector &dfsList, - vector &node_list, + const vector &node_list, int &return_index, - vector rev_post_order, - int prev_node); - void mutated_DFS_visit(vector &dfsList, - vector &node_list, - int &index, - int &traversal_index, - vector rev_post_order, - int mutate_point); + const unordered_map &node_id_to_pos); + void mutated_DFS_visit(vector &dfsList, + const vector &node_list, + int &index, + int &traversal_index, + const unordered_map &node_id_to_pos, + int mutate_point, + mt19937 rng); + + // custom comparator function to sort nodes according to order in given vector + bool sortByOrder(const unordered_map& node_id_to_pos, node* a, node* b); //PARENT-CHILDREN void set_parent(node* n) ; @@ -155,18 +161,26 @@ class maximal_planar_subgraph_finder public: maximal_planar_subgraph_finder(); ~maximal_planar_subgraph_finder(); - int find_mps(string input_file); - int compute_removed_edge_size(string input_file, vector post_order); - vector generate_post_order(string input_file); - vector generate_mutated_post_order(string input_file, vector post_order, int mutate_point); - vector generate_guided_post_order(string input_file, vector post_order); + + // functions that prepare state + void init_from_graph(const ogdf::Graph &G); + vector generate_post_order(const ogdf::Graph &G); + vector generate_mutated_post_order(const ogdf::Graph &G, const vector &post_order, int mutate_point); + vector generate_guided_post_order(const ogdf::Graph &G, const vector &post_order); + void postOrderTraversal(); + void guidedPostOrderTraversal(const vector &post_order); + void mutatedPostOrderTraversal(const vector &post_order, int mutate_point); + + // compute_mps combines functionality to reduce repeating object initialization + // the results are returned by modifying mutable reference + void compute_mps(const ogdf::Graph &G, int mutate_point, vector &post_order, int &return_edge_size); + + int find_mps(const ogdf::Graph &G); + int compute_removed_edge_size(const ogdf::Graph &G, vector post_order); node* get_new_node(node_type t); - void read_from_gml(string input_file); + void reset_state(); int output_removed_edge_size(); vector return_post_order(); - void postOrderTraversal(); - void guidedPostOrderTraversal(vector post_order); - void mutatedPostOrderTraversal(vector post_order, int mutate_point); // void set_post_order(vector post_order); void print_post_order(); void sort_adj_list(); @@ -198,4 +212,4 @@ private: vector _new_node_list; //Newly added nodes. }; -#endif +#endif // for MPS_H diff --git a/deferred_planarity_test/makefile b/deferred_planarity_test/makefile index 8a8fac8..934e95b 100644 --- a/deferred_planarity_test/makefile +++ b/deferred_planarity_test/makefile @@ -10,7 +10,7 @@ DEPS := $(OBJS:.o=.d) # compiler and flags CXX := g++ CPPFLAGS := -Iinclude -MMD -MP -CXXFLAGS := -std=c++14 -Wall +CXXFLAGS := -std=c++14 -Wall LDFLAGS := -lOGDF build: $(TARGET) @@ -31,4 +31,4 @@ $(BIN_DIR) $(OBJ_DIR): .PHONY: clean clean: - rm -r $(BIN_DIR) $(OBJ_DIR) + rm -r $(OBJ_DIR) diff --git a/deferred_planarity_test/src/main.cpp b/deferred_planarity_test/src/main.cpp index acb33a7..f28306a 100644 --- a/deferred_planarity_test/src/main.cpp +++ b/deferred_planarity_test/src/main.cpp @@ -14,68 +14,73 @@ #include #define START_TEMP 100 +// #define TIME using namespace std; -int compute_removed_edge_size(string input_file, vector post_order); +int compute_removed_edge_size(const ogdf::Graph &G, vector post_order); // these functions are defined in mps_test.cpp // but their signatures are not in mps.h, hence they are declared here -vector generate_post_order(string input_file); -vector generate_mutated_post_order(string input_file, vector post_order, int mutate_point); -vector generate_guided_post_order(string input_file, vector post_order); +ogdf::Graph read_from_gml(string input_file); +vector generate_post_order(const ogdf::Graph &G); +vector generate_mutated_post_order(const ogdf::Graph &G, vector post_order, int mutate_point); +vector generate_guided_post_order(const ogdf::Graph &G, vector post_order); +void compute_mps(const ogdf::Graph &G, int mutate_point, vector &post_order, int &return_edge_size); -void vector_printer(vector state) { - for (int i = 0; i < state.size(); ++i) { +void vector_printer(const vector& state) { + for (size_t i = 0; i < state.size(); ++i) { std::cout << state[i] << ","; } std::cout << std::endl; } -vector repeated_mutation(string input_file, int k_max, int mutate_point) { +vector repeated_mutation(const ogdf::Graph &G, int k_max) { // generate first post order - std::cout << "generate first post order" << std::endl; - vector state_old = generate_post_order(input_file); - vector state_new; + // std::cout << "generate first post order" << std::endl; + vector old_order = generate_post_order(G); + vector_printer(old_order); + vector temp_order = old_order; + int new_removed_size; + int old_removed_size = INT_MAX; + + // prepare random selection + std::random_device rd; + std::mt19937 gen{rd()}; // seed the generator + int first_value = 0; + // we want the index of the third last value + // at a given traversal index, only the next iteration has the mutated value + int last_value = (old_order.size() - 1) - 2; + std::uniform_int_distribution<> dist{first_value, last_value}; // set min and max for (int k = 0; k < k_max; ++k) { - std::cout << "cycle:" << k << std::endl; + // function compute new post_order and new_removed_size + // temp_order and new_removed_size will be updated with new values - vector_printer(state_old); - - - // mutation produces rotated view - state_new = generate_mutated_post_order(input_file, state_old, mutate_point); - vector_printer(state_new); + #ifdef TIME + auto start = std::chrono::high_resolution_clock::now(); + #endif + compute_mps(G, dist(gen), temp_order, new_removed_size); + #ifdef TIME + auto end = std::chrono::high_resolution_clock::now(); + std::cout << "compute_mps: " << std::chrono::duration_cast(end - start).count() << std::endl; + #endif - // another round of guided post order gives canonical representation - state_new = generate_guided_post_order(input_file, state_new); - vector_printer(state_new); - - - std::cout << std::endl; + // if there is an improvement + // 1. update the removed size to use the new smaller size + // 2. update the old_order to be the new_order + if (new_removed_size < old_removed_size) { + old_removed_size = new_removed_size; + old_order = temp_order; + // if there is no improvement, we revert the temp_order to the old_order + } else { + temp_order = old_order; + } } - return state_new; + return old_order; } -void test_correctness(string input_file) { - vector state_old = generate_post_order(input_file); - int num_removed_edges; - num_removed_edges = compute_removed_edge_size(input_file, state_old); -} - - -int get_graph_size(string input_file) { - ogdf::Graph G; - - // utilize OGDF readGML - if (!ogdf::GraphIO::read(G, input_file, ogdf::GraphIO::readGML)) { - std::cerr << "Could not read " << input_file << ".gml" << std::endl; - } - - return G.numberOfNodes(); -} //----------------------------------------------------------------------------------- // Main function. @@ -85,18 +90,22 @@ int get_graph_size(string input_file) { int main(int argc, char* argv[]) { string input_file = argv[1]; int k_max = std::stoi(argv[2]); - int mutate_point = std::stoi(argv[3]); + + const ogdf::Graph G = read_from_gml(input_file); // generate order here - vector post_order = repeated_mutation(input_file, k_max, mutate_point); - // test_correctness(input_file); + vector post_order = repeated_mutation(G, k_max); + + // test timing of function + // test_correctness(G); // // print final order and number of edges - // // print post_order - // std::copy(post_order.begin(), post_order.end(), std::ostream_iterator(std::cout, ",")); - // std::cout << std::endl; - // int removed_edges = compute_removed_edge_size(input_file, post_order); - // std::cout << "Number of removed edges: " << removed_edges << std::endl; + std::cout << "---" << std::endl; + std::cout << "final report" << std::endl; + std::copy(post_order.begin(), post_order.end(), std::ostream_iterator(std::cout, ",")); + std::cout << std::endl; + int removed_edges = compute_removed_edge_size(G, post_order); + std::cout << "Number of removed edges: " << removed_edges << std::endl; return 0; } diff --git a/deferred_planarity_test/src/mps.cpp b/deferred_planarity_test/src/mps.cpp index 0c07fbd..8c27ff9 100644 --- a/deferred_planarity_test/src/mps.cpp +++ b/deferred_planarity_test/src/mps.cpp @@ -3,7 +3,6 @@ //----------------------------------------------------------------------------------- #include "mps.h" -#include // #define DEBUG @@ -12,8 +11,8 @@ maximal_planar_subgraph_finder::maximal_planar_subgraph_finder() {} //Destructor maximal_planar_subgraph_finder::~maximal_planar_subgraph_finder() { - for (int i = 0; i < _node_list.size(); ++i) delete _node_list[i]; - for (int i = 0; i < _new_node_list.size(); ++i) delete _new_node_list[i]; + for (size_t i = 0; i < _node_list.size(); ++i) delete _node_list[i]; + for (size_t i = 0; i < _new_node_list.size(); ++i) delete _new_node_list[i]; } node* @@ -25,7 +24,9 @@ maximal_planar_subgraph_finder::get_new_node(node_type t) { vector maximal_planar_subgraph_finder::return_post_order() { vector post_order; - for (int i = 0; i < _post_order_list.size(); ++i) { + // we have arg number of elements + post_order.reserve(_post_order_list.size()); // reserve for decreased reallocation + for (size_t i = 0; i < _post_order_list.size(); ++i) { post_order.push_back(_post_order_list[i]->node_id()); } return post_order; @@ -37,7 +38,7 @@ maximal_planar_subgraph_finder::postOrderTraversal() { node::init_mark(); // always start with node 0 int postOrderID = 0; - for (int i = 0; i < _node_list.size(); ++i) { + for (size_t i = 0; i < _node_list.size(); ++i) { if (!_node_list[i]->is_marked()) { _node_list[i]->DFS_visit(_post_order_list, postOrderID); } @@ -49,33 +50,49 @@ maximal_planar_subgraph_finder::postOrderTraversal() { // take in a post-order argument then traces the graph in the same order // return is by reference via _post_order_list void -maximal_planar_subgraph_finder::guidedPostOrderTraversal(vector post_order) { +maximal_planar_subgraph_finder::guidedPostOrderTraversal(const vector &post_order) { node::init_mark(); - vector rev_post_order; - for (int i = post_order.size() - 1; i >= 0; --i) { - rev_post_order.push_back(post_order[i]); - } - int postOrderID = 0; + // // implementation 1: pass reversed vector + // vector rev_post_order; + // for (int i = post_order.size() - 1; i >= 0; --i) { + // rev_post_order.push_back(post_order[i]); + // } + // int start = rev_post_order[0]; + + // implementation 2: use unordered_map to map node_id to position in reversed post_order + unordered_map node_id_to_pos; + node_id_to_pos.reserve(post_order.size()); + int j = 0; + // we flip the post_order vector around + for (size_t i = post_order.size() - 1; i != std::numeric_limits::max(); --i) { + node_id_to_pos[post_order[i]] = j++; + } + + int postOrderID = 0; int end_condition = _node_list.size(); - int start = rev_post_order[0]; + // we start from the end of the post_order, which is the root node + int start = post_order[post_order.size() - 1]; int i = start; - - int prev_node = INT_MAX; + + // reserve for _post_order_list to decrease reallocation + _post_order_list.reserve(_node_list.size()); + + while (true) { if (((start > 0) && (i == (start - 1))) || ((start == 0 ) && (i == end_condition - 1))) { if (!_node_list[i]->is_marked()) { - _node_list[i]->guided_DFS_visit(_post_order_list, _node_list, postOrderID, rev_post_order, prev_node); + _node_list[i]->guided_DFS_visit(_post_order_list, _node_list, postOrderID, node_id_to_pos); } break; } if (!_node_list[i]->is_marked()) { - _node_list[i]->guided_DFS_visit(_post_order_list, _node_list, postOrderID, rev_post_order, prev_node); + _node_list[i]->guided_DFS_visit(_post_order_list, _node_list, postOrderID, node_id_to_pos); } i = (i + 1) % end_condition; } @@ -85,23 +102,50 @@ maximal_planar_subgraph_finder::guidedPostOrderTraversal(vector post_order) // take in a post-order argument then traces the graph in the same order // return is by reference via _post_order_list void -maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector post_order, int mutate_point) { +maximal_planar_subgraph_finder::mutatedPostOrderTraversal(const vector &post_order, int mutate_point) { node::init_mark(); - vector rev_post_order; - for (int i = post_order.size() - 1; i >= 0; --i) { - rev_post_order.push_back(post_order[i]); + // // implementation 1: use vector + // vector rev_post_order; + // for (size_t i = post_order.size() - 1; i != std::numeric_limits::max(); --i) { + // rev_post_order.push_back(post_order[i]); + // } + + // implementation 2: use unordered_map to map node_id to position in reversed post_order + unordered_map node_id_to_pos; + node_id_to_pos.reserve(post_order.size()); + int j = 0; + // we flip the post_order vector around + for (size_t i = post_order.size() - 1; i != std::numeric_limits::max(); --i) { + node_id_to_pos[post_order[i]] = j++; } + int postOrderID = 0; int traversal_index = 0; - // Define the range [0, n] - int n = _node_list.size() - 1; // Change 'n' to your desired upper bound + // setup random rng function + std::random_device rd; + std::mt19937 rng{rd()}; + + + int start = 0; + // if we mutate first node, we will select a random starting node + if (mutate_point == 0) { + int first_value = 0; + int last_value = post_order.size() - 1; + std::uniform_int_distribution<> dist{first_value, last_value}; + start = post_order[dist(rng)]; + // if we don't mutate first, we just use the root node of the post_order + } else { + start = post_order[post_order.size() - 1]; + } // set loop variables - int start = rev_post_order[0]; int i = start; + // reserve for _post_order_list to decrease reallocation + _post_order_list.reserve(_node_list.size()); + int end_condition = _node_list.size(); // this loop assumes start is not from 0 @@ -112,13 +156,13 @@ maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector post_order { if (!_node_list[i]->is_marked()) { - _node_list[i]->mutated_DFS_visit(_post_order_list, _node_list, postOrderID, traversal_index, rev_post_order, mutate_point); + _node_list[i]->mutated_DFS_visit(_post_order_list, _node_list, postOrderID, traversal_index, node_id_to_pos, mutate_point, rng); } break; } if (!_node_list[i]->is_marked()) { - _node_list[i]->mutated_DFS_visit(_post_order_list, _node_list, postOrderID, traversal_index, rev_post_order, mutate_point); + _node_list[i]->mutated_DFS_visit(_post_order_list, _node_list, postOrderID, traversal_index, node_id_to_pos, mutate_point, rng); } i = (i + 1) % end_condition; } @@ -127,7 +171,7 @@ maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector post_order void maximal_planar_subgraph_finder::print_post_order() { int current_index; - for (int i = 0; i < _post_order_list.size(); ++i) { + for (size_t i = 0; i < _post_order_list.size(); ++i) { current_index = _post_order_list[i]->node_id(); std::cout << current_index << ","; } @@ -149,12 +193,12 @@ void maximal_planar_subgraph_finder::sort_adj_list() { vector > vecList; vecList.resize(_post_order_list.size()); - for (int i = 0; i < _post_order_list.size(); ++i) { + for (size_t i = 0; i < _post_order_list.size(); ++i) { for (int j = 0; j < _post_order_list[i]->degree(); ++j) { vecList[_post_order_list[i]->adj(j)->post_order_index()].push_back(_post_order_list[i]); } } - for (int i = 0; i < _post_order_list.size(); ++i) { + for (size_t i = 0; i < _post_order_list.size(); ++i) { _post_order_list[i]->set_adj_list(vecList[i]); } } @@ -163,20 +207,20 @@ maximal_planar_subgraph_finder::sort_adj_list() { //Order the edges properly. void maximal_planar_subgraph_finder::determine_edges() { - for (int i = 0; i < _post_order_list.size(); ++i) { + for (size_t i = 0; i < _post_order_list.size(); ++i) { if (_post_order_list[i]->parent() == 0) continue; _post_order_list[i]->set_1st_label(_post_order_list[i]->parent()->post_order_index()); _edge_list.push_back(pair (_post_order_list[i]->parent(), _post_order_list[i])); } - for (int i = 0; i < _post_order_list.size(); ++i) { + for (size_t i = 0; i < _post_order_list.size(); ++i) { for (int j = 0; j < _post_order_list[i]->degree(); ++j) { - if (_post_order_list[i]->adj(j)->post_order_index() > i) break; - if (_post_order_list[i]->adj(j)->get_1st_label() == i) continue; + if (_post_order_list[i]->adj(j)->post_order_index() > static_cast(i)) break; + if (_post_order_list[i]->adj(j)->get_1st_label() == static_cast(i)) continue; _back_edge_list.push_back(pair (_post_order_list[i], _post_order_list[i]->adj(j))); _is_back_edge_eliminate.push_back(false); } } - for (int i = 0; i < _post_order_list.size(); ++i) { + for (size_t i = 0; i < _post_order_list.size(); ++i) { _post_order_list[i]->set_1st_label(INT_MAX); } } @@ -186,7 +230,7 @@ void maximal_planar_subgraph_finder::back_edge_traversal() { node* i_node = 0; node* current_node = 0; - for (int i = 0; i < _back_edge_list.size(); ++i) { + for (size_t i = 0; i < _back_edge_list.size(); ++i) { current_node = _back_edge_list[i].second; i_node = _back_edge_list[i].first; if (!back_edge_traversal(current_node, i_node->post_order_index())) _is_back_edge_eliminate[i] = true; @@ -463,7 +507,7 @@ maximal_planar_subgraph_finder::trim(node* u) { new_AE_root = get_new_node(AE_VIRTUAL_ROOT); new_AE_root->init_AE(node_list[0]); //Eliminate the children other than the path. - for (int i = 1; i < node_list.size(); ++i) { + for (size_t i = 1; i < node_list.size(); ++i) { for (int j = 0; j < node_list[i]->child_num(); ++j) { if (node_list[i]->child(j) != node_list[i-1]) eliminate(node_list[i]->child(j)); } @@ -473,7 +517,7 @@ maximal_planar_subgraph_finder::trim(node* u) { else { node_list[0]->set_to_boundary_path(down, node_list[1]); node_list[node_list.size()-1]->set_to_boundary_path(up, node_list[node_list.size()-2]); - for (int i = 1; i < node_list.size()-1; ++i) { + for (size_t i = 1; i < node_list.size()-1; ++i) { node_list[i]->set_to_boundary_path(node_list[i-1], node_list[i+1]); } } @@ -481,7 +525,7 @@ maximal_planar_subgraph_finder::trim(node* u) { up_next = up->get_next(node_list[node_list.size()-1]); down_next = down->get_next(node_list[0]); //Unfold the c-nodes in the node_list. - for (int i = 0; i < node_list.size(); ++i) { + for (size_t i = 0; i < node_list.size(); ++i) { if (node_list[i]->type() == C_NODE) c_node_extension(node_list[i]); } //Return the new boundary. @@ -655,7 +699,7 @@ maximal_planar_subgraph_finder::parallel_search_sentinel(node* n0, node* n0_prev } //If the c-node found is top-tier, then assign all the traversed node a pointer to c-node. - for (int i = 0; i < traversed.size(); ++i) traversed[i]->set_c_node(c); + for (size_t i = 0; i < traversed.size(); ++i) traversed[i]->set_c_node(c); return pair((node*)0, (node*)0); } @@ -703,7 +747,7 @@ pair maximal_planar_subgraph_finder::count_sentinel_elimination(pa node* maximal_planar_subgraph_finder::construct(node* u) { //Basic works. - int i_label = u->get_1st_label(); + // int i_label = u->get_1st_label(); // unused node* node_i = _post_order_list[u->get_1st_label()]; parenting_labeling_shaving(u, node_i); @@ -751,7 +795,7 @@ maximal_planar_subgraph_finder::construct(node* u) { node* maximal_planar_subgraph_finder::construct(node* c, node* p) { //Basic works. - int i_label = c->get_1st_label(); + // int i_label = c->get_1st_label(); // unused var node* node_i = _post_order_list[c->get_1st_label()]; parenting_labeling_shaving(p, node_i); //note: Now, c must have exactly two children left, and c has a parent-link to p, p has achild link to c, too. @@ -822,11 +866,11 @@ maximal_planar_subgraph_finder::parenting_labeling_shaving(node* u, node* node_i u_i_path.push_back(u_i_path[u_i_path.size()-1]->parent()); if (u_i_path[u_i_path.size()-1] == node_i) break; } - for (int i = 0; i < u_i_path.size()-2; ++i) { + for (size_t i = 0; i < u_i_path.size()-2; ++i) { u_i_path[i]->add_child(u_i_path[i+1]); u_i_path[i+1]->set_parent(u_i_path[i]); } - for (int i = 0; i < u_i_path.size()-2; ++i) { + for (size_t i = 0; i < u_i_path.size()-2; ++i) { for (int j = 0; j < u_i_path[i+1]->child_num(); ++j) { if (u_i_path[i+1]->child(j) == u_i_path[i]) { u_i_path[i+1]->remove_child(j); diff --git a/deferred_planarity_test/src/mps_test.cpp b/deferred_planarity_test/src/mps_test.cpp index 47b4259..a514816 100644 --- a/deferred_planarity_test/src/mps_test.cpp +++ b/deferred_planarity_test/src/mps_test.cpp @@ -2,10 +2,14 @@ // Implementation of a MPS algorithm via PC-tree. //----------------------------------------------------------------------------------- +#include #include "mps.h" + #include // #define DEBUG +// #define DEBUG_2 +// #define TIME //----------------------------------------------------------------------------------- // Finding MPS @@ -13,36 +17,54 @@ // programs to call from main: -int find_mps(string input_file) { +// read input file of gml format +ogdf::Graph read_from_gml(string input_file) { + ogdf::Graph G; + + // utilize OGDF readGML + if (!ogdf::GraphIO::read(G, input_file, ogdf::GraphIO::readGML)) { + std::cerr << "Could not read " << input_file << ".gml" << std::endl; + } + return G; +} + + +int find_mps(const ogdf::Graph &G) { maximal_planar_subgraph_finder m; - return m.find_mps(input_file); + return m.find_mps(G); } -int compute_removed_edge_size(string input_file, vector post_order) { +int compute_removed_edge_size(const ogdf::Graph &G, vector post_order) { maximal_planar_subgraph_finder m; - return m.compute_removed_edge_size(input_file, post_order); + return m.compute_removed_edge_size(G, post_order); } -vector generate_post_order(string input_file) { +vector generate_post_order(const ogdf::Graph &G) { maximal_planar_subgraph_finder m; - return m.generate_post_order(input_file); + return m.generate_post_order(G); } -vector generate_mutated_post_order(string input_file, vector post_order, int mutate_point) { +vector generate_mutated_post_order(const ogdf::Graph &G, vector post_order, int mutate_point) { maximal_planar_subgraph_finder m; - return m.generate_mutated_post_order(input_file, post_order, mutate_point); + return m.generate_mutated_post_order(G, post_order, mutate_point); } -vector generate_guided_post_order(string input_file, vector post_order) { +vector generate_guided_post_order(const ogdf::Graph &G, vector post_order) { maximal_planar_subgraph_finder m; - return m.generate_guided_post_order(input_file, post_order); + return m.generate_guided_post_order(G, post_order); +} + + +void compute_mps(const ogdf::Graph &G, int mutate_point, vector &post_order, int &return_edge_size) { + maximal_planar_subgraph_finder m; + m.compute_mps(G, mutate_point, post_order, return_edge_size); } // --------- -int maximal_planar_subgraph_finder::find_mps(string input_file) { - read_from_gml(input_file); +int maximal_planar_subgraph_finder::find_mps(const ogdf::Graph &G) { + init_from_graph(G); postOrderTraversal(); #ifdef DEBUG @@ -55,8 +77,8 @@ int maximal_planar_subgraph_finder::find_mps(string input_file) { return output_removed_edge_size(); } -vector maximal_planar_subgraph_finder::generate_post_order(string input_file) { - read_from_gml(input_file); +vector maximal_planar_subgraph_finder::generate_post_order(const ogdf::Graph &G) { + init_from_graph(G); postOrderTraversal(); #ifdef DEBUG @@ -68,8 +90,9 @@ vector maximal_planar_subgraph_finder::generate_post_order(string input_fil } // result of this will be used as input to "compute_removed_edge_size" -vector maximal_planar_subgraph_finder::generate_mutated_post_order(string input_file, vector post_order, int mutate_point) { - read_from_gml(input_file); +vector maximal_planar_subgraph_finder::generate_mutated_post_order(const ogdf::Graph &G, const vector &post_order, int mutate_point) { + init_from_graph(G); + mutatedPostOrderTraversal(post_order, mutate_point); #ifdef DEBUG @@ -81,8 +104,8 @@ vector maximal_planar_subgraph_finder::generate_mutated_post_order(string i } // result of this will be used as input to "compute_removed_edge_size" -vector maximal_planar_subgraph_finder::generate_guided_post_order(string input_file, vector post_order) { - read_from_gml(input_file); +vector maximal_planar_subgraph_finder::generate_guided_post_order(const ogdf::Graph &G, const vector &post_order) { + init_from_graph(G); guidedPostOrderTraversal(post_order); // #ifdef DEBUG @@ -95,36 +118,48 @@ vector maximal_planar_subgraph_finder::generate_guided_post_order(string in -int maximal_planar_subgraph_finder::compute_removed_edge_size(string input_file, vector post_order) { - read_from_gml(input_file); - guidedPostOrderTraversal(post_order); - - #ifdef DEBUG - std::cout << "guided post order traversal" << std::endl; - print_post_order(); - #endif +int maximal_planar_subgraph_finder::compute_removed_edge_size(const ogdf::Graph &G, vector post_order) { + // read_from_gml + init_from_graph(G); + // guidedPostOrderTraversal + guidedPostOrderTraversal(post_order); sort_adj_list(); - determine_edges(); - back_edge_traversal(); + determine_edges(); + back_edge_traversal(); + return output_removed_edge_size(); } +void maximal_planar_subgraph_finder::reset_state() { + _post_order_list.clear(); +} + +void maximal_planar_subgraph_finder::compute_mps(const ogdf::Graph &G, int mutate_point, vector &post_order, int &return_edge_size) { + init_from_graph(G); + mutatedPostOrderTraversal(post_order, mutate_point); + sort_adj_list(); + determine_edges(); + back_edge_traversal(); + return_edge_size = output_removed_edge_size(); + + // now we get the canonical representation of the post order + vector temp_post_order = return_post_order(); + + reset_state(); // clear the _post_order_list + // perform guided Post Order Traversal to flip the tree + guidedPostOrderTraversal(temp_post_order); + + post_order = return_post_order(); +} + //----------------------------------------------------------------------------------- -// Imput, output +// Input, output //----------------------------------------------------------------------------------- - -// read input file of gml format -void maximal_planar_subgraph_finder::read_from_gml(string input_file) { - ogdf::Graph G; - - // utilize OGDF readGML - if (!ogdf::GraphIO::read(G, input_file, ogdf::GraphIO::readGML)) { - std::cerr << "Could not read " << input_file << ".gml" << std::endl; - } - +void maximal_planar_subgraph_finder::init_from_graph(const ogdf::Graph &G) { // create nodes + _node_list.reserve(G.numberOfNodes()); for (int i = 0; i < G.numberOfNodes(); ++i) { _node_list.push_back(new node(P_NODE)); _node_list[i]->set_id(i); @@ -144,7 +179,7 @@ void maximal_planar_subgraph_finder::read_from_gml(string input_file) { // count the number of removed edges int maximal_planar_subgraph_finder::output_removed_edge_size() { int sum = 0; - for (int i = 0; i < _back_edge_list.size(); ++i) { + for (size_t i = 0; i < _back_edge_list.size(); ++i) { if (_is_back_edge_eliminate[i]) ++sum; } return sum; diff --git a/deferred_planarity_test/src/node.cpp b/deferred_planarity_test/src/node.cpp index 6ce6378..0b43207 100644 --- a/deferred_planarity_test/src/node.cpp +++ b/deferred_planarity_test/src/node.cpp @@ -5,7 +5,7 @@ #include "mps.h" // #define DEBUG -#define DEBUG_MUTATION +// #define DEBUG_MUTATION //----------------------------------------------------------------------------------- // CONSTRUCTOR @@ -37,7 +37,7 @@ void node::set_post_order_index(int i) {_post_order_index = i;} //Only used when consturcting c-node //The first node calling this function would not be labeled. void node::recursively_labeling() { - for (int i = 0; i < _children.size(); ++i) { + for (size_t i = 0; i < _children.size(); ++i) { _children[i]->_label.second = ARTIFICIAL_EDGE; _children[i]->recursively_labeling(); } @@ -58,7 +58,7 @@ void node::set_adj_list(vector vec) {_adj_list = vec;} void node::DFS_visit(vector &dfsList, int &index) { mark(); - for (int i = 0; i < _adj_list.size(); ++i) { + for (size_t i = 0; i < _adj_list.size(); ++i) { if (!_adj_list[i]->is_marked()) { _adj_list[i]->_parent = this; _adj_list[i]->DFS_visit(dfsList, index); @@ -70,11 +70,19 @@ void node::DFS_visit(vector &dfsList, int &index) { } +bool node::sortByOrder(const std::unordered_map& node_id_to_pos, node* a, node* b) { + auto iter_a = node_id_to_pos.find(a->node_id()); + auto iter_b = node_id_to_pos.find(b->node_id()); + + // second yields the position + return iter_a->second < iter_b->second; +} + + void node::guided_DFS_visit(vector &dfsList, - vector &node_list, + const vector &node_list, int &return_index, - vector rev_post_order, - int prev_node) + const unordered_map &node_id_to_pos) { mark(); @@ -82,28 +90,35 @@ void node::guided_DFS_visit(vector &dfsList, // purpose of this block: create list of neighbors ordered in the order they appear in rev_post_order // we want to select neighbors that match the rev_post_order at the specific traversal_index - // create an unordered set to efficiently check for presence of an element - std::unordered_set neighbor_set; - for (int i = 0; i < _adj_list.size(); ++i) { - neighbor_set.insert(_adj_list[i]->node_id()); - } - // when an element in rev_post_order is found in neighbor_set, we add that to neighbor_list - // this produces a neighbor_list that follows the order by which they occur in the rev_post_order - // it is ok if the neighbor was already visited before, - // it would've been marked and will be subsequently ignored - vector neighbor_list; - for (int i = 0; i < rev_post_order.size(); ++i) { - if (neighbor_set.find(rev_post_order[i]) != neighbor_set.end()) { - // only add if newly encountered - if (!node_list[rev_post_order[i]]->is_marked()) { - neighbor_list.push_back(node_list[rev_post_order[i]]); - } - } - } + // implementation 1: loop through all elements + // // create an unordered set to efficiently check for presence of an element + // std::unordered_set neighbor_set; + // for (int i = 0; i < _adj_list.size(); ++i) { + // neighbor_set.insert(_adj_list[i]->node_id()); + // } + // // when an element in rev_post_order is found in neighbor_set, we add that to neighbor_list + // // this produces a neighbor_list that follows the order by which they occur in the rev_post_order + // // it is ok if the neighbor was already visited before, + // // it would've been marked and will be subsequently ignored + // vector neighbor_list; + // for (int i = 0; i < rev_post_order.size(); ++i) { + // if (neighbor_set.find(rev_post_order[i]) != neighbor_set.end()) { + // // only add if newly encountered + // if (!node_list[rev_post_order[i]]->is_marked()) { + // neighbor_list.push_back(node_list[rev_post_order[i]]); + // } + // } + // } + + // implementation 2: sort elements of _adj_list + vector neighbor_list = _adj_list; + std::sort(neighbor_list.begin(), neighbor_list.end(), [this, &node_id_to_pos](node* a, node* b) { + return sortByOrder(node_id_to_pos, a, b); + }); + #ifdef DEBUG std::cout << "current node:" << this->node_id() << std::endl; - std::cout << "prev node:" << prev_node << std::endl; for (int i = 0; i < neighbor_list.size(); ++i) { std::cout << neighbor_list[i]->node_id() << "(" << neighbor_list[i]->is_marked() << ")" << ","; } @@ -112,10 +127,10 @@ void node::guided_DFS_visit(vector &dfsList, - for (int i = 0; i < neighbor_list.size(); ++i) { + for (size_t i = 0; i < neighbor_list.size(); ++i) { if (!neighbor_list[i]->is_marked()) { neighbor_list[i]->_parent = this; - neighbor_list[i]->guided_DFS_visit(dfsList, node_list, return_index, rev_post_order, this->node_id()); + neighbor_list[i]->guided_DFS_visit(dfsList, node_list, return_index, node_id_to_pos); } } @@ -124,13 +139,13 @@ void node::guided_DFS_visit(vector &dfsList, ++return_index; } - -void node::mutated_DFS_visit(vector &dfsList, - vector &node_list, - int &return_index, - int &traversal_index, - vector rev_post_order, - int mutate_point) +void node::mutated_DFS_visit(vector &dfsList, + const vector &node_list, + int &return_index, + int &traversal_index, + const unordered_map &node_id_to_pos, + int mutate_point, + mt19937 rng) { // mark current node @@ -139,53 +154,57 @@ void node::mutated_DFS_visit(vector &dfsList, // purpose of this block: create list of neighbors ordered in the order they appear in rev_post_order // we want to select neighbors that match the rev_post_order at the specific traversal_index - // create an unordered set to efficiently check for presence of an element - std::unordered_set neighbor_set; - for (int i = 0; i < _adj_list.size(); ++i) { - neighbor_set.insert(_adj_list[i]->node_id()); - } - // when an element in rev_post_order is found in neighbor_set, we add that to neighbor_list - // this produces a neighbor_list that follows the order by which they occur in the rev_post_order - // it is ok if the neighbor was already visited before, - // it would've been marked and will be subsequently ignored - vector neighbor_list; - for (int i = 0; i < rev_post_order.size(); ++i) { - if (neighbor_set.find(rev_post_order[i]) != neighbor_set.end()) { - neighbor_list.push_back(node_list[rev_post_order[i]]); - } - } + // // implementation 1: naively check by running through all elements of rev_post_order + // // create an unordered set to efficiently check for presence of an element + // std::unordered_set neighbor_set; + // for (size_t i = 0; i < _adj_list.size(); ++i) { + // neighbor_set.insert(_adj_list[i]->node_id()); + // } + // // when an element in rev_post_order is found in neighbor_set, we add that to neighbor_list + // // this produces a neighbor_list that follows the order by which they occur in the rev_post_order + // // it is ok if the neighbor was already visited before, + // // it would've been marked and will be subsequently ignored + // vector neighbor_list; + // for (size_t i = 0; i < rev_post_order.size(); ++i) { + // if (neighbor_set.find(rev_post_order[i]) != neighbor_set.end()) { + // neighbor_list.push_back(node_list[rev_post_order[i]]); + // } + // } - - - // since we increment the index before this line, the current index is "index - 1" + vector neighbor_list = _adj_list; // if the current index matches the mutate_point, then we know this is the cycle to mutate if (traversal_index == mutate_point) { - // Create a random number generator and seed it - // std::cout << "mutated at index: " << index - 1<< "and at mutate point: " << mutate_point << std::endl; - std::random_device rd; - std::mt19937 rng(rd()); - // Use std::shuffle to shuffle the elements in the vector + // we shuffle the neighbor list std::shuffle(neighbor_list.begin(), neighbor_list.end(), rng); + // otherwise just sort based on the order set by node_id_to_pos, which is + // set by the reversed post_order + } else { + std::sort(neighbor_list.begin(), neighbor_list.end(), [this, &node_id_to_pos](node *a, node *b) + { return sortByOrder(node_id_to_pos, a, b); }); + } - #ifdef DEBUG_MUTATION - std::cout << "current node:" << this->node_id() << std::endl; - for (int i = 0; i < neighbor_list.size(); ++i) { - std::cout << neighbor_list[i]->node_id() << "(" << neighbor_list[i]->is_marked() << ")" << ","; - } - std::cout << std::endl; - #endif - } + + #ifdef DEBUG_MUTATION + std::cout << "current node:" << this->node_id() << std::endl; + for (size_t i = 0; i < neighbor_list.size(); ++i) { + std::cout << neighbor_list[i]->node_id() << "(" << neighbor_list[i]->is_marked() << ")" << ","; + } + std::cout << std::endl; + #endif + + + // increment traversal index after checking // next node will receive incremented index traversal_index++; - for (int i = 0; i < neighbor_list.size(); ++i) + for (size_t i = 0; i < neighbor_list.size(); ++i) { if (!neighbor_list[i]->is_marked()) { neighbor_list[i]->_parent = this; - neighbor_list[i]->mutated_DFS_visit(dfsList, node_list, return_index, traversal_index, rev_post_order, mutate_point); + neighbor_list[i]->mutated_DFS_visit(dfsList, node_list, return_index, traversal_index, node_id_to_pos, mutate_point, rng); } } @@ -213,7 +232,7 @@ void node::remove_child(int i) { } void node::remove_child(node* n) { - for (int i = 0; i < _children.size(); ++i) { + for (size_t i = 0; i < _children.size(); ++i) { if (_children[i] == n) { _children[i] = _children[_children.size()-1]; _children.resize(_children.size()-1); @@ -289,7 +308,7 @@ void node::init_AE(node* u) { if (u->child_num() == 0) return; _children = u->_children; u->clear_children(); - for (int i = 0; i < _children.size(); ++i) { + for (size_t i = 0; i < _children.size(); ++i) { _children[i]->set_parent(this); } set_parent(u);