Compare commits

...

4 Commits

7 changed files with 275 additions and 157 deletions

2
README.md Normal file
View File

@ -0,0 +1,2 @@
The objective of this branch is to measure the number of removed edges between
preserved and mutated parts of the DFS tree.

View File

@ -33,6 +33,12 @@ enum node_type {
AE_VIRTUAL_ROOT = 3
};
enum back_edge_type {
RETAINED = 0,
MUTATED_REMOVE = 1,
NON_MUTATED_REMOVE = 2
};
class node
{
public:
@ -56,8 +62,16 @@ public:
node* adj(int i);
void set_adj_list(vector<node*> vec);
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 mutated_DFS_visit(vector<node*> &dfsList, vector<node*> &node_list, int &index, vector<int> rev_post_order, int &mutate_point);
void guided_DFS_visit(vector<node*> &dfsList,
vector<node*> &node_list,
int &return_index,
vector<int> rev_post_order);
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
void set_parent(node* n) ;
@ -147,14 +161,20 @@ public:
maximal_planar_subgraph_finder();
~maximal_planar_subgraph_finder();
int find_mps(string input_file);
int compute_removed_edge_size(string input_file, vector<int> post_order);
int compute_removed_edge_size(string input_file, vector<int> post_order, int mutate_point);
void print_removed_edge_stats(string input_file, vector<int> post_order, int mutate_point);
vector<int> generate_post_order(string input_file);
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);
vector<int> generate_mutated_post_order(string input_file, vector<int> post_order, int mutate_point);
void set_mutate_point(int mutate_point);
int get_mutate_point();
node* get_new_node(node_type t);
void read_from_gml(string input_file);
int output_removed_edge_size();
vector<int> postOrderTraversal();
vector<int> mutatedPostOrderTraversal(vector<int> post_order);
void output_print_removed_edge_stats();
int output_int_removed_edge_size();
vector<int> return_post_order();
void postOrderTraversal();
void mutatedPostOrderTraversal(vector<int> post_order, int mutate_point);
void guidedPostOrderTraversal(vector<int> post_order);
void set_post_order(vector<int> post_order);
void sort_adj_list();
@ -182,8 +202,9 @@ private:
vector<pair<node*, node*> > _edge_list; // Edges in DFS-tree. These edges must be contained in the maximal planar subgraph that we found.
vector<node*> _post_order_list; //The sorted version (increasing with post-order-index) of _node_list.
vector<pair<node*, node*> > _back_edge_list; // Edges other than that in DFS-tree. (The first node's index is higher than the second's.)
vector<bool> _is_back_edge_eliminate; //Record that if the back-edge has been eliminated or not.
vector<back_edge_type> _is_back_edge_eliminate; //Record that if the back-edge has been eliminated or not.
vector<node*> _new_node_list; //Newly added nodes.
int _mutate_point; // store the mutate_point
};
#endif

View File

@ -31,4 +31,4 @@ $(BIN_DIR) $(OBJ_DIR):
.PHONY: clean
clean:
rm -r $(BIN_DIR) $(OBJ_DIR)
rm -r $(OBJ_DIR)

View File

@ -11,51 +11,57 @@
#include <iterator>
#include <random>
#include <vector>
#include <ogdf/fileformats/GraphIO.h>
#define START_TEMP 100
using namespace std;
int compute_removed_edge_size(string input_file, vector<int> post_order);
// functions defined in mps_test.cpp
int compute_removed_edge_size(string input_file, vector<int> post_order, int mutate_point);
void print_removed_edge_stats(string input_file, vector<int> post_order, int mutate_point);
vector<int> generate_post_order(string input_file);
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);
vector<int> generate_mutated_post_order_at_x(string input_file, vector<int> post_order, int mutate_point);
double temp_decay(int k, int k_max) {
return 1.0 - ((k + 1.0) / (k_max));
void vector_printer(vector<int> state) {
for (int i = 0; i < state.size(); ++i) {
std::cout << state[i] << ",";
}
std::cout << std::endl;
}
vector<int> sa_solve(string input_file, int k_max) {
// create sampling function
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_real_distribution<> distribution(0.0, 1.0);
void measure_removed_edges(string input_file, int k_max, int mutate_point) {
// generate first state
vector<int> state_old = generate_post_order(input_file);
vector<int> state_new;
int e_old = compute_removed_edge_size(input_file, state_old);
int e_new = 0;
int delta = 0;
// initialize terms
double temp;
int removed_old = compute_removed_edge_size(input_file, state_old, mutate_point);
int removed_new;
for (int k = 0; k < k_max; ++k) {
temp = START_TEMP * temp_decay(k, k_max);
std::cout << "first post order" << std::endl;
vector_printer(state_old);
state_new = generate_mutated_post_order(input_file, state_old);
e_new = compute_removed_edge_size(input_file, state_new);
delta = e_new - e_old;
// run mutation on canonical representation directly
state_new = generate_mutated_post_order_at_x(input_file, state_old, mutate_point);
// rotate output of mutated state to canonical representation
state_new = generate_guided_post_order(input_file, state_new);
// tree produced should be the same as tree from mutation
removed_new = compute_removed_edge_size(input_file, state_new, mutate_point);
std::cout << "mutated post order" << std::endl;
vector_printer(state_new);
// std::cout << "removed edges in old: " << removed_old << std::endl;
// std::cout << "removed edges in new: " << removed_new << std::endl;
print_removed_edge_stats(input_file, state_new, mutate_point);
if (std::exp( -(delta) / temp) > distribution(rng)) {
state_old = state_new;
e_old = e_new;
}
}
return state_old;
}
@ -78,16 +84,10 @@ 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]);
// generate order here
vector<int> post_order = sa_solve(input_file, k_max);
// std::copy(post_order.begin(), post_order.end(), std::ostream_iterator<int>(std::cout, " "));
// std::cout << std::endl;
// print order
int removed_edges = compute_removed_edge_size(input_file, post_order);
std::cout << "Number of removed edges: " << removed_edges << std::endl;
measure_removed_edges(input_file, k_max, mutate_point);
return 0;
}

