added printing stats
This commit is contained in:
parent
3f161b9630
commit
14be1007c5
2 changed files with 111 additions and 71 deletions
180
main.c
180
main.c
|
|
@ -1,4 +1,5 @@
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
@ -46,6 +47,8 @@ bool verbose = false;
|
||||||
|
|
||||||
bool print_with_color = false;
|
bool print_with_color = false;
|
||||||
|
|
||||||
|
bool print_stats = false;
|
||||||
|
|
||||||
bool force_rebuild = false;
|
bool force_rebuild = false;
|
||||||
|
|
||||||
bool quiet = false;
|
bool quiet = false;
|
||||||
|
|
@ -56,7 +59,7 @@ static void parse_args(int argc, char* const* argv)
|
||||||
|
|
||||||
print_with_color = isatty(1);
|
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':
|
case 'p':
|
||||||
print_all_and_quit = true;
|
print_all_and_quit = true;
|
||||||
|
|
@ -70,6 +73,10 @@ static void parse_args(int argc, char* const* argv)
|
||||||
quiet = true;
|
quiet = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
print_stats = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -158,14 +165,14 @@ static void parse_args(int argc, char* const* argv)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'B':
|
case 'B':
|
||||||
{
|
{
|
||||||
force_rebuild = true;
|
force_rebuild = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(!"TODO");
|
assert(!"TODO");
|
||||||
break;
|
break;
|
||||||
|
|
@ -189,7 +196,7 @@ static void parse_args(int argc, char* const* argv)
|
||||||
|
|
||||||
enum kind {
|
enum kind {
|
||||||
ek_unreachable,
|
ek_unreachable,
|
||||||
|
|
||||||
ek_0,
|
ek_0,
|
||||||
ek_1,
|
ek_1,
|
||||||
ek_W,
|
ek_W,
|
||||||
|
|
@ -222,7 +229,7 @@ struct expr {
|
||||||
enum kind kind;
|
enum kind kind;
|
||||||
|
|
||||||
uint16_t cond, left, right;
|
uint16_t cond, left, right;
|
||||||
|
|
||||||
int cost;
|
int cost;
|
||||||
} lookup[N];
|
} lookup[N];
|
||||||
|
|
||||||
|
|
@ -254,7 +261,7 @@ static void print(uint16_t truthtable, int depth)
|
||||||
assert(!"NOPE");
|
assert(!"NOPE");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ek_0:
|
case ek_0:
|
||||||
{
|
{
|
||||||
printf(print_with_color ? LITERAL_ESCAPE "0" RESET_ESCAPE : "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++)
|
for (int i = 0; i < N; i++)
|
||||||
{
|
{
|
||||||
lookup[i].kind = ek_unreachable;
|
lookup[i].kind = ek_unreachable;
|
||||||
|
|
||||||
lookup[i].cost = INT_MAX;
|
lookup[i].cost = INT_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// heap of truthtables; key = cost
|
// heap of truthtables; key = cost
|
||||||
struct {
|
struct {
|
||||||
uint16_t data[N];
|
uint16_t data[N];
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
// truthtable -> index in 'todo'
|
// truthtable -> index in 'todo'
|
||||||
int reverse[N];
|
int reverse[N];
|
||||||
} todo;
|
} todo;
|
||||||
|
|
||||||
// init 'todo':
|
// init 'todo':
|
||||||
{
|
{
|
||||||
todo.n = 0;
|
todo.n = 0;
|
||||||
|
|
||||||
for (int i = 0; i < N; i++)
|
for (int i = 0; i < N; i++)
|
||||||
{
|
{
|
||||||
todo.reverse[i] = -1;
|
todo.reverse[i] = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t pop(void)
|
uint16_t pop(void)
|
||||||
{
|
{
|
||||||
assert(todo.n > 0);
|
assert(todo.n > 0);
|
||||||
|
|
@ -465,11 +472,11 @@ void calculate_simplifications(void)
|
||||||
|
|
||||||
index = new_index;
|
index = new_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
todo.data[index] = truthtable;
|
todo.data[index] = truthtable;
|
||||||
|
|
||||||
todo.reverse[truthtable] = index;
|
todo.reverse[truthtable] = index;
|
||||||
|
|
||||||
lookup[truthtable].cost = cost;
|
lookup[truthtable].cost = cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -495,60 +502,60 @@ void calculate_simplifications(void)
|
||||||
|
|
||||||
lookup[truthtable].cost = cost;
|
lookup[truthtable].cost = cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a list of the "done" truthtables
|
// create a list of the "done" truthtables
|
||||||
struct {
|
struct {
|
||||||
int headtails[N], next[N], head;
|
int headtails[N], next[N], head;
|
||||||
|
|
||||||
// for debugging:
|
// for debugging:
|
||||||
#if ZDEBUG
|
#if ZDEBUG
|
||||||
bool in[N];
|
bool in[N];
|
||||||
#endif
|
#endif
|
||||||
} done = {};
|
} done = {};
|
||||||
|
|
||||||
// init 'done':
|
// init 'done':
|
||||||
{
|
{
|
||||||
done.head = -1;
|
done.head = -1;
|
||||||
|
|
||||||
for (int i = 0; i < N; i++)
|
for (int i = 0; i < N; i++)
|
||||||
{
|
{
|
||||||
done.headtails[i] = -1;
|
done.headtails[i] = -1;
|
||||||
|
|
||||||
#if ZDEBUG
|
#if ZDEBUG
|
||||||
done.in[i] = false;
|
done.in[i] = false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(int index)
|
void insert(int index)
|
||||||
{
|
{
|
||||||
#if ZDEBUG
|
#if ZDEBUG
|
||||||
assert(!done.in[index]);
|
assert(!done.in[index]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int head = index & 1 ? index & ~(index & -index) : index, prevhead = -1;
|
int head = index & 1 ? index & ~(index & -index) : index, prevhead = -1;
|
||||||
|
|
||||||
while (done.headtails[head] == -1 || index < done.headtails[head])
|
while (done.headtails[head] == -1 || index < done.headtails[head])
|
||||||
{
|
{
|
||||||
done.headtails[head] = index;
|
done.headtails[head] = index;
|
||||||
|
|
||||||
prevhead = head, head = head & ~(head & -head);
|
prevhead = head, head = head & ~(head & -head);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (done.headtails[head] < index)
|
if (done.headtails[head] < index)
|
||||||
{
|
{
|
||||||
if (prevhead == -1)
|
if (prevhead == -1)
|
||||||
{
|
{
|
||||||
assert(done.headtails[head] == head);
|
assert(done.headtails[head] == head);
|
||||||
|
|
||||||
done.next[head] = index;
|
done.next[head] = index;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int tophalftail = done.headtails[prevhead - 1];
|
int tophalftail = done.headtails[prevhead - 1];
|
||||||
|
|
||||||
assert(tophalftail != -1);
|
assert(tophalftail != -1);
|
||||||
|
|
||||||
done.next[tophalftail] = index;
|
done.next[tophalftail] = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -556,35 +563,35 @@ void calculate_simplifications(void)
|
||||||
{
|
{
|
||||||
done.head = index;
|
done.head = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
int n = ~index & M;
|
int n = ~index & M;
|
||||||
int tail = index & 1 ? index : index | (n & -n), prevtail = -1;
|
int tail = index & 1 ? index : index | (n & -n), prevtail = -1;
|
||||||
|
|
||||||
while (done.headtails[tail] == -1 || done.headtails[tail] < index)
|
while (done.headtails[tail] == -1 || done.headtails[tail] < index)
|
||||||
{
|
{
|
||||||
done.headtails[tail] = index;
|
done.headtails[tail] = index;
|
||||||
|
|
||||||
prevtail = tail, tail = tail | (n = ~tail & M, n & -n);
|
prevtail = tail, tail = tail | (n = ~tail & M, n & -n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < done.headtails[tail])
|
if (index < done.headtails[tail])
|
||||||
{
|
{
|
||||||
if (prevtail == -1)
|
if (prevtail == -1)
|
||||||
{
|
{
|
||||||
assert(done.headtails[tail] == tail);
|
assert(done.headtails[tail] == tail);
|
||||||
|
|
||||||
#if ZDEBUG
|
#if ZDEBUG
|
||||||
assert(done.in[tail]);
|
assert(done.in[tail]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
done.next[index] = tail;
|
done.next[index] = tail;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int bottomhalfhead = done.headtails[prevtail + 1];
|
int bottomhalfhead = done.headtails[prevtail + 1];
|
||||||
|
|
||||||
assert(bottomhalfhead != -1);
|
assert(bottomhalfhead != -1);
|
||||||
|
|
||||||
done.next[index] = bottomhalfhead;
|
done.next[index] = bottomhalfhead;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -592,26 +599,26 @@ void calculate_simplifications(void)
|
||||||
{
|
{
|
||||||
done.next[index] = -1;
|
done.next[index] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ZDEBUG
|
#if ZDEBUG
|
||||||
done.in[index] = true;
|
done.in[index] = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
append(W, 0), lookup[W].kind = ek_W;
|
append(W, 0), lookup[W].kind = ek_W;
|
||||||
append(X, 0), lookup[X].kind = ek_X;
|
append(X, 0), lookup[X].kind = ek_X;
|
||||||
append(Y, 0), lookup[Y].kind = ek_Y;
|
append(Y, 0), lookup[Y].kind = ek_Y;
|
||||||
append(Z, 0), lookup[Z].kind = ek_Z;
|
append(Z, 0), lookup[Z].kind = ek_Z;
|
||||||
|
|
||||||
append(0, 1), lookup[0].kind = ek_0;
|
append(0, 1), lookup[0].kind = ek_0;
|
||||||
append(M, 1), lookup[M].kind = ek_1;
|
append(M, 1), lookup[M].kind = ek_1;
|
||||||
|
|
||||||
for (int iterations = 1; todo.n && iterations <= N; iterations++)
|
for (int iterations = 1; todo.n && iterations <= N; iterations++)
|
||||||
{
|
{
|
||||||
uint16_t truthtable = pop();
|
uint16_t truthtable = pop();
|
||||||
|
|
||||||
insert(truthtable);
|
insert(truthtable);
|
||||||
|
|
||||||
int cost = lookup[truthtable].cost;
|
int cost = lookup[truthtable].cost;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
|
|
@ -893,9 +900,9 @@ void get_simplifications(void)
|
||||||
"This may take a while." "\n"
|
"This may take a while." "\n"
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuild: {};
|
rebuild: {};
|
||||||
|
|
||||||
if (!quiet && !verbose)
|
if (!quiet && !verbose)
|
||||||
{
|
{
|
||||||
puts("re-run with '-v' to watch progress");
|
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)
|
else if (command)
|
||||||
{
|
{
|
||||||
uint16_t truthtable = evaluate(command);
|
uint16_t truthtable = evaluate(command);
|
||||||
|
|
@ -1456,28 +1518,6 @@ int main(int argc, char* const* argv)
|
||||||
}
|
}
|
||||||
else
|
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)
|
if (!quiet)
|
||||||
{
|
{
|
||||||
puts("Use C-style syntax for boolean operators and expressions.");
|
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.");
|
puts("Comparison operators are also suppported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (char* line; (line = readline(">>> ")); free(line))
|
for (char* line; (line = readline(">>> ")); free(line))
|
||||||
{
|
{
|
||||||
if (!*line) continue;
|
if (!*line) continue;
|
||||||
|
|
||||||
add_history(line);
|
add_history(line);
|
||||||
|
|
||||||
uint16_t truthtable = evaluate(line);
|
uint16_t truthtable = evaluate(line);
|
||||||
|
|
||||||
// printf("truthtable = 0b%016b\n", truthtable);
|
// printf("truthtable = 0b%016b\n", truthtable);
|
||||||
|
|
|
||||||
2
makefile
2
makefile
|
|
@ -16,7 +16,7 @@ cflags += -O3
|
||||||
|
|
||||||
cflags += -Wno-unused
|
cflags += -Wno-unused
|
||||||
|
|
||||||
ldflags += -lreadline
|
ldflags += -lreadline -lm
|
||||||
|
|
||||||
/tmp/4-variable-simplifier: main.c
|
/tmp/4-variable-simplifier: main.c
|
||||||
$(cc) $(cppflags) $(cflags) $< -o $@ $(ldflags)
|
$(cc) $(cppflags) $(cflags) $< -o $@ $(ldflags)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue