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 AE_VIRTUAL_ROOT = 3
}; };
enum back_edge_type {
RETAINED = 0,
MUTATED_REMOVE = 1,
NON_MUTATED_REMOVE = 2
};
class node class node
{ {
public: public:
@ -56,12 +62,11 @@ 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, void guided_DFS_visit(vector<node*> &dfsList,
vector<node *> &node_list, vector<node*> &node_list,
int &return_index, int &return_index,
vector<int> rev_post_order, vector<int> rev_post_order);
int prev_node); void mutated_DFS_visit(vector<node*> &dfsList,
void mutated_DFS_visit(vector<node*> &dfsList,
vector<node*> &node_list, vector<node*> &node_list,
int &index, int &index,
int &traversal_index, int &traversal_index,
@ -156,19 +161,22 @@ public:
maximal_planar_subgraph_finder(); maximal_planar_subgraph_finder();
~maximal_planar_subgraph_finder(); ~maximal_planar_subgraph_finder();
int find_mps(string input_file); 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_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_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); 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(); void output_print_removed_edge_stats();
int output_int_removed_edge_size();
vector<int> return_post_order(); vector<int> return_post_order();
void postOrderTraversal(); void postOrderTraversal();
void mutatedPostOrderTraversal(vector<int> post_order, int mutate_point);
void guidedPostOrderTraversal(vector<int> post_order); void guidedPostOrderTraversal(vector<int> post_order);
void mutatedPostOrderTraversal(vector<int> post_order); void set_post_order(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();
@ -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<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<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<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. vector<node*> _new_node_list; //Newly added nodes.
int _mutate_point; // store the mutate_point
}; };
#endif #endif

View File

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

View File

@ -11,52 +11,60 @@
#include <iterator> #include <iterator>
#include <random> #include <random>
#include <vector> #include <vector>
#include <ogdf/fileformats/GraphIO.h> #include <ogdf/fileformats/GraphIO.h>
#define START_TEMP 100
using namespace std; 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_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_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) { void vector_printer(vector<int> state) {
// generate first post order for (int i = 0; i < state.size(); ++i) {
std::cout << "generate first post order" << std::endl; 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_old = generate_post_order(input_file);
vector<int> state_new; 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) { for (int k = 0; k < k_max; ++k) {
// rotate it first std::cout << "first post order" << std::endl;
std::cout << "cycle:" << k << std::endl; vector_printer(state_old);
std::cout << "rotate the dfs tree" << std::endl;
state_new = generate_guided_post_order(input_file, state_old); // run mutation on canonical representation directly
// then the next traversal will rotate it back state_new = generate_mutated_post_order_at_x(input_file, state_old, mutate_point);
std::cout << "mutate the dfs tree" << std::endl; // rotate output of mutated state to canonical representation
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); state_new = generate_guided_post_order(input_file, state_new);
// second time will rotate back the rotated tree // tree produced should be the same as tree from mutation
std::cout << "print the mutated tree again" << std::endl; removed_new = compute_removed_edge_size(input_file, state_new, mutate_point);
state_new = generate_guided_post_order(input_file, state_new);
std::cout << std::endl; 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) { int get_graph_size(string input_file) {
ogdf::Graph G; ogdf::Graph G;
@ -76,17 +84,10 @@ int get_graph_size(string input_file) {
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
string input_file = argv[1]; string input_file = argv[1];
int k_max = std::stoi(argv[2]); int k_max = std::stoi(argv[2]);
int mutate_point = std::stoi(argv[3]);
// generate order here // generate order here
vector<int> post_order = repeated_mutation(input_file, k_max); measure_removed_edges(input_file, k_max, mutate_point);
// 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;
return 0; return 0;
} }

View File

@ -3,9 +3,7 @@
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
#include "mps.h" #include "mps.h"
#include <iterator> #include <cassert>
// #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() {}
@ -22,6 +20,17 @@ 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];
} }
// 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> vector<int>
maximal_planar_subgraph_finder::return_post_order() { maximal_planar_subgraph_finder::return_post_order() {
vector<int> post_order; vector<int> post_order;
@ -31,11 +40,11 @@ maximal_planar_subgraph_finder::return_post_order() {
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 void
maximal_planar_subgraph_finder::postOrderTraversal() { maximal_planar_subgraph_finder::postOrderTraversal() {
node::init_mark(); node::init_mark();
// always start with node 0
int postOrderID = 0; int postOrderID = 0;
for (int i = 0; i < _node_list.size(); ++i) { for (int i = 0; i < _node_list.size(); ++i) {
if (!_node_list[i]->is_marked()) { if (!_node_list[i]->is_marked()) {
@ -45,9 +54,7 @@ maximal_planar_subgraph_finder::postOrderTraversal() {
} }
// Determine the post-order-list by a DFS-traversal. //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();
@ -61,33 +68,31 @@ 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, prev_node); _node_list[i]->guided_DFS_visit(_post_order_list, _node_list, postOrderID, rev_post_order);
} }
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, prev_node); _node_list[i]->guided_DFS_visit(_post_order_list, _node_list, postOrderID, rev_post_order);
} }
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.
// 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::mutatedPostOrderTraversal(vector<int> post_order) { maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> post_order, int mutate_point) {
node::init_mark(); 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; vector<int> rev_post_order;
for (int i = post_order.size() - 1; i >= 0; --i) { for (int i = post_order.size() - 1; i >= 0; --i) {
rev_post_order.push_back(post_order[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; int traversal_index = 0;
// introduce random selection // introduce random selection
std::random_device rd;
std::mt19937 rng(rd());
// Define the range [0, n] // Define the range [0, n]
int n = _node_list.size() - 1; // Change 'n' to your desired upper bound int n = _node_list.size() - 1; // Change 'n' to your desired upper bound
// Create a uniform distribution for the range [0, n] // assert(mutate_point < 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;
// set loop variables // set loop variables
int start = rev_post_order[0]; int start = rev_post_order[0];
int i = start; int i = start;
// if mutate_point = 0
if (mutate_point == 0) {
// generate another point
start = distribution(rng);
}
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)))
@ -130,6 +121,7 @@ maximal_planar_subgraph_finder::mutatedPostOrderTraversal(vector<int> post_order
} }
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, traversal_index, rev_post_order, mutate_point); _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 //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::set_post_order(vector<int> post_order) {
// for (int i = 0; i < _node_list.size(); ++i) { for (int i = 0; i < _node_list.size(); ++i) {
// _node_list[i]->set_post_order_index(post_order[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
@ -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)->post_order_index() > i) break;
if (_post_order_list[i]->adj(j)->get_1st_label() == i) continue; 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))); _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) { 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 //The main part of the whole algorithm: Back-edge-traversal
void void
maximal_planar_subgraph_finder::back_edge_traversal() { maximal_planar_subgraph_finder::back_edge_traversal() {
node* i_node = 0; node* i_node = nullptr;
node* current_node = 0; 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) { for (int i = 0; i < _back_edge_list.size(); ++i) {
// current node is the lower
current_node = _back_edge_list[i].second; current_node = _back_edge_list[i].second;
i_node = _back_edge_list[i].first; 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(). //sub-function for the for-loop of back_edge_traversal().

View File

@ -4,23 +4,29 @@
#include "mps.h" #include "mps.h"
#include <ogdf/fileformats/GraphIO.h> #include <ogdf/fileformats/GraphIO.h>
#include <algorithm>
#include <vector>
#define DEBUG
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
// Finding MPS // Finding MPS
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
// programs to call from main: // functions to call from main:
int find_mps(string input_file) { int find_mps(string input_file) {
maximal_planar_subgraph_finder m; maximal_planar_subgraph_finder m;
return m.find_mps(input_file); 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; 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) { 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); 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) { vector<int> generate_guided_post_order(string input_file, vector<int> post_order) {
maximal_planar_subgraph_finder m; maximal_planar_subgraph_finder m;
return m.generate_guided_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) { 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();
return output_removed_edge_size(); return output_int_removed_edge_size();
} }
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);
set_mutate_point(INT_MAX); // essentially removed mutate_point
postOrderTraversal(); postOrderTraversal();
#ifdef DEBUG
std::cout << "standard post order traversal" << std::endl;
print_post_order();
#endif
return return_post_order(); 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) { vector<int> maximal_planar_subgraph_finder::generate_guided_post_order(string input_file, vector<int> post_order) {
read_from_gml(input_file); read_from_gml(input_file);
set_mutate_point(INT_MAX); // essentially remove mutate point
guidedPostOrderTraversal(post_order); guidedPostOrderTraversal(post_order);
#ifdef DEBUG
std::cout << "guided post order traversal" << std::endl;
print_post_order();
#endif
return return_post_order(); 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); read_from_gml(input_file);
set_mutate_point(mutate_point);
guidedPostOrderTraversal(post_order); guidedPostOrderTraversal(post_order);
#ifdef DEBUG
std::cout << "guided post order traversal" << std::endl;
print_post_order();
#endif
sort_adj_list(); sort_adj_list();
determine_edges(); determine_edges();
back_edge_traversal(); 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); _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 // create edges
for (ogdf::edge e : G.edges) { for (ogdf::edge e : G.edges) {
ogdf::node source = e->source(); 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 // 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; int sum = 0;
for (int i = 0; i < _back_edge_list.size(); ++i) { 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; return sum;
} }

View File

@ -4,8 +4,6 @@
#include "mps.h" #include "mps.h"
// #define DEBUG
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
// CONSTRUCTOR // 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;} 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) { void node::DFS_visit(vector<node*> &dfsList, int &index) {
mark(); mark();
for (int i = 0; i < _adj_list.size(); ++i) { 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); _adj_list[i]->DFS_visit(dfsList, index);
} }
} }
// head recursion: function call before returning result
set_post_order_index(index); set_post_order_index(index);
dfsList.push_back(this); dfsList.push_back(this);
++index; ++index;
} }
void node::guided_DFS_visit(vector<node *> &dfsList, void node::guided_DFS_visit(vector<node *> &dfsList,
vector<node *> &node_list, vector<node *> &node_list,
int &return_index, int &return_index,
vector<int> rev_post_order, vector<int> rev_post_order)
int prev_node)
{ {
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 // 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 // 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" // introduce mutation at mutate_point
// if the current index matches the mutate_point, then we know this is the cycle to mutate
if (traversal_index == mutate_point) { if (traversal_index == 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);
} }
// increment traversal index after checking // increment traversal index after checking
// next node will receive incremented index // 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); dfsList.push_back(this);
++return_index; ++return_index;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
// PARENT-CHILDREN // PARENT-CHILDREN
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------