From 8ca09dbf9ec6c169f3c411748a3cfbdec8bb389c Mon Sep 17 00:00:00 2001 From: Richard Wong Date: Thu, 22 Feb 2024 10:52:36 +0900 Subject: [PATCH] Bug: fixed broken guided traversal. Discovered that guided traversal rotates the dfs tree. --- deferred_planarity_test/include/mps.h | 14 +++- deferred_planarity_test/src/main.cpp | 24 +++++- deferred_planarity_test/src/mps.cpp | 11 ++- deferred_planarity_test/src/mps_test.cpp | 27 +++++-- deferred_planarity_test/src/node.cpp | 94 ++++++++++++++++++------ 5 files changed, 132 insertions(+), 38 deletions(-) diff --git a/deferred_planarity_test/include/mps.h b/deferred_planarity_test/include/mps.h index 3003163..e2d7639 100644 --- a/deferred_planarity_test/include/mps.h +++ b/deferred_planarity_test/include/mps.h @@ -56,8 +56,17 @@ public: node* adj(int i); void set_adj_list(vector vec); void DFS_visit(vector &dfsList, int &index); - void guided_DFS_visit(vector &dfsList, vector &node_list, int &index, vector rev_post_order); - void mutated_DFS_visit(vector &dfsList, vector &node_list, int &index, vector rev_post_order, int &mutate_point); + void guided_DFS_visit(vector &dfsList, + 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); //PARENT-CHILDREN void set_parent(node* n) ; @@ -150,6 +159,7 @@ public: 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); + vector generate_guided_post_order(string input_file, vector post_order); node* get_new_node(node_type t); void read_from_gml(string input_file); int output_removed_edge_size(); diff --git a/deferred_planarity_test/src/main.cpp b/deferred_planarity_test/src/main.cpp index 88cb85a..3d258b0 100644 --- a/deferred_planarity_test/src/main.cpp +++ b/deferred_planarity_test/src/main.cpp @@ -21,15 +21,31 @@ 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); +vector generate_guided_post_order(string input_file, vector post_order); vector repeated_mutation(string input_file, 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; int num_removed_edges; for (int k = 0; k < k_max; ++k) { - state_new = generate_mutated_post_order(input_file, state_old); - num_removed_edges = compute_removed_edge_size(input_file, state_new); + // rotate it first + std::cout << "cycle:" << k << std::endl; + std::cout << "rotate the dfs tree" << std::endl; + state_new = generate_guided_post_order(input_file, state_old); + // then the next traversal will rotate it back + std::cout << "mutate the dfs tree" << std::endl; + state_new = generate_mutated_post_order(input_file, state_new); + // num_removed_edges = compute_removed_edge_size(input_file, state_new); + // first time will rotate the tree + std::cout << "rotate the dfs tree" << std::endl; + state_new = generate_guided_post_order(input_file, state_new); + // second time will rotate back the rotated tree + std::cout << "print the mutated tree again" << std::endl; + state_new = generate_guided_post_order(input_file, state_new); + std::cout << std::endl; } return state_new; } @@ -62,8 +78,8 @@ int main(int argc, char* argv[]) { int k_max = std::stoi(argv[2]); // generate order here - // vector post_order = repeated_mutation(input_file, k_max); - test_correctness(input_file); + vector post_order = repeated_mutation(input_file, k_max); + // test_correctness(input_file); // // print final order and number of edges // // print post_order diff --git a/deferred_planarity_test/src/mps.cpp b/deferred_planarity_test/src/mps.cpp index 82c1bad..2b3a886 100644 --- a/deferred_planarity_test/src/mps.cpp +++ b/deferred_planarity_test/src/mps.cpp @@ -61,19 +61,21 @@ maximal_planar_subgraph_finder::guidedPostOrderTraversal(vector post_order) int end_condition = _node_list.size(); int start = rev_post_order[0]; int i = start; + + int prev_node = INT_MAX; 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); + _node_list[i]->guided_DFS_visit(_post_order_list, _node_list, postOrderID, rev_post_order, prev_node); } break; } if (!_node_list[i]->is_marked()) { - _node_list[i]->guided_DFS_visit(_post_order_list, _node_list, postOrderID, rev_post_order); + _node_list[i]->guided_DFS_visit(_post_order_list, _node_list, postOrderID, rev_post_order, prev_node); } i = (i + 1) % end_condition; } @@ -91,6 +93,7 @@ maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector post_order rev_post_order.push_back(post_order[i]); } int postOrderID = 0; + int traversal_index = 0; // introduce random selection std::random_device rd; @@ -123,13 +126,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, rev_post_order, mutate_point); + _node_list[i]->mutated_DFS_visit(_post_order_list, _node_list, postOrderID, traversal_index, rev_post_order, mutate_point); } break; } if (!_node_list[i]->is_marked()) { - _node_list[i]->mutated_DFS_visit(_post_order_list, _node_list, postOrderID, rev_post_order, mutate_point); + _node_list[i]->mutated_DFS_visit(_post_order_list, _node_list, postOrderID, traversal_index, rev_post_order, mutate_point); } i = (i + 1) % end_condition; } diff --git a/deferred_planarity_test/src/mps_test.cpp b/deferred_planarity_test/src/mps_test.cpp index 9693983..38d3a0d 100644 --- a/deferred_planarity_test/src/mps_test.cpp +++ b/deferred_planarity_test/src/mps_test.cpp @@ -33,6 +33,11 @@ vector generate_mutated_post_order(string input_file, vector post_orde return m.generate_mutated_post_order(input_file, post_order); } +vector generate_guided_post_order(string input_file, vector post_order) { + maximal_planar_subgraph_finder m; + return m.generate_guided_post_order(input_file, post_order); +} + // --------- @@ -55,6 +60,7 @@ vector maximal_planar_subgraph_finder::generate_post_order(string input_fil postOrderTraversal(); #ifdef DEBUG + std::cout << "standard post order traversal" << std::endl; print_post_order(); #endif @@ -67,6 +73,20 @@ vector maximal_planar_subgraph_finder::generate_mutated_post_order(string i mutatedPostOrderTraversal(post_order); #ifdef DEBUG + std::cout << "mutated post order traversal" << std::endl; + print_post_order(); + #endif + + return return_post_order(); +} + +// 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); + guidedPostOrderTraversal(post_order); + + #ifdef DEBUG + std::cout << "guided post order traversal" << std::endl; print_post_order(); #endif @@ -74,16 +94,13 @@ vector maximal_planar_subgraph_finder::generate_mutated_post_order(string i } + int maximal_planar_subgraph_finder::compute_removed_edge_size(string input_file, vector post_order) { read_from_gml(input_file); guidedPostOrderTraversal(post_order); - - // set post_order_index - for (int i = 0; i < _post_order_list.size(); ++i) { - _node_list[_post_order_list[i]->node_id()]->set_post_order_index(i); - } #ifdef DEBUG + std::cout << "guided post order traversal" << std::endl; print_post_order(); #endif diff --git a/deferred_planarity_test/src/node.cpp b/deferred_planarity_test/src/node.cpp index 380b814..93c856d 100644 --- a/deferred_planarity_test/src/node.cpp +++ b/deferred_planarity_test/src/node.cpp @@ -69,50 +69,96 @@ void node::DFS_visit(vector &dfsList, int &index) { } -void node::guided_DFS_visit(vector &dfsList, vector &node_list, int &index, vector rev_post_order) { +void node::guided_DFS_visit(vector &dfsList, + vector &node_list, + int &return_index, + vector rev_post_order, + int prev_node) +{ + mark(); + // 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 - // purpose of this block: create list of neighbors - vector neighbor_list; + // 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) { - // we get the neighbors via _adj_list - // we get the id's of the neighbor nodes, then we use the id's to get the actual nodes via node_list - // node_list maps id to the actual node - neighbor_list.push_back(node_list[_adj_list[i]->node_id()]); + 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]]); + } + } + } + + #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() << ")" << ","; + } + std::cout << std::endl; + #endif + for (int 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, index, rev_post_order); + neighbor_list[i]->guided_DFS_visit(dfsList, node_list, return_index, rev_post_order, this->node_id()); } } - set_post_order_index(index); + set_post_order_index(return_index); dfsList.push_back(this); - ++index; + ++return_index; } -void node::mutated_DFS_visit(vector &dfsList, vector &node_list, int &index, vector rev_post_order, int &mutate_point) { +void node::mutated_DFS_visit(vector &dfsList, + vector &node_list, + int &return_index, + int &traversal_index, + vector rev_post_order, + int mutate_point) +{ + // mark current node mark(); + + // 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 - // purpose of this block: create list of neighbors - vector neighbor_list; + // 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) { - // we get the neighbors via _adj_list - // we get the id's of the neighbor nodes, then we use the id's to get the actual nodes via node_list - // node_list maps id to the actual node - neighbor_list.push_back(node_list[_adj_list[i]->node_id()]); + 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]]); + } + } + // 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 (index - 1 == mutate_point) { + 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; @@ -120,23 +166,25 @@ void node::mutated_DFS_visit(vector &dfsList, vector &node_list, i // 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++; for (int 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, index, rev_post_order, mutate_point); + neighbor_list[i]->mutated_DFS_visit(dfsList, node_list, return_index, traversal_index, rev_post_order, mutate_point); } } - set_post_order_index(index); + set_post_order_index(return_index); dfsList.push_back(this); - ++index; + ++return_index; } - - //----------------------------------------------------------------------------------- // PARENT-CHILDREN //-----------------------------------------------------------------------------------