Compare commits

...

2 Commits

Author SHA1 Message Date
Richard Wong 8ca09dbf9e
Bug: fixed broken guided traversal. Discovered that guided traversal
rotates the dfs tree.
2024-02-22 10:52:36 +09:00
Richard Wong 54b51b002d
Fix: changed logic in modified-postOrderTraversal to match default
postOrderTraversal
Refactor: make postOrderTraversal functions single responsibility only
2024-02-20 17:00:51 +09:00
6 changed files with 216 additions and 135 deletions

1
README.md Normal file
View File

@ -0,0 +1 @@
This branch tests the idea of using fuzzing to choose the direction of mutation

View File

@ -56,8 +56,17 @@ public:
node* adj(int i); node* adj(int i);
void set_adj_list(vector<node*> vec); void set_adj_list(vector<node*> vec);
void DFS_visit(vector<node*> &dfsList, int &index); void DFS_visit(vector<node*> &dfsList, int &index);
void guided_DFS_visit(vector<node*> &dfsList, vector<node*> &node_list, int &index, vector<int> rev_post_order); void guided_DFS_visit(vector<node *> &dfsList,
void mutated_DFS_visit(vector<node*> &dfsList, vector<node*> &node_list, int &index, vector<int> rev_post_order, int &mutate_point); vector<node *> &node_list,
int &return_index,
vector<int> rev_post_order,
int prev_node);
void mutated_DFS_visit(vector<node*> &dfsList,
vector<node*> &node_list,
int &index,
int &traversal_index,
vector<int> rev_post_order,
int mutate_point);
//PARENT-CHILDREN //PARENT-CHILDREN
void set_parent(node* n) ; void set_parent(node* n) ;
@ -150,13 +159,16 @@ public:
int compute_removed_edge_size(string input_file, vector<int> post_order); int compute_removed_edge_size(string input_file, vector<int> post_order);
vector<int> generate_post_order(string input_file); vector<int> generate_post_order(string input_file);
vector<int> generate_mutated_post_order(string input_file, vector<int> post_order); vector<int> generate_mutated_post_order(string input_file, vector<int> post_order);
vector<int> generate_guided_post_order(string input_file, vector<int> post_order);
node* get_new_node(node_type t); node* get_new_node(node_type t);
void read_from_gml(string input_file); void read_from_gml(string input_file);
int output_removed_edge_size(); int output_removed_edge_size();
vector<int> postOrderTraversal(); vector<int> return_post_order();
vector<int> mutatedPostOrderTraversal(vector<int> post_order); void postOrderTraversal();
void guidedPostOrderTraversal(vector<int> post_order); void guidedPostOrderTraversal(vector<int> post_order);
void set_post_order(vector<int> post_order); void mutatedPostOrderTraversal(vector<int> post_order);
// void set_post_order(vector<int> post_order);
void print_post_order();
void sort_adj_list(); void sort_adj_list();
void determine_edges(); void determine_edges();
void back_edge_traversal(); void back_edge_traversal();

View File

