diff --git a/deferred_planarity_test/include/mps.h b/deferred_planarity_test/include/mps.h index 2844290..c5a0fae 100644 --- a/deferred_planarity_test/include/mps.h +++ b/deferred_planarity_test/include/mps.h @@ -63,13 +63,14 @@ public: const vector &node_list, int &return_index, const unordered_map &node_id_to_pos); - void mutated_DFS_visit(vector &dfsList, - vector &node_list, - int &index, - int &traversal_index, - vector rev_post_order, - int mutate_point); - + void mutated_DFS_visit(vector &dfsList, + 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); @@ -164,11 +165,11 @@ public: // 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, vector post_order, int mutate_point); - vector generate_guided_post_order(const ogdf::Graph &G, vector post_order); + 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(vector post_order); - void mutatedPostOrderTraversal(vector post_order, int mutate_point); + 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 diff --git a/deferred_planarity_test/src/main.cpp b/deferred_planarity_test/src/main.cpp index aa3229b..8d9c68a 100644 --- a/deferred_planarity_test/src/main.cpp +++ b/deferred_planarity_test/src/main.cpp @@ -52,12 +52,11 @@ vector repeated_mutation(const ogdf::Graph &G, int k_max) { // 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 - int mutate_point = dist(gen); // generate number for (int k = 0; k < k_max; ++k) { // function compute new post_order and new_removed_size // temp_order and new_removed_size will be updated with new values - compute_mps(G, mutate_point, temp_order, new_removed_size); + compute_mps(G, dist(gen), temp_order, new_removed_size); // 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 diff --git a/deferred_planarity_test/src/mps.cpp b/deferred_planarity_test/src/mps.cpp index 6f61c6e..8c27ff9 100644 --- a/deferred_planarity_test/src/mps.cpp +++ b/deferred_planarity_test/src/mps.cpp @@ -24,6 +24,8 @@ maximal_planar_subgraph_finder::get_new_node(node_type t) { vector maximal_planar_subgraph_finder::return_post_order() { vector post_order; + // 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()); } @@ -48,7 +50,7 @@ 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(); // // implementation 1: pass reversed vector @@ -61,6 +63,7 @@ maximal_planar_subgraph_finder::guidedPostOrderTraversal(vector post_order) // 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) { @@ -73,6 +76,10 @@ maximal_planar_subgraph_finder::guidedPostOrderTraversal(vector post_order) int start = post_order[post_order.size() - 1]; int i = start; + // 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))) @@ -95,24 +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; + // // 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) { - rev_post_order.push_back(post_order[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 @@ -123,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; } diff --git a/deferred_planarity_test/src/mps_test.cpp b/deferred_planarity_test/src/mps_test.cpp index b4ae576..91a1d0b 100644 --- a/deferred_planarity_test/src/mps_test.cpp +++ b/deferred_planarity_test/src/mps_test.cpp @@ -8,7 +8,7 @@ #include // #define DEBUG -#define DEBUG_2 +// #define DEBUG_2 // #define TIME //----------------------------------------------------------------------------------- @@ -90,7 +90,7 @@ vector maximal_planar_subgraph_finder::generate_post_order(const ogdf::Grap } // result of this will be used as input to "compute_removed_edge_size" -vector maximal_planar_subgraph_finder::generate_mutated_post_order(const ogdf::Graph &G, vector post_order, int mutate_point) { +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); @@ -104,7 +104,7 @@ vector maximal_planar_subgraph_finder::generate_mutated_post_order(const og } // result of this will be used as input to "compute_removed_edge_size" -vector maximal_planar_subgraph_finder::generate_guided_post_order(const ogdf::Graph &G, vector post_order) { +vector maximal_planar_subgraph_finder::generate_guided_post_order(const ogdf::Graph &G, const vector &post_order) { init_from_graph(G); guidedPostOrderTraversal(post_order); @@ -208,6 +208,7 @@ void maximal_planar_subgraph_finder::compute_mps(const ogdf::Graph &G, int mutat 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); diff --git a/deferred_planarity_test/src/node.cpp b/deferred_planarity_test/src/node.cpp index 5eeb34c..01940ba 100644 --- a/deferred_planarity_test/src/node.cpp +++ b/deferred_planarity_test/src/node.cpp @@ -139,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, + vector &node_list, + int &return_index, + int &traversal_index, + const unordered_map &node_id_to_pos, + int mutate_point, + mt19937 rng) { // mark current node @@ -154,22 +154,37 @@ 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 (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]]); - } + // // 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]]); + // } + // } + + 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) { + // 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 (size_t i = 0; i < neighbor_list.size(); ++i) { @@ -179,18 +194,7 @@ void node::mutated_DFS_visit(vector &dfsList, #endif - // since we increment the index before this line, the current index is "index - 1" - // 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 - std::shuffle(neighbor_list.begin(), neighbor_list.end(), rng); - - } - + // increment traversal index after checking // next node will receive incremented index traversal_index++; @@ -200,7 +204,7 @@ void node::mutated_DFS_visit(vector &dfsList, 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); } }