added printing stats

This commit is contained in:
Alex Thannhauser 2025-07-17 11:20:48 -05:00
parent 3f161b9630
commit 14be1007c5
2 changed files with 111 additions and 71 deletions

180
main.c
View file

@ -1,4 +1,5 @@
#include <math.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
@ -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);

View file

@ -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)