#include #include #include #include #include #include #include #include #include #include #include #include #include "mmalloc.hpp" #include "timer.hpp" using namespace std; using boost::optional; #ifndef BIT_WIDTH #define BIT_WIDTH 16 #endif typedef typename boost::uint_t::least State; const State logState = BIT_WIDTH; const State maxState = (State) 1 << logState; bitset<8> rule(110); State update(State s) { State r(0); bitset b(s); for (unsigned i=0; i Trans; typedef array pbitset; void iterState(function f, optional msg = optional(), bool parallel = false) { PerfPrinter perfPrinter(msg); int numThreads=1; if (parallel) { numThreads = min((State) thread::hardware_concurrency(), maxState); } list tasks; for (int t=0; tjoin(), delete tasks.front(), tasks.pop_front()); } void iterTrans(int times, function f, optional msg = optional(), bool parallel = false) { PerfPrinter perfPrinter(msg); auto msg2 = [=,&msg] (int i) { return msg ? (*msg + string(" ") + to_string(times-i) + string("/") + to_string(times)) : msg; }; while (times--) { iterState(f, msg2(times), parallel); } } void init(Trans &t) { iterState([&](int s) { t[s] = update(s); }, (string) "single step transition table", true); } void findCycle(Trans &t, Trans &c, pbitset &reachable) { // compute reachability iterState([&](int s) { reachable[t[s]] = 1; }, (string) "reachability", true); // forward to t=maxState; now every state is in a cycle iterTrans(logState, [&](int s) { t[s] = t[t[s]]; }, (string) "fwd time"); // compute loop id (lowest occuring state no): go through the loop again and // record the lowest occuring state number iterState([&](int s) { c[s] = t[s]; }, (string) "init cycles", true); iterTrans(logState, [&](int s) { c[s] = min(c[s], c[t[s]]); t[s] = t[t[s]]; }, (string) "cycles"); } void cycleStat(Trans &c, pbitset &reachable) { struct Stat { State basin, len, eden, minState; Stat() : basin(0), len(0), eden(0), minState(maxState) {} }; map cyc; // How big is the basin of attraction? // How many garden of eden states does it contain? iterState([&](int s) { cyc[c[s]].basin++; if (!reachable[s]) cyc[c[s]].eden++; }, (string) "basin & eden"); // how long is the cycle, what is the actual minimal state { PerfPrinter perfPrinter((string) "cycle length"); for (auto i : cyc) { Stat &s = cyc[i.first]; State cur, start; cur = start = c[i.first]; do { s.len++; s.minState = min(s.minState, cur); cur=update(cur); } while (cur != start); }} // find duplicates cycles (only bitshifted) map> ccyc; { PerfPrinter perfPrinter((string) "find duplicate cycles"); auto canonize = [](State s) { State cs = s; for (State i=0; i>(logState-i))) & (maxState - 1))); return cs; }; for (auto i : cyc) { ccyc[canonize(i.second.minState)].insert(i.first); }} // print it for (auto i : ccyc) { Stat &s = cyc[*(i.second.begin())]; cout << bitset(i.first) << "\t" << i.second.size() << "\t" << s.len << "\t" << s.basin << "\t" << s.eden << "\t" << i.first << endl; } } void print(Trans &t) { for (auto s : t) cout << bitset(s) << endl; } void printTraj(State s, int count) { while (count--) { cout << bitset(s) << endl; s = update(s); } } int main(int argc, char **argv) { assert(argc >= 2); rule = atoi(argv[1]); if (!strcmp(argv[2], "traj")) { assert(argc == 5); printTraj(atoi(argv[3]), atoi(argv[4])); } if (!strcmp(argv[2], "cycle")) { Trans *t = mmalloc(), *c = mmalloc(); pbitset *r = mmalloc(); init(*t); findCycle(*t, *c, *r); cycleStat(*c, *r); } return 0; }