diff --git a/main.c b/main.c index dc43ef2..d3ce95b 100644 --- a/main.c +++ b/main.c @@ -1,4 +1,5 @@ +#include #include #include #include @@ -46,6 +47,8 @@ bool verbose = false; bool print_with_color = false; +bool print_stats = false; + bool force_rebuild = false; bool quiet = false; @@ -56,7 +59,7 @@ static void parse_args(int argc, char* const* argv) print_with_color = isatty(1); - for (int opt; (opt = getopt(argc, argv, "pyqvc:eEo:C:B")) != -1; ) switch (opt) + for (int opt; (opt = getopt(argc, argv, "pyqmvc:eEo:C:B")) != -1; ) switch (opt) { case 'p': print_all_and_quit = true; @@ -70,6 +73,10 @@ static void parse_args(int argc, char* const* argv) quiet = true; break; + case 'm': + print_stats = true; + break; + case 'v': verbose = true; break; @@ -158,14 +165,14 @@ static void parse_args(int argc, char* const* argv) break; } - + case 'B': { force_rebuild = true; - + break; } - + default: assert(!"TODO"); break; @@ -189,7 +196,7 @@ static void parse_args(int argc, char* const* argv) enum kind { ek_unreachable, - + ek_0, ek_1, ek_W, @@ -222,7 +229,7 @@ struct expr { enum kind kind; uint16_t cond, left, right; - + int cost; } lookup[N]; @@ -254,7 +261,7 @@ static void print(uint16_t truthtable, int depth) assert(!"NOPE"); break; } - + case ek_0: { printf(print_with_color ? LITERAL_ESCAPE "0" RESET_ESCAPE : "0"); @@ -377,30 +384,30 @@ void calculate_simplifications(void) for (int i = 0; i < N; i++) { lookup[i].kind = ek_unreachable; - + lookup[i].cost = INT_MAX; } } - + // heap of truthtables; key = cost struct { uint16_t data[N]; int n; - + // truthtable -> index in 'todo' int reverse[N]; } todo; - + // init 'todo': { todo.n = 0; - + for (int i = 0; i < N; i++) { todo.reverse[i] = -1; } } - + uint16_t pop(void) { assert(todo.n > 0); @@ -465,11 +472,11 @@ void calculate_simplifications(void) index = new_index; } - + todo.data[index] = truthtable; - + todo.reverse[truthtable] = index; - + lookup[truthtable].cost = cost; } @@ -495,60 +502,60 @@ void calculate_simplifications(void) lookup[truthtable].cost = cost; } - + // create a list of the "done" truthtables struct { int headtails[N], next[N], head; - + // for debugging: #if ZDEBUG bool in[N]; #endif } done = {}; - + // init 'done': { done.head = -1; - + for (int i = 0; i < N; i++) { done.headtails[i] = -1; - + #if ZDEBUG done.in[i] = false; #endif } } - + void insert(int index) { #if ZDEBUG assert(!done.in[index]); #endif - + int head = index & 1 ? index & ~(index & -index) : index, prevhead = -1; - + while (done.headtails[head] == -1 || index < done.headtails[head]) { done.headtails[head] = index; - + prevhead = head, head = head & ~(head & -head); } - + if (done.headtails[head] < index) { if (prevhead == -1) { assert(done.headtails[head] == head); - + done.next[head] = index; } else { int tophalftail = done.headtails[prevhead - 1]; - + assert(tophalftail != -1); - + done.next[tophalftail] = index; } } @@ -556,35 +563,35 @@ void calculate_simplifications(void) { done.head = index; } - + int n = ~index & M; int tail = index & 1 ? index : index | (n & -n), prevtail = -1; - + while (done.headtails[tail] == -1 || done.headtails[tail] < index) { done.headtails[tail] = index; - + prevtail = tail, tail = tail | (n = ~tail & M, n & -n); } - + if (index < done.headtails[tail]) { if (prevtail == -1) { assert(done.headtails[tail] == tail); - + #if ZDEBUG assert(done.in[tail]); #endif - + done.next[index] = tail; } else { int bottomhalfhead = done.headtails[prevtail + 1]; - + assert(bottomhalfhead != -1); - + done.next[index] = bottomhalfhead; } } @@ -592,26 +599,26 @@ void calculate_simplifications(void) { done.next[index] = -1; } - + #if ZDEBUG done.in[index] = true; #endif } - + append(W, 0), lookup[W].kind = ek_W; append(X, 0), lookup[X].kind = ek_X; append(Y, 0), lookup[Y].kind = ek_Y; append(Z, 0), lookup[Z].kind = ek_Z; - + append(0, 1), lookup[0].kind = ek_0; append(M, 1), lookup[M].kind = ek_1; - + for (int iterations = 1; todo.n && iterations <= N; iterations++) { uint16_t truthtable = pop(); - + insert(truthtable); - + int cost = lookup[truthtable].cost; if (verbose) @@ -893,9 +900,9 @@ void get_simplifications(void) "This may take a while." "\n" ""); } - + rebuild: {}; - + if (!quiet && !verbose) { puts("re-run with '-v' to watch progress"); @@ -1439,6 +1446,61 @@ int main(int argc, char* const* argv) } } } + else if (print_stats) + { + printf("statistics:" "\n"); + + uintmax_t total_cost = 0; + int n = 0; + int max_cost = 0; + + for (int i = 0; i < N; i++) + { + int cost = lookup[i].cost; + + if (cost != INT_MAX) + { + if (max_cost < cost) + { + max_cost = cost; + } + + total_cost += cost; + + n += 1; + } + } + + if (n) + { + printf("minimum operators needed: 1" "\n"); + printf("maximum operators needed: %i" "\n", max_cost); + + double average = (double) total_cost / n; + + printf("average operators needed: %g" "\n", average); + + double working = 0.0; + + for (int i = 0; i < N; i++) + { + int cost = lookup[i].cost; + + if (cost != INT_MAX) + { + working += pow(cost - average, 2); + } + } + + double stddev = sqrt(working / (n - 1)); + + printf("standard deviation: %g" "\n", stddev); + } + else + { + puts("everything unreachable: no statistics to give"); + } + } else if (command) { uint16_t truthtable = evaluate(command); @@ -1456,28 +1518,6 @@ int main(int argc, char* const* argv) } else { - // Let's humble-brag just a little. - #if 0 - { - int max_cost = 0; - - for (int i = 0; i < N; i++) - { - int cost = lookup[i].cost; - - if (cost != INT_MAX && max_cost < cost) - { - max_cost = cost; - } - } - - puts(""); - printf("I can simplify any tree down to %i operators or less.\n", - max_cost); - puts(""); - } - #endif - if (!quiet) { puts("Use C-style syntax for boolean operators and expressions."); @@ -1486,13 +1526,13 @@ int main(int argc, char* const* argv) puts("Comparison operators are also suppported."); } - + for (char* line; (line = readline(">>> ")); free(line)) { if (!*line) continue; - + add_history(line); - + uint16_t truthtable = evaluate(line); // printf("truthtable = 0b%016b\n", truthtable); diff --git a/makefile b/makefile index 568c038..a4d67d3 100644 --- a/makefile +++ b/makefile @@ -16,7 +16,7 @@ cflags += -O3 cflags += -Wno-unused -ldflags += -lreadline +ldflags += -lreadline -lm /tmp/4-variable-simplifier: main.c $(cc) $(cppflags) $(cflags) $< -o $@ $(ldflags)