View File

@ -3,6 +3,7 @@
//-----------------------------------------------------------------------------------
#include "mps.h"
#include <cassert>
// constructor can be made empty
maximal_planar_subgraph_finder::maximal_planar_subgraph_finder() {}
@ -19,8 +20,29 @@ maximal_planar_subgraph_finder::get_new_node(node_type t) {
return _new_node_list[_new_node_list.size()-1];
}
//Determine the post-order-list by a DFS-traversal.
// setter and getter for mutate_point
void
maximal_planar_subgraph_finder::set_mutate_point(int mutate_point) {
_mutate_point = mutate_point;
}
int
maximal_planar_subgraph_finder::get_mutate_point() {
return _mutate_point;
}
vector<int>
maximal_planar_subgraph_finder::return_post_order() {
vector<int> post_order;
for (int i = 0; i < _post_order_list.size(); ++i) {
post_order.push_back(_post_order_list[i]->node_id());
}
return post_order;
}
//Determine the post-order-list by a DFS-traversal.
void
maximal_planar_subgraph_finder::postOrderTraversal() {
node::init_mark();
int postOrderID = 0;
@ -29,12 +51,6 @@ maximal_planar_subgraph_finder::postOrderTraversal() {
_node_list[i]->DFS_visit(_post_order_list, postOrderID);
}
}
vector<int> post_order;
for (int i = 0; i < _post_order_list.size(); ++i) {
post_order.push_back(_post_order_list[i]->node_id());
}
return post_order;
}
@ -72,37 +88,27 @@ maximal_planar_subgraph_finder::guidedPostOrderTraversal(vector<int> post_order)
}
//Determine the post-order-list by a DFS-traversal.
vector<int>
maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> post_order) {
void
maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> post_order, int mutate_point) {
node::init_mark();
// reverse post_order because reversed post_order is the traversal of the DFS tree from the starting node
vector<int> rev_post_order;
for (int i = post_order.size() - 1; i >= 0; --i) {
rev_post_order.push_back(post_order[i]);
}
int postOrderID = 0;
int traversal_index = 0;
// introduce random selection
std::random_device rd;
std::mt19937 rng(rd());
// Define the range [0, n]
int n = _node_list.size() - 1; // Change 'n' to your desired upper bound
// Create a uniform distribution for the range [0, n]
std::uniform_int_distribution<int> distribution(0, n);
// Generate a random number between 0 and n (inclusive)
int mutate_point = distribution(rng);
// std::cout << "the mutate point: " << mutate_point << std::endl;
// assert(mutate_point < n);
// set loop variables
int start = rev_post_order[0];
int i = start;
// if mutate_point = 0
if (mutate_point == 0) {
// generate another point
start = distribution(rng);
}
int end_condition = _node_list.size();
while (true)
@ -111,27 +117,17 @@ maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> 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;
}
// std::cout << _node_list[i]->node_id() << ", " << !_node_list[i]->is_marked() << std::endl;
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;
}
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;
}
@ -173,7 +169,7 @@ maximal_planar_subgraph_finder::determine_edges() {
if (_post_order_list[i]->adj(j)->post_order_index() > i) break;
if (_post_order_list[i]->adj(j)->get_1st_label() == i) continue;
_back_edge_list.push_back(pair<node*, node*> (_post_order_list[i], _post_order_list[i]->adj(j)));
_is_back_edge_eliminate.push_back(false);
_is_back_edge_eliminate.push_back(RETAINED);
}
}
for (int i = 0; i < _post_order_list.size(); ++i) {
@ -184,14 +180,36 @@ maximal_planar_subgraph_finder::determine_edges() {
//The main part of the whole algorithm: Back-edge-traversal
void
maximal_planar_subgraph_finder::back_edge_traversal() {
node* i_node = 0;
node* current_node = 0;
node* i_node = nullptr;
node* current_node = nullptr;
int dfs_mutate_point = get_mutate_point();
int node_list_last_index = _node_list.size() - 1;
// dfs_mutate_point starts counting from the DFS head
// post_order starts from the last leaf of the DFS tree
// hence we start counting from the post_order last index
int post_order_mutate_point = node_list_last_index - dfs_mutate_point;
// std::cout << "post_order_mutate_point: " << post_order_mutate_point << std::endl;
// back_edge first node is higher than the second
for (int i = 0; i < _back_edge_list.size(); ++i) {
// current node is the lower
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;
// back_edge_traversal returns true if it should be included
// false otherwise
if (!back_edge_traversal(current_node, i_node->post_order_index())) {
// if current_node is higher than post_order_mutate_point
// then it is the preserved section
if (current_node->post_order_index() > post_order_mutate_point) {
std::cout << "(" << current_node->node_id() << "[" << current_node->post_order_index() << "]"
<< "," << i_node->node_id() << "[" << i_node->post_order_index() << "]" << ") ";
_is_back_edge_eliminate[i] = NON_MUTATED_REMOVE;
} else {
_is_back_edge_eliminate[i] = MUTATED_REMOVE;
}
}
}
std::cout << std::endl;
}
//sub-function for the for-loop of back_edge_traversal().
bool maximal_planar_subgraph_finder::back_edge_traversal(node* traverse_node, int index) {

View File

@ -4,21 +4,29 @@
#include "mps.h"
#include <ogdf/fileformats/GraphIO.h>
#include <algorithm>
#include <vector>
//-----------------------------------------------------------------------------------
// Finding MPS
//-----------------------------------------------------------------------------------
// programs to call from main:
// functions to call from main:
int find_mps(string input_file) {
maximal_planar_subgraph_finder m;
return m.find_mps(input_file);
}
int compute_removed_edge_size(string input_file, vector<int> post_order) {
int compute_removed_edge_size(string input_file, vector<int> post_order, int mutate_point) {
maximal_planar_subgraph_finder m;
return m.compute_removed_edge_size(input_file, post_order);
return m.compute_removed_edge_size(input_file, post_order, mutate_point);
}
void print_removed_edge_stats(string input_file, vector<int> post_order, int mutate_point) {
maximal_planar_subgraph_finder m;
m.print_removed_edge_stats(input_file, post_order, mutate_point);
}
vector<int> generate_post_order(string input_file) {
@ -26,13 +34,18 @@ vector<int> generate_post_order(string input_file) {
return m.generate_post_order(input_file);
}
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) {
maximal_planar_subgraph_finder m;
return m.generate_mutated_post_order(input_file, post_order);
return m.generate_guided_post_order(input_file, post_order);
}
vector<int> generate_mutated_post_order_at_x(string input_file, vector<int> post_order, int mutate_point) {
maximal_planar_subgraph_finder m;
return m.generate_mutated_post_order(input_file, post_order, mutate_point);
}
// ---------
// immediate functions called by functions called from main
int maximal_planar_subgraph_finder::find_mps(string input_file) {
read_from_gml(input_file);
@ -40,45 +53,59 @@ int maximal_planar_subgraph_finder::find_mps(string input_file) {
sort_adj_list();
determine_edges();
back_edge_traversal();
return output_removed_edge_size();
return output_int_removed_edge_size();
}
vector<int> maximal_planar_subgraph_finder::generate_post_order(string input_file) {
read_from_gml(input_file);
return postOrderTraversal();
set_mutate_point(INT_MAX); // essentially removed mutate_point
postOrderTraversal();
return return_post_order();
}
vector<int> maximal_planar_subgraph_finder::generate_mutated_post_order(string input_file, vector<int> post_order) {
read_from_gml(input_file);
return mutatedPostOrderTraversal(post_order);
}
int maximal_planar_subgraph_finder::compute_removed_edge_size(string input_file, vector<int> post_order) {
vector<int> maximal_planar_subgraph_finder::generate_guided_post_order(string input_file, vector<int> post_order) {
read_from_gml(input_file);
set_mutate_point(INT_MAX); // essentially remove mutate point
guidedPostOrderTraversal(post_order);
// let's reverse the order
std::reverse(_post_order_list.begin(), _post_order_list.end());
// then 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);
return return_post_order();
}
// 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;
vector<int> maximal_planar_subgraph_finder::generate_mutated_post_order(string input_file, vector<int> post_order, int mutate_point) {
read_from_gml(input_file);
set_mutate_point(INT_MAX);
mutatedPostOrderTraversal(post_order, mutate_point);
return return_post_order();
}
int maximal_planar_subgraph_finder::compute_removed_edge_size(string input_file, vector<int> post_order, int mutate_point) {
read_from_gml(input_file);
set_mutate_point(mutate_point);
guidedPostOrderTraversal(post_order);
sort_adj_list();
determine_edges();
back_edge_traversal();
return output_removed_edge_size();
return output_int_removed_edge_size();
}
void maximal_planar_subgraph_finder::print_removed_edge_stats(string input_file, vector<int> post_order, int mutate_point) {
read_from_gml(input_file);
set_mutate_point(mutate_point);
guidedPostOrderTraversal(post_order);
sort_adj_list();
determine_edges();
back_edge_traversal();
output_print_removed_edge_stats();
}
//-----------------------------------------------------------------------------------
// Imput, output
// Input, output
//-----------------------------------------------------------------------------------
@ -97,6 +124,14 @@ void maximal_planar_subgraph_finder::read_from_gml(string input_file) {
_node_list[i]->set_id(i);
}
// vector<ogdf::edge> unique_edges;
// // we want to get unique edge only
// for (ogdf::edge e : G.edges) {
// // Check if the edge is already in the array
// if (std::find(unique_edges.begin(), unique_edges.end(), e) == unique_edges.end())
// unique_edges.push_back(e);
// }
// create edges
for (ogdf::edge e : G.edges) {
ogdf::node source = e->source();
@ -109,10 +144,47 @@ 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() {
void maximal_planar_subgraph_finder::output_print_removed_edge_stats() {
int mutated_sum = 0;
int preserved_sum = 0;
vector<pair<node*, node*>> mutated_removed_edges;
vector<pair<node*, node*>> preserved_removed_edges;
for (int i = 0; i < _back_edge_list.size(); ++i) {
if (_is_back_edge_eliminate[i] == MUTATED_REMOVE) {
mutated_removed_edges.push_back(_back_edge_list[i]);
++mutated_sum;
}
if (_is_back_edge_eliminate[i] == NON_MUTATED_REMOVE) {
preserved_removed_edges.push_back(_back_edge_list[i]);
++preserved_sum;
}
}
// print the edges
// std::cout << "mutated removed edges: " << std::endl;
// for (int i = 0; i < mutated_removed_edges.size(); ++i) {
// std::cout << mutated_removed_edges[i].first->node_id() << ", " <<
// mutated_removed_edges[i].second->node_id() << std::endl;
// }
// std::cout << "preserved removed edges: " << std::endl;
// for (int i = 0; i < preserved_removed_edges.size(); ++i) {
// std::cout << preserved_removed_edges[i].first->node_id() << ", " <<
// preserved_removed_edges[i].second->node_id() << std::endl;
// }
std::cout << "<- sum of removed edges -> " << std::endl;
std::cout << "mutated portion: " << mutated_sum << std::endl;
std::cout << "preserved portion: " << preserved_sum << std::endl;
}
int maximal_planar_subgraph_finder::output_int_removed_edge_size() {
int sum = 0;
for (int i = 0; i < _back_edge_list.size(); ++i) {
if (_is_back_edge_eliminate[i]) ++sum;
if (_is_back_edge_eliminate[i] != RETAINED) ++sum;
}
return sum;
}

View File

@ -53,6 +53,8 @@ node* node::adj(int i) {return _adj_list[i];}
void node::set_adj_list(vector<node*> vec) {_adj_list = vec;}
// original DFS visit implementation
// it just uses _adj_list directly as list of neighbors
void node::DFS_visit(vector<node*> &dfsList, int &index) {
mark();
for (int i = 0; i < _adj_list.size(); ++i) {
@ -61,104 +63,107 @@ void node::DFS_visit(vector<node*> &dfsList, int &index) {
_adj_list[i]->DFS_visit(dfsList, index);
}
}
// head recursion: function call before returning result
set_post_order_index(index);
dfsList.push_back(this);
++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)
{
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
std::unordered_set<int> 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<node *> 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]]);
}
}
// 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);
dfsList.push_back(this);
++index;
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);
}
}
// head recursion
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();
// 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
std::unordered_set<int> 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<node *> 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]]);
}
}
// 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);
dfsList.push_back(this);
++index;
if (index - 1 == mutate_point) {
// introduce mutation at 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;
std::mt19937 rng(rd());
// Use std::shuffle to shuffle the elements in the vector
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)
{
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);
}
}
// head recursion like the initial dfs visit implementation
set_post_order_index(return_index);
dfsList.push_back(this);
++return_index;
}