// Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2021 Noah H. and Tom H. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "robin_hood.h" namespace hash_tuple { template struct hash { size_t operator()(TT const& tt) const { return robin_hood::hash()(tt); } }; } namespace hash_tuple{ namespace { template inline void hash_combine(std::size_t& seed, T const& v) { seed ^= hash_tuple::hash()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); } } } namespace hash_tuple{ namespace { // Recursive template code derived from Matthieu M. template ::value - 1> struct HashValueImpl { static void apply(size_t& seed, Tuple const& tuple) { HashValueImpl::apply(seed, tuple); hash_combine(seed, std::get(tuple)); } }; template struct HashValueImpl { static void apply(size_t& seed, Tuple const& tuple) { hash_combine(seed, std::get<0>(tuple)); } }; } template struct hash> { size_t operator()(std::tuple const& tt) const { size_t seed = 0; HashValueImpl >::apply(seed, tt); return seed; } }; } // 0 INVASION PERCOLATION // 1 LEATH ALGORITHM #define RUN 1 // LEATH TERMINATION CONDITION // 0 TERMINATE AT NUM VERTICES // 1 TERMINATE AT DISTANCE #define TERM 1 using namespace std; typedef tuple Vertex; typedef tuple VVertex; vector vertex_neighbours(Vertex); tuple LeathRun(int,double); vector rand_bernoulli(float,int); void print_vertex(Vertex); void write_to_file(vector> &vec, string file_name) { std::ofstream f(file_name); for(vector>::const_iterator i = vec.begin(); i != vec.end(); ++i) { f << get<0>(*i) << ','<< get<1>(*i) << ','<(*i) <<','<(*i)<< '\n'; } } void write_to_file(vector vec, string file_name) { std::ofstream outFile(file_name); for (const auto &e : vec) outFile << e << "\n"; } void write_to_file(vector vec, string file_name) { std::ofstream outFile(file_name); for (const auto &e : vec) outFile << e << "\n"; } vector vertex_neighbours(Vertex v) { int x = get<0>(v); int y = get<1>(v); int z = get<2>(v); vector ret{make_tuple(x+1,y,z), make_tuple(x-1,y,z), make_tuple(x,y+1,z+x), make_tuple(x,y-1,z-x)}; return ret; } vector rand_bernoulli(double p,int n) { thread_local static random_device rd; thread_local static mt19937 rng(rd()); thread_local static bernoulli_distribution dist(p); thread_local auto gen = [](){ return dist(rng); }; vector open(n); generate(begin(open), end(open), gen); return open; } vector rand_uniform(int n) { thread_local static random_device rd; thread_local static mt19937_64 rng(rd()); thread_local static uniform_real_distribution dist(0.0,1.0); thread_local auto gen = [](){ return dist(rng); }; vector values(n); generate(begin(values), end(values), gen); return values; } void print_vertex(Vertex v) { std::cout<< "("<(v)<<","<(v)<<","<(v)<<")\n"; } int dist(int x,int y,int z) { if (x==0 && y==0 && z==0) { return 0; } if(z<=0) { y=-y; z=-z; } if (abs(y)>abs(x)) { int temp = y; y=x; x=temp; } if (x<=0) { x=-x; y=-y; } if(y>=0) { float sz = float(sqrt(z)); if(x<=sz) { return 2*(ceil(2*sz))-x-y; } else { if(x*y>=z) { return x+y; } else { return 2*ceil(float(z)/float(x))+x-y; } } } else { float sz = sqrt(float(z-x*y)); if (x<=sz) { return 2*ceil(2*sz)-x+y; } else { return 2*ceil(float(z)/float(x))+x-y; } } } tuple LeathRun(int n, double p) { Vertex initial_vertex = std::make_tuple(0,0,0); robin_hood::unordered_set > visited_vertices; queue vertex_frontier; vertex_frontier.push(initial_vertex); int visited = 1; int num_open_edges = 0; int num_closed_edges = 0; int max_dist = 0; // OR max_dist < n #if TERM == 0 while(visited(current),get<1>(current),get<2>(current))); if (visited_vertices.find(current) != visited_vertices.end()) { continue; } visited_vertices.insert(current); vector neighbours = vertex_neighbours(current); vector open = rand_bernoulli(p,4); int num_open = 0; int num = 0; for(int i=0; i < 4; i++) { if(visited_vertices.find(neighbours[i]) == visited_vertices.end()) { if(open[num] == true) { num_open += 1; vertex_frontier.push(neighbours[i]); } num+=1; } } num_open_edges += num_open; num_closed_edges += (num-num_open); visited+=1; } return make_tuple(visited,num_open_edges,num_closed_edges,max_dist); } class Compare { public: bool operator() (VVertex& v1, VVertex& v2) { return get<0>(v1)>get<0>(v2); } }; vector invasion_percolation(int n) { int max_t = ceil(4*log(float(n)/100)/log(2))+1; vector rec_vals(max_t); for (int i=0;i> visited_vertices; visited_vertices.reserve(n+1); visited_vertices.insert(initial_vertex); vector frontier_edges = vertex_neighbours(initial_vertex); int s = frontier_edges.size(); vector frontier_values = rand_uniform(s); priority_queue, Compare> frontier; for (int i=0;i visited_numbers; visited_numbers.reserve(max_t); int visited_number_running = 4; double current_marker = 1; int visited = 0; while(visited0 && visited%1000000==0) { auto it=frontier.lower_bound(make_tuple(current_marker,0,0)); frontier.erase(it,frontier.end()); }*/ visited+=1; VVertex currentE = frontier.top(); Vertex current = make_tuple(get<1>(currentE),get<2>(currentE),get<3>(currentE)); frontier.pop(); //current_marker=1; current_marker = (double)visited/(double)visited_number_running+2.347*pow(visited,-0.4); if (visited_vertices.find(current) != visited_vertices.end()) { if (visited==rec_vals[rec_index]) { rec_index+=1; visited_numbers.push_back(visited_number_running); } continue; } visited_vertices.insert(current); vector neighbours = vertex_neighbours(current); int num_n_v = 0; short ss = neighbours.size(); vector random = rand_uniform(ss); for (int i=0;i(nb),get<1>(nb),get<2>(nb)); } } } visited_number_running += num_n_v; if(visited==rec_vals[rec_index]) { rec_index+=1; visited_numbers.push_back(visited_number_running); } } return visited_numbers; } // RUN LEATH ALGORITHM // 1. n = max distance/number of steps (depending on TERM) // 2. p = percolation probability // 3. N = number of samples // 4. filename = output path #if RUN == 1 int main(int argc, char** argv) { int n = stoi(argv[1]); double p = stod(argv[2]); int N = stoi(argv[3]); string filename = argv[4]; std::cout << "n="<> file_results(num_this_file); for (int w=0; w results; results.reserve((ceil(4*log(float(n)/100)/log(2))+1)* num_runs_this_file); for (int i=0;i visited_numbers = invasion_percolation(n); copy (visited_numbers.begin(), visited_numbers.end(),back_inserter(results)); } write_to_file(results,filename+"/f"+to_string(j)); } std::cout << "done\n"; } #endif