Compare commits

..

4 Commits

7 changed files with 259 additions and 222 deletions

View File

@ -1 +1,2 @@
This branch tests the idea of using fuzzing to choose the direction of mutation
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,12 +62,11 @@ 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 &return_index,
vector<int> rev_post_order,
int prev_node);
void mutated_DFS_visit(vector<node*> &dfsList,
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,
@ -156,19 +161,22 @@ 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();
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 mutatedPostOrderTraversal(vector<int> post_order);
// void set_post_order(vector<int> post_order);
void print_post_order();
void set_post_order(vector<int> post_order);
void sort_adj_list();
void determine_edges();
void back_edge_traversal();
@ -194,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,52 +11,60 @@
#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);
vector<int> repeated_mutation(string input_file, int k_max) {
// generate first post order
std::cout << "generate first post order" << std::endl;
void vector_printer(vector<int> state) {
for (int i = 0; i < state.size(); ++i) {
std::cout << state[i] << ",";
}
std::cout << std::endl;
}
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 num_removed_edges;
int removed_old = compute_removed_edge_size(input_file, state_old, mutate_point);
int removed_new;
for (int k = 0; k < k_max; ++k) {
// 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;
std::cout << "first post order" << std::endl;
vector_printer(state_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);
// 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;
// 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);
}
return state_new;
}
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) {
ogdf::Graph G;
@ -76,17 +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 = repeated_mutation(input_file, k_max);
// test_correctness(input_file);
// // 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;
// 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,9 +3,7 @@
//-----------------------------------------------------------------------------------
#include "mps.h"
#include <iterator>
// #define DEBUG
#include <cassert>
// constructor can be made empty
maximal_planar_subgraph_finder::maximal_planar_subgraph_finder() {}
@ -22,6 +20,17 @@ maximal_planar_subgraph_finder::get_new_node(node_type t) {
return _new_node_list[_new_node_list.size()-1];
}
// 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;
@ -31,11 +40,11 @@ maximal_planar_subgraph_finder::return_post_order() {
return post_order;
}
//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()) {
@ -45,9 +54,7 @@ maximal_planar_subgraph_finder::postOrderTraversal() {
}
// 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
//Determine the post-order-list by a DFS-traversal.
void
maximal_planar_subgraph_finder::guidedPostOrderTraversal(vector<int> post_order) {
node::init_mark();
@ -61,33 +68,31 @@ maximal_planar_subgraph_finder::guidedPostOrderTraversal(vector<int> 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, prev_node);
_node_list[i]->guided_DFS_visit(_post_order_list, _node_list, postOrderID, rev_post_order);
}
break;
}
// std::cout << _node_list[i]->node_id() << ", " << !_node_list[i]->is_marked() << std::endl;
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, rev_post_order);
}
i = (i + 1) % end_condition;
}
}
//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
maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> post_order) {
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]);
@ -96,30 +101,16 @@ maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> post_order
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();
// 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)
{
if (((start > 0) && (i == (start - 1))) || ((start == 0 ) && (i == end_condition - 1)))
@ -130,6 +121,7 @@ maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> post_order
}
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, traversal_index, rev_post_order, mutate_point);
@ -138,25 +130,15 @@ maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> post_order
}
}
void
maximal_planar_subgraph_finder::print_post_order() {
int current_index;
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]);
// }
// }
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.
void
@ -187,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) {
@ -198,13 +180,35 @@ 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().

View File

@ -4,23 +4,29 @@
#include "mps.h"
#include <ogdf/fileformats/GraphIO.h>
#include <algorithm>
#include <vector>
#define DEBUG
//-----------------------------------------------------------------------------------
// 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) {
@ -28,90 +34,78 @@ 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) {
maximal_planar_subgraph_finder m;
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);
}
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);
postOrderTraversal();
#ifdef DEBUG
print_post_order();
#endif
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);
set_mutate_point(INT_MAX); // essentially removed mutate_point
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) {
read_from_gml(input_file);
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);
set_mutate_point(INT_MAX); // essentially remove mutate point
guidedPostOrderTraversal(post_order);
#ifdef DEBUG
std::cout << "guided post order traversal" << std::endl;
print_post_order();
#endif
return return_post_order();
}
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 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);
#ifdef DEBUG
std::cout << "guided post order traversal" << std::endl;
print_post_order();
#endif
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
//-----------------------------------------------------------------------------------
@ -130,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();
@ -142,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

@ -4,8 +4,6 @@
#include "mps.h"
// #define DEBUG
//-----------------------------------------------------------------------------------
// CONSTRUCTOR
//-----------------------------------------------------------------------------------
@ -55,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) {
@ -63,78 +63,19 @@ 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 &return_index,
vector<int> rev_post_order,
int prev_node)
vector<int> rev_post_order)
{
mark();
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
// 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()) {
// 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, 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 &return_index,
int &traversal_index,
vector<int> 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
@ -154,18 +95,57 @@ void node::mutated_DFS_visit(vector<node*> &dfsList,
}
}
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, 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 &return_index,
int &traversal_index,
vector<int> rev_post_order,
int mutate_point) {
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
// 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]]);
}
}
// 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
// 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);
}
}
// increment traversal index after checking
// next node will receive incremented index
@ -180,11 +160,14 @@ void node::mutated_DFS_visit(vector<node*> &dfsList,
}
}
set_post_order_index(return_index);
// head recursion like the initial dfs visit implementation
set_post_order_index(return_index);
dfsList.push_back(this);
++return_index;
}
//-----------------------------------------------------------------------------------
// PARENT-CHILDREN
//-----------------------------------------------------------------------------------