@ -21,44 +21,42 @@ int compute_removed_edge_size(string input_file, vector<int> post_order);
vector<int> generate_post_order(string input_file); vector<int> generate_post_order(string input_file);
vector<int> generate_mutated_post_order(string input_file, vector<int> post_order); vector<int> generate_mutated_post_order(string input_file, vector<int> post_order);
vector<int> generate_guided_post_order(string input_file, vector<int> post_order);
double temp_decay(int k, int k_max) {
return 1.0 - ((k + 1.0) / (k_max));
}
vector<int> sa_solve(string input_file, int k_max) { vector<int> repeated_mutation(string input_file, int k_max) {
// generate first post order
// create sampling function std::cout << "generate first post order" << std::endl;
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_real_distribution<> distribution(0.0, 1.0);
// generate first state
vector<int> state_old = generate_post_order(input_file); vector<int> state_old = generate_post_order(input_file);
vector<int> state_new; vector<int> state_new;
int e_old = compute_removed_edge_size(input_file, state_old); int num_removed_edges;
int e_new = 0;
int delta = 0;
// initialize terms
double temp;
for (int k = 0; k < k_max; ++k) { for (int k = 0; k < k_max; ++k) {
temp = START_TEMP * temp_decay(k, k_max); // rotate it first
std::cout << "cycle:" << k << std::endl;
state_new = generate_mutated_post_order(input_file, state_old); std::cout << "rotate the dfs tree" << std::endl;
e_new = compute_removed_edge_size(input_file, state_new); state_new = generate_guided_post_order(input_file, state_old);
delta = e_new - e_old; // then the next traversal will rotate it back
std::cout << "mutate the dfs tree" << std::endl;
if (std::exp( -(delta) / temp) > distribution(rng)) { state_new = generate_mutated_post_order(input_file, state_new);
state_old = state_new; // num_removed_edges = compute_removed_edge_size(input_file, state_new);
e_old = e_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;
return state_old;
} }
void test_correctness(string input_file) {
vector<int> 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) { int get_graph_size(string input_file) {
ogdf::Graph G; ogdf::Graph G;
@ -80,14 +78,15 @@ int main(int argc, char* argv[]) {
int k_max = std::stoi(argv[2]); int k_max = std::stoi(argv[2]);
// generate order here // generate order here
vector<int> post_order = sa_solve(input_file, k_max); vector<int> post_order = repeated_mutation(input_file, k_max);
// test_correctness(input_file);
// std::copy(post_order.begin(), post_order.end(), std::ostream_iterator<int>(std::cout, " ")); // // print final order and number of edges
// // print post_order
// std::copy(post_order.begin(), post_order.end(), std::ostream_iterator<int>(std::cout, ","));
// std::cout << std::endl; // std::cout << std::endl;
// int removed_edges = compute_removed_edge_size(input_file, post_order);
// print order // std::cout << "Number of removed edges: " << removed_edges << std::endl;
int removed_edges = compute_removed_edge_size(input_file, post_order);
std::cout << "Number of removed edges: " << removed_edges << std::endl;
return 0; return 0;
} }

View File

@ -3,6 +3,9 @@
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
#include "mps.h" #include "mps.h"
#include <iterator>
// #define DEBUG
// constructor can be made empty // constructor can be made empty
maximal_planar_subgraph_finder::maximal_planar_subgraph_finder() {} maximal_planar_subgraph_finder::maximal_planar_subgraph_finder() {}
@ -19,17 +22,8 @@ maximal_planar_subgraph_finder::get_new_node(node_type t) {
return _new_node_list[_new_node_list.size()-1]; return _new_node_list[_new_node_list.size()-1];
} }
//Determine the post-order-list by a DFS-traversal. vector<int>
vector<int> maximal_planar_subgraph_finder::return_post_order() {
maximal_planar_subgraph_finder::postOrderTraversal() {
node::init_mark();
int postOrderID = 0;
for (int i = 0; i < _node_list.size(); ++i) {
if (!_node_list[i]->is_marked()) {
_node_list[i]->DFS_visit(_post_order_list, postOrderID);
}
}
vector<int> post_order; vector<int> post_order;
for (int i = 0; i < _post_order_list.size(); ++i) { for (int i = 0; i < _post_order_list.size(); ++i) {
post_order.push_back(_post_order_list[i]->node_id()); post_order.push_back(_post_order_list[i]->node_id());
@ -37,8 +31,23 @@ maximal_planar_subgraph_finder::postOrderTraversal() {
return post_order; return post_order;
} }
//Determine the post-order-list by a DFS-traversal. //Determine the post-order-list by a DFS-traversal.
void
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) {
if (!_node_list[i]->is_marked()) {
_node_list[i]->DFS_visit(_post_order_list, postOrderID);
}
}
}
// Determine the post-order-list by a DFS-traversal.
// take in a post-order argument then traces the graph in the same order
// return is by reference via _post_order_list
void void
maximal_planar_subgraph_finder::guidedPostOrderTraversal(vector<int> post_order) { maximal_planar_subgraph_finder::guidedPostOrderTraversal(vector<int> post_order) {
node::init_mark(); node::init_mark();
@ -52,27 +61,30 @@ maximal_planar_subgraph_finder::guidedPostOrderTraversal(vector<int> post_order)
int end_condition = _node_list.size(); int end_condition = _node_list.size();
int start = rev_post_order[0]; int start = rev_post_order[0];
int i = start; int i = start;
int prev_node = INT_MAX;
while (true) while (true)
{ {
if (((start > 0) && (i == (start - 1))) || ((start == 0 ) && (i == end_condition - 1))) if (((start > 0) && (i == (start - 1))) || ((start == 0 ) && (i == end_condition - 1)))
{ {
if (!_node_list[i]->is_marked()) 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; break;
} }
// std::cout << _node_list[i]->node_id() << ", " << !_node_list[i]->is_marked() << std::endl;
if (!_node_list[i]->is_marked()) 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; i = (i + 1) % end_condition;
} }
} }
//Determine the post-order-list by a DFS-traversal. //Determine the post-order-list by a DFS-traversal.
vector<int> // 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<int> post_order) { maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> post_order) {
node::init_mark(); node::init_mark();
@ -81,6 +93,7 @@ maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> post_order
rev_post_order.push_back(post_order[i]); rev_post_order.push_back(post_order[i]);
} }
int postOrderID = 0; int postOrderID = 0;
int traversal_index = 0;
// introduce random selection // introduce random selection
std::random_device rd; std::random_device rd;
@ -105,45 +118,46 @@ maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> post_order
int end_condition = _node_list.size(); int end_condition = _node_list.size();
// this loop assumes start is not from 0
// if starting index is not 0, it just increments and loops around until it encounters the element before it
while (true) while (true)
{ {
if (((start > 0) && (i == (start - 1))) || ((start == 0 ) && (i == end_condition - 1))) if (((start > 0) && (i == (start - 1))) || ((start == 0 ) && (i == end_condition - 1)))
{ {
if (!_node_list[i]->is_marked()) 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; break;
} }
// std::cout << _node_list[i]->node_id() << ", " << !_node_list[i]->is_marked() << std::endl;
if (!_node_list[i]->is_marked()) 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; i = (i + 1) % end_condition;
} }
vector<int> return_order;
for (int i = 0; i < _post_order_list.size(); ++i) {
return_order.push_back(_post_order_list[i]->node_id());
}
// we have to reverse the order as we add to list in the forward direction of recursion
// unlike that of previous methods where we add to list in the return direction of recursion
std::reverse(return_order.begin(), return_order.end());
return return_order;
} }
//Set the post-order-list via given list
void void
maximal_planar_subgraph_finder::set_post_order(vector<int> post_order) { maximal_planar_subgraph_finder::print_post_order() {
for (int i = 0; i < _node_list.size(); ++i) { int current_index;
_node_list[i]->set_post_order_index(post_order[i]); for (int i = 0; i < _post_order_list.size(); ++i) {
current_index = _post_order_list[i]->node_id();
std::cout << current_index << ",";
} }
std::cout << std::endl;
} }
// this function is not used anywhere
//Set the post-order-list via given list
// void
// maximal_planar_subgraph_finder::set_post_order(vector<int> post_order) {
// for (int i = 0; i < _node_list.size(); ++i) {
// _node_list[i]->set_post_order_index(post_order[i]);
// }
// }
//Sort the adj-list of every node increasingly according to post-order-index. //Sort the adj-list of every node increasingly according to post-order-index.
void void
maximal_planar_subgraph_finder::sort_adj_list() { maximal_planar_subgraph_finder::sort_adj_list() {

View File

@ -5,6 +5,8 @@
#include "mps.h" #include "mps.h"
#include <ogdf/fileformats/GraphIO.h> #include <ogdf/fileformats/GraphIO.h>
#define DEBUG
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
// Finding MPS // Finding MPS
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
@ -31,12 +33,22 @@ vector<int> generate_mutated_post_order(string input_file, vector<int> post_orde
return m.generate_mutated_post_order(input_file, post_order); return m.generate_mutated_post_order(input_file, post_order);
} }
vector<int> generate_guided_post_order(string input_file, vector<int> post_order) {
maximal_planar_subgraph_finder m;
return m.generate_guided_post_order(input_file, post_order);
}
// --------- // ---------
int maximal_planar_subgraph_finder::find_mps(string input_file) { int maximal_planar_subgraph_finder::find_mps(string input_file) {
read_from_gml(input_file); read_from_gml(input_file);
postOrderTraversal(); postOrderTraversal();
#ifdef DEBUG
print_post_order();
#endif
sort_adj_list(); sort_adj_list();
determine_edges(); determine_edges();
back_edge_traversal(); back_edge_traversal();
@ -45,31 +57,52 @@ int maximal_planar_subgraph_finder::find_mps(string input_file) {
vector<int> maximal_planar_subgraph_finder::generate_post_order(string input_file) { vector<int> maximal_planar_subgraph_finder::generate_post_order(string input_file) {
read_from_gml(input_file); read_from_gml(input_file);
return postOrderTraversal(); postOrderTraversal();
#ifdef DEBUG
std::cout << "standard 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<int> maximal_planar_subgraph_finder::generate_mutated_post_order(string input_file, vector<int> post_order) { vector<int> maximal_planar_subgraph_finder::generate_mutated_post_order(string input_file, vector<int> post_order) {
read_from_gml(input_file); read_from_gml(input_file);
return mutatedPostOrderTraversal(post_order); 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<int> maximal_planar_subgraph_finder::generate_guided_post_order(string input_file, vector<int> post_order) {
read_from_gml(input_file);
guidedPostOrderTraversal(post_order);
#ifdef DEBUG
std::cout << "guided post order traversal" << std::endl;
print_post_order();
#endif
return return_post_order();
}
int maximal_planar_subgraph_finder::compute_removed_edge_size(string input_file, vector<int> post_order) { int maximal_planar_subgraph_finder::compute_removed_edge_size(string input_file, vector<int> post_order) {
read_from_gml(input_file); read_from_gml(input_file);
guidedPostOrderTraversal(post_order); guidedPostOrderTraversal(post_order);
// let's reverse the order #ifdef DEBUG
std::reverse(_post_order_list.begin(), _post_order_list.end()); std::cout << "guided post order traversal" << std::endl;
// then set post_order_index print_post_order();
for (int i = 0; i < _post_order_list.size(); ++i) { #endif
_node_list[_post_order_list[i]->node_id()]->set_post_order_index(i);
}
// std::cout << "check order of duplicated traversal" << std::endl;
// for (int i = 0; i < _post_order_list.size(); ++i) {
// std::cout << _post_order_list[i]->node_id() << " ";
// }
// std::cout << std::endl;
sort_adj_list(); sort_adj_list();
determine_edges(); determine_edges();

View File

@ -4,6 +4,8 @@
#include "mps.h" #include "mps.h"
// #define DEBUG
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
// CONSTRUCTOR // CONSTRUCTOR
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
@ -67,102 +69,122 @@ void node::DFS_visit(vector<node*> &dfsList, int &index) {
} }
void node::guided_DFS_visit(vector<node*> &dfsList, vector<node*> &node_list, int &index, vector<int> rev_post_order) { void node::guided_DFS_visit(vector<node *> &dfsList,
vector<node *> &node_list,
int &return_index,
vector<int> rev_post_order,
int prev_node)
{
mark(); mark();
// you will want to sort the neighbor nodes by the order they appear in the rev_post_order
vector<node *> neighbor_list; // purpose of this block: create list of neighbors ordered in the order they appear in rev_post_order
std::unordered_set<int> neighbor_set; // 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 // create an unordered set to efficiently check for presence of an element
std::unordered_set<int> neighbor_set;
for (int i = 0; i < _adj_list.size(); ++i) { for (int i = 0; i < _adj_list.size(); ++i) {
neighbor_set.insert(_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 // 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<node *> neighbor_list;
for (int i = 0; i < rev_post_order.size(); ++i) { for (int i = 0; i < rev_post_order.size(); ++i) {
if (neighbor_set.find(rev_post_order[i]) != neighbor_set.end()) { if (neighbor_set.find(rev_post_order[i]) != neighbor_set.end()) {
neighbor_list.push_back(node_list[rev_post_order[i]]); // only add if newly encountered
if (!node_list[rev_post_order[i]]->is_marked()) {
neighbor_list.push_back(node_list[rev_post_order[i]]);
}
} }
} }
// print the neighbors #ifdef DEBUG
// std::cout << "current index: " << this->node_id() << std::endl; std::cout << "current node:" << this->node_id() << std::endl;
// for (int i = 0; i < neighbor_list.size(); ++i) { std::cout << "prev node:" << prev_node << std::endl;
// std::cout << neighbor_list[i]->node_id() << " "; 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; }
std::cout << std::endl;
#endif
set_post_order_index(index);
dfsList.push_back(this);
++index;
for (int i = 0; i < neighbor_list.size(); ++i) { for (int i = 0; i < neighbor_list.size(); ++i) {
if (!neighbor_list[i]->is_marked()) { if (!neighbor_list[i]->is_marked()) {
neighbor_list[i]->_parent = this; 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(return_index);
dfsList.push_back(this);
++return_index;
} }
void node::mutated_DFS_visit(vector<node*> &dfsList, vector<node*> &node_list, int &index, vector<int> rev_post_order, int &mutate_point) { void node::mutated_DFS_visit(vector<node*> &dfsList,
vector<node*> &node_list,
int &return_index,
int &traversal_index,
vector<int> rev_post_order,
int mutate_point)
{
// mark current node
mark(); mark();
// you will want to sort the neighbor nodes by the order they appear in the rev_post_order
vector<node *> neighbor_list;
std::unordered_set<int> neighbor_set;
// 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 // create an unordered set to efficiently check for presence of an element
std::unordered_set<int> neighbor_set;
for (int i = 0; i < _adj_list.size(); ++i) { for (int i = 0; i < _adj_list.size(); ++i) {
neighbor_set.insert(_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 // 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<node *> neighbor_list;
for (int i = 0; i < rev_post_order.size(); ++i) { for (int i = 0; i < rev_post_order.size(); ++i) {
if (neighbor_set.find(rev_post_order[i]) != neighbor_set.end()) { if (neighbor_set.find(rev_post_order[i]) != neighbor_set.end()) {
neighbor_list.push_back(node_list[rev_post_order[i]]); neighbor_list.push_back(node_list[rev_post_order[i]]);
} }
} }
// print the neighbors
// std::cout << "current index: " << this->node_id() << std::endl;
// for (int i = 0; i < neighbor_list.size(); ++i) {
// std::cout << neighbor_list[i]->node_id() << " ";
// }
// std::cout << std::endl;
set_post_order_index(index); // since we increment the index before this line, the current index is "index - 1"
dfsList.push_back(this); // if the current index matches the mutate_point, then we know this is the cycle to mutate
++index; if (traversal_index == mutate_point) {
if (index - 1 == mutate_point) {
// Create a random number generator and seed it // Create a random number generator and seed it
// std::cout << "mutated at index: " << index - 1<< "and at mutate point: " << mutate_point << std::endl; // std::cout << "mutated at index: " << index - 1<< "and at mutate point: " << mutate_point << std::endl;
std::random_device rd; std::random_device rd;
std::mt19937 rng(rd()); std::mt19937 rng(rd());
// Use std::shuffle to shuffle the elements in the vector // Use std::shuffle to shuffle the elements in the vector
std::shuffle(neighbor_list.begin(), neighbor_list.end(), rng); std::shuffle(neighbor_list.begin(), neighbor_list.end(), rng);
// // print the neighbors
// std::cout << "order after mutation: " << std::endl;
// std::cout << "current index: " << this->node_id() << std::endl;
// for (int i = 0; i < neighbor_list.size(); ++i)
// {
// std::cout << neighbor_list[i]->node_id() << " ";
// }
// std::cout << std::endl;
} }
// increment traversal index after checking
// next node will receive incremented index
traversal_index++;
for (int i = 0; i < neighbor_list.size(); ++i) for (int i = 0; i < neighbor_list.size(); ++i)
{ {
if (!neighbor_list[i]->is_marked()) if (!neighbor_list[i]->is_marked())
{ {
neighbor_list[i]->_parent = this; 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(return_index);
dfsList.push_back(this);
++return_index;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
// PARENT-CHILDREN // PARENT-CHILDREN
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------