Compare commits

...

10 Commits

Author SHA1 Message Date
26dc599d88 Suppression of "6 numbers" limit. New option to choose tree type. 2021-01-28 11:01:29 +01:00
9ee0453611 Note about not use-able on Windows 2021-01-27 16:19:44 +01:00
80bd319a6d Ooops. 2021-01-27 16:00:05 +01:00
3da1891778 merged signal.c in timer.c 2021-01-27 15:26:19 +01:00
691bc6304a typo 2021-01-27 14:18:56 +01:00
38838f6e4f DEBUG flags explanation in README 2021-01-27 14:16:38 +01:00
05dbc9d261 typo 2021-01-27 14:11:38 +01:00
e28083c107 fix bad URL 2021-01-27 14:04:35 +01:00
d2b71dff2e basic README 2021-01-27 13:56:34 +01:00
c6851b22c0 added timer for maxed calculation time. 2021-01-27 13:56:03 +01:00
11 changed files with 314 additions and 89 deletions

View File

@@ -33,7 +33,7 @@ TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, pa
export PATH := .:$(PATH) export PATH := .:$(PATH)
TARGETS=lceb tree oper timer TARGETS=lceb tree oper timer
OBJS=lceb.o tree.o oper.o stack.o eval.o best.o timer.o stack.o signal.o OBJS=lceb.o tree.o oper.o stack.o eval.o best.o timer.o stack.o
INCLUDES=lceb.h INCLUDES=lceb.h
DEPS=$(INCLUDES) Makefile DEPS=$(INCLUDES) Makefile

141
README.md Normal file
View File

@@ -0,0 +1,141 @@
# lceb - a Countdown solver in C.
`lceb` will find the best solutions(s) for the
[Numbers part of the Countdown game](https://en.wikipedia.org/wiki/Countdown_(game_show)#Numbers_round)
"[_Le compte est Bon_](https://fr.wikipedia.org/wiki/Des_chiffres_et_des_lettres#Le_Compte_est_Bon)" in French).
## Requisites
`lceb` has only been tested on `GNU/Linux` systems. It should not compile at all on `Windows`. I am not sure about `MacOS`.
## Get the source
``` text
git clone https://git.bodiccea.tk/bruno/Le-Compte-est-Bon.git
```
## Build
To display more debug information, you may first enable some DEBUG flags in the `Makefile`. I usually use the `-DDEBUG`, `-DDEBUG_MAIN`, and `-DDEBUG_MEM`, as below
```makefile
CFLAGS:=$(CFLAGS) -DDEBUG # general (signal handler, etc...)
CFLAGS:=$(CFLAGS) -DDEBUG_MAIN # general information in main
#CFLAGS:=$(CFLAGS) -DDEBUG_MAINSLEEP # sleep 1 sec within main loop (SIGINTR test)
#CFLAGS:=$(CFLAGS) -DDEBUG_MAINLOOP # main loop (do not use this!)
#CFLAGS:=$(CFLAGS) -DDEBUG_TIMER # timer
#CFLAGS:=$(CFLAGS) -DDEBUG_SIGNAL # signal
#CFLAGS:=$(CFLAGS) -DDEBUG_BEST # best control
#CFLAGS:=$(CFLAGS) -DDEBUG_TREE # tree
#CFLAGS:=$(CFLAGS) -DDEBUG_OPER # oper
#CFLAGS:=$(CFLAGS) -DDEBUG_STACK # stack
#CFLAGS:=$(CFLAGS) -DDEBUG_STACK2 # stack - more details
#CFLAGS:=$(CFLAGS) -DDEBUG_EVAL # eval
#CFLAGS:=$(CFLAGS) -DDEBUG_EVAL2 # eval 2
#CFLAGS:=$(CFLAGS) -DDEBUG_EVAL3 # eval 3
CFLAGS:=$(CFLAGS) -DDEBUG_MEM # malloc
```
To build the binaries just run:
```console
$ make lceb
```
## Usage
### basic usage and output
```console
$ ./lceb 2 7 1 7 8 8
timer started...
mem: allocating operators working area (5 bytes)
new_stack: allocating 1024 stacks
get_node: allocating 1024 new nodes - total nodes=1024
target assigned (2).
SIGINT armed.
stacks : 30
ops combinations: 256
trees : 14
max evaluations : 537,600
Le compte est bon: 5 solutions with 2 ops (1st after 0.00030 secs).
1 8 7 - +
1 8 8 / +
1 7 7 / +
1 8 + 7 -
8 7 1 - -
Total time elapsed: 0.01327 secs, nodes/leaves evaluated:401,817/397,973
```
`lceb` takes at least 3 arguments: target number (the one to find), and from 2 to 6 use-able numbers.
The solutions are displayed by default in RPN notation (here `1 8 7 - +` means `(8-7)+1`).
### options
You can see the available options with `lceb -h`:
```console
$ ./lceb -h
usage: ./lceb [options] target n1 n2 [...n6]
Countdown game solver.
-1: Show only one solution (immediate stop when exact solution found
-c: Show solutions timer
-d TYPE: Solutions display type. TYPE can be:
r: RPN (default)
p: Polish
l: Lisp (binary operators)
i: Infix (full parentheses)
d: Suitable for dc(1) input
t: Tree
-i: Show intermediate solutions
-s: Do not show summary (time, nodes evaluated)
-t: Use less trees (WedderburnEtherington instead of Catalan)
-T TIMER: Will stop after TIMER 1/10th seconds
-h: This help
```
### the -t option
Using `-t` gives a large performance boost. Compare the two output below :
```console
$ ./lceb -di -c 997 4 8 25 2 5 3
timer started...
mem: allocating operators working area (6 bytes)
new_stack: allocating 1024 stacks
get_node: allocating 1024 new nodes - total nodes=1024
target assigned (997).
SIGINT armed.
stacks : 720
ops combinations: 1,024
trees : 42
max evaluations : 185,794,560
get_node: allocating 1024 new nodes - total nodes=2048
get_node: allocating 1024 new nodes - total nodes=3072
get_node: allocating 1024 new nodes - total nodes=4096
get_node: allocating 1024 new nodes - total nodes=5120
Le compte est bon: 3 solutions with 3 ops (1st after 0.00841 secs).
0.00841 secs: (((5 * 8) * 25) - 3)
0.00841 secs: (((5 * 25) * 8) - 3)
0.00841 secs: (((8 * 25) * 5) - 3)
Total time elapsed: 3.40713 secs, nodes/leaves evaluated:138,979,332/132,474,697
```
```console
$ ./lceb -di -t -c 997 4 8 25 2 5 3
timer started...
mem: allocating operators working area (6 bytes)
new_stack: allocating 1024 stacks
get_node: allocating 1024 new nodes - total nodes=1024
target assigned (997).
SIGINT armed.
stacks : 720
ops combinations: 1,024
trees : 6
max evaluations : 26,542,080
get_node: allocating 1024 new nodes - total nodes=2048
Le compte est bon: 3 solutions with 3 ops (1st after 0.15392 secs).
0.15392 secs: (((5 * 8) * 25) - 3)
0.15392 secs: (((5 * 25) * 8) - 3)
0.15393 secs: (((8 * 25) * 5) - 3)
Total time elapsed: 0.47460 secs, nodes/leaves evaluated:18,793,369/18,650,735
```
It should be noted that having general performance improvement does not mean that the first solution will be found sooner.

23
best.c
View File

@@ -12,7 +12,7 @@ static int bestops=MAXINT;
static BEST bests[1024*10]; /* TODO: should be dynamic */ static BEST bests[1024*10]; /* TODO: should be dynamic */
static int nbests=0; static int nbests=0;
extern int displaytimer; extern int displaytimer, firstonly;
int displayintermediate=0; int displayintermediate=0;
int displaytype=0; int displaytype=0;
@@ -43,8 +43,13 @@ int check_best(res, nops, node, values, ops)
if (diff < bestdiff || (diff == bestdiff && nops < bestops)) { if (diff < bestdiff || (diff == bestdiff && nops < bestops)) {
//best=res; //best=res;
// clear old bests // clear old bests
for (i=0; i<nbests; ++i) for (i=0; i<nbests; ++i) {
free_node(bests[i].root); found=free_node(bests[i].root);
# ifdef DEBUG_TREE
printf("check_best: freed %d nodes\n", found);
# endif
}
bestdiff=diff; bestdiff=diff;
bestops=nops; bestops=nops;
nbests=0; nbests=0;
@@ -120,12 +125,16 @@ void print_best(node, values, pops, depth)
void print_bests() void print_bests()
{ {
int i=0; int i=0, j=firstonly? 1: nbests;
printf("BEST SOLUTION: res=%d diff=%d ops=%d ", bests[i].res, bestdiff, bestops); if (bestdiff==0) {
printf("Le compte est bon: %d solutions with %d ops ", nbests, bestops);
} else {
printf("Found %d results with difference %d and %d ops ", nbests, bestdiff, bestops);
}
//if (displaytimer) //if (displaytimer)
printf("found after %.5f secs.", get_timer(bests[i].timer)); printf("(1st after %.5f secs).", get_timer(bests[i].timer));
putchar('\n'); putchar('\n');
for (i=0; i<nbests; ++i) { for (i=0; i<j; ++i) {
//print_best(bests[i].root, bests[i].values, bests[i].oper, 0); //print_best(bests[i].root, bests[i].values, bests[i].oper, 0);
//printf("%5d =", bests[i].res); //printf("%5d =", bests[i].res);
if (displaytimer) if (displaytimer)

4
eval.c
View File

@@ -82,7 +82,7 @@ int eval_node(node, depth, pvals, pops, ncalcs)
if (val1<val2) { if (val1<val2) {
NODE *tmp=node->left; NODE *tmp=node->left;
# ifdef DEBUG_EVAL2 # ifdef DEBUG_EVAL2
printf("eval: Sub: swapping val1=%d val2=%d\n", val1, val2); printf("eval: Div: swapping val1=%d val2=%d\n", val1, val2);
# endif # endif
node->left=node->right; node->left=node->right;
node->right=tmp; node->right=tmp;
@@ -115,7 +115,7 @@ int eval_node(node, depth, pvals, pops, ncalcs)
} }
} }
if (sigint_received) { if (sigint_received) {
print_bests(); print_results();
exit(1); exit(1);
} }

24
lceb.c
View File

@@ -20,6 +20,7 @@
static char *cmd; static char *cmd;
static int treetype=TREE_CATALAN; static int treetype=TREE_CATALAN;
static int maxmillisecs=0;
extern int displaytimer, displayintermediate, displaytype, firstonly; extern int displaytimer, displayintermediate, displaytype, firstonly;
int displaysummary=1; int displaysummary=1;
@@ -42,7 +43,7 @@ void help()
{ {
usage(); usage();
fprintf(stderr, "Countdown game solver.\n"); fprintf(stderr, "Countdown game solver.\n");
fprintf(stderr, " -1: Stops immediately when one solution is found\n"); fprintf(stderr, " -1: Show only one solution (immediate stop when exact solution found\n");
fprintf(stderr, " -c: Show solutions timer\n"); fprintf(stderr, " -c: Show solutions timer\n");
fprintf(stderr, " -d TYPE: Solutions display type. TYPE can be:\n"); fprintf(stderr, " -d TYPE: Solutions display type. TYPE can be:\n");
fprintf(stderr, " r: RPN (default)\n"); fprintf(stderr, " r: RPN (default)\n");
@@ -54,6 +55,7 @@ void help()
fprintf(stderr, " -i: Show intermediate solutions\n"); fprintf(stderr, " -i: Show intermediate solutions\n");
fprintf(stderr, " -s: Do not show summary (time, nodes evaluated)\n"); fprintf(stderr, " -s: Do not show summary (time, nodes evaluated)\n");
fprintf(stderr, " -t: Use less trees (WedderburnEtherington instead of Catalan)\n"); fprintf(stderr, " -t: Use less trees (WedderburnEtherington instead of Catalan)\n");
fprintf(stderr, " -T TIMER: Will stop after TIMER 1/10th seconds\n");
fprintf(stderr, " -h: This help\n"); fprintf(stderr, " -h: This help\n");
} }
@@ -75,7 +77,7 @@ int main(ac, av)
TREE *tree; TREE *tree;
char intarray[1024]; char intarray[1024];
char *comb; char *comb;
char *options="1thcisd:"; char *options="1thcisd:T:";
int option; int option;
# ifdef DEBUG_MAINLOOP # ifdef DEBUG_MAINLOOP
int eval; int eval;
@@ -124,6 +126,9 @@ int main(ac, av)
case 's': case 's':
displaysummary=0; displaysummary=0;
break; break;
case 'T':
maxmillisecs=atoi(optarg)*100;
break;
case 't': case 't':
treetype=TREE_WEDDERBURN; treetype=TREE_WEDDERBURN;
break; break;
@@ -143,23 +148,26 @@ int main(ac, av)
} }
setlocale(LC_ALL, ""); /* to use "%'d" in printf */ setlocale(LC_ALL, ""); /* to use "%'d" in printf */
start_timer(); start_timer();
if (maxmillisecs)
set_alarm(maxmillisecs);
target=atoi(av[optind]); target=atoi(av[optind]);
stacksize=ac-optind-1; stacksize=ac-optind-1;
nops=stacksize-1; nops=stacksize-1;
gen_combinations(nops);
ncombs=n_combs();
for (i=optind+1; i<ac; ++i) { for (i=optind+1; i<ac; ++i) {
val=atoi(av[i]); val=atoi(av[i]);
push_stack(&inputstack, val); push_stack(&inputstack, val);
} }
gen_stacks(&inputstack); gen_stacks(&inputstack);
gen_combinations(nops);
ncombs=n_combs();
if (treetype==TREE_CATALAN) { if (treetype==TREE_CATALAN) {
gen_tree(intarray, nops, 0, 0); gen_tree(intarray, nops, 0, 0, 0);
} else { } else {
gen_reduced_trees(nops); gen_tree(intarray, nops, 0, 0, 1);
//gen_reduced_trees(nops);
} }
set_target(target); set_target(target);
set_intr(); set_intr();

10
lceb.h
View File

@@ -1,12 +1,15 @@
#include <time.h> #include <time.h>
#define MAXINPUT (6) /* max numbers as input */ #define MAXINPUT (10) /* max numbers as input */
#define ALLOCSIZE (1024) /* # of elements to alloc */ #define ALLOCSIZE (1024) /* # of elements to alloc */
#define MIN(a,b) (((a)<(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b))
#define ABS(a) (((a)<0)?-(a):(a)) #define ABS(a) (((a)<0)?-(a):(a))
#define NANOSEC 1000000000.0
#define MILLISEC 1000
typedef enum { typedef enum {
Nop='N', Nop='N',
Add='+', Add='+',
@@ -71,10 +74,11 @@ extern void print_results();
/* signal.c */ /* signal.c */
extern void set_intr(); extern void set_intr();
extern int stopped(); extern int stopped();
extern void set_alarm(int ms);
/* tree.c */ /* tree.c */
extern NODE *get_node(); extern NODE *get_node();
extern void free_node(NODE *node); extern int free_node(NODE *node);
extern int compare_nodes(NODE *node1, NODE *node2, int depth); extern int compare_nodes(NODE *node1, NODE *node2, int depth);
extern void print_node(NODE *node, char side, int depth, int details); extern void print_node(NODE *node, char side, int depth, int details);
extern void print_tree(TREE *tree, int details); extern void print_tree(TREE *tree, int details);
@@ -85,7 +89,7 @@ extern NODE *dup_node(NODE *src);
extern NODE *build_tree(char *desc, int size); extern NODE *build_tree(char *desc, int size);
//extern void gen_tree(int *seq, int n, int nb1, int nb0); //extern void gen_tree(int *seq, int n, int nb1, int nb0);
extern void gen_reduced_trees(int n); extern void gen_reduced_trees(int n);
extern void gen_tree(char *seq, int n, int nb1, int nb0); extern void gen_tree(char *seq, int n, int nb1, int nb0, int reduced);
extern TREE *nth_tree(int n); extern TREE *nth_tree(int n);
extern int n_trees(); extern int n_trees();

17
oper.c
View File

@@ -4,7 +4,7 @@
#include <malloc.h> #include <malloc.h>
#include "lceb.h" #include "lceb.h"
static char *combs[1024]; /* should be dynamic */ static char **combs;
static int ncombs=0; static int ncombs=0;
void print_comb(n) void print_comb(n)
@@ -59,19 +59,23 @@ static char *combine(ops, len, n)
void gen_combinations(nops) void gen_combinations(nops)
int nops; int nops;
{ {
char *ops="+-*/"; char *ops="/-*+";
int i, n_combs; int i, n_combs;
int len_ops=strlen(ops); int len_ops=strlen(ops);
# ifdef DEBUG_OPER # ifdef DEBUG_OPER
printf("gen_combinations(%d)\n", nops); printf("gen_combinations(%d)\n", nops);
# endif # endif
n_combs=n_combine(len_ops, nops); n_combs=n_combine(len_ops, nops);
//printf("gen: n=%d\n", n_combs); # ifdef DEBUG_MEM
printf("allocating %d operators combinations\n", n_combs);
# endif
combs=malloc(sizeof (char*)*n_combs);
for (i=0; i<n_combs; ++i) { for (i=0; i<n_combs; ++i) {
combs[ncombs]=strdup(combine(ops, nops, i)); combs[ncombs]=strdup(combine(ops, nops, i));
ncombs++; ncombs++;
} }
} }
int n_combs() int n_combs()
{ {
return ncombs; return ncombs;
@@ -87,12 +91,17 @@ int main(ac, av)
int ac; int ac;
char **av; char **av;
{ {
char *ops="+-*/", *p; char *ops="/-+*", *p;
int len_ops=strlen(ops); int len_ops=strlen(ops);
int i, nops, ncombs; int i, nops, ncombs;
if (ac!=2) {
fprintf(stderr, "usage: %s nops\n", *av);
exit (1);
}
nops=atoi(*(av+1)); nops=atoi(*(av+1));
ncombs=n_combine(len_ops, nops); ncombs=n_combine(len_ops, nops);
combs=malloc(sizeof (char*)*ncombs);
printf("# operators combinations : %d\nlist = ", ncombs); printf("# operators combinations : %d\nlist = ", ncombs);
for (i=0; i<ncombs; ++i) { for (i=0; i<ncombs; ++i) {
p=combine(ops, nops, i); p=combine(ops, nops, i);

View File

@@ -1,33 +0,0 @@
#include <stdio.h>
#include <signal.h>
int sigint_received=0;
static void stopall()
{
printf("SIGINT RECEIVED: aborting eval\n");
sigint_received=1;
}
int stopped()
{
return sigint_received;
}
void set_intr()
{
struct sigaction sig;
sig.sa_handler = stopall;
sigemptyset(&sig.sa_mask);
//sigaddset(&new.sa_mask, SIGINT);
//sigaddset(&new.sa_mask, SIGALRM);
sig.sa_flags = 0;
//sigaction(SIGINT, NULL, &old);
//if (old_action.sa_handler != SIG_IGN) {
sigaction(SIGINT, &sig, NULL);
sigaction(SIGALRM, &sig, NULL);
# ifdef DEBUG
printf("SIGINT and SIGALRM armed.\n");
# endif
}

View File

@@ -52,7 +52,7 @@ STACK *new_stack(size, name, keep)
STACK *stack; STACK *stack;
int i; int i;
# ifdef DEBUG_STACK2 # ifdef DEBUG_STACK
printf("new_stack(size=%d, name=[%s] last=%d total=%d)\n", printf("new_stack(size=%d, name=[%s] last=%d total=%d)\n",
size, name, laststack, totalstacks); size, name, laststack, totalstacks);
# endif # endif
@@ -82,7 +82,7 @@ STACK *new_stack(size, name, keep)
strncpy(stack->name, name? name: "No name", sizeof(stack->name)); strncpy(stack->name, name? name: "No name", sizeof(stack->name));
//if (size) { //if (size) {
//pelt=malloc(size*sizeof(int)); //pelt=malloc(size*sizeof(int));
stack->size=MAXINPUT; stack->size=size;
//stack->stack=pelt; //stack->stack=pelt;
//if (keep) //if (keep)
// keep_stack(stack); // keep_stack(stack);
@@ -146,7 +146,7 @@ STACK *dup_stack(stack, name)
STACK *new; STACK *new;
int *dst; int *dst;
int size=stack->size, last=stack->last, i; int size=stack->size, last=stack->last, i;
//printf("DUP: totalstacks=%d\n", totalstacks);
new=new_stack(size, name, 0); new=new_stack(size, name, 0);
new->last=stack->last; new->last=stack->last;
dst=new->stack; dst=new->stack;
@@ -201,6 +201,8 @@ void gen_stacks(stack)
int n=1; int n=1;
int exists=1; int exists=1;
printf("GEN: totalstacks=%d\n", totalstacks);
# ifdef DEBUG_STACK # ifdef DEBUG_STACK
printf("generating stacks...\n"); printf("generating stacks...\n");
# endif # endif

77
timer.c
View File

@@ -1,13 +1,68 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <unistd.h>
#include <signal.h>
#define NANOSEC 1000000000.0 #include <sys/time.h>
#define MILLISEC 1000 #include <string.h>
#include "lceb.h"
int sigint_received=0;
int displaytimer=0; int displaytimer=0;
static struct timespec start; static struct timespec start;
static void stopall(signum)
int signum;
{
printf("SIGNAL %d RECEIVED: aborting eval\n", signum);
sigint_received=1;
}
int stopped()
{
return sigint_received;
}
void set_intr()
{
struct sigaction sig;
sig.sa_handler = stopall;
sigemptyset(&sig.sa_mask);
sig.sa_flags = 0;
sigaction(SIGINT, &sig, NULL);
//sigaction(SIGUSR1, &sig, NULL);
# ifdef DEBUG
printf("SIGINT armed.\n");
# endif
}
void set_alarm(ms)
int ms;
{
struct sigaction sig;
struct itimerval timer;
/* Install timer_handler as the signal handler for SIGVTALRM. */
//memset (&sa, 0, sizeof (sa));
sig.sa_handler = stopall;
sigemptyset(&sig.sa_mask);
sig.sa_flags = 0;
sigaction (SIGALRM, &sig, NULL);
timer.it_value.tv_sec = ms/1000;
timer.it_value.tv_usec = (ms%1000)*1000;
# ifdef DEBUG
printf("alarm clock set to %.2f secs.\n",
timer.it_value.tv_sec + timer.it_value.tv_usec / 1000000.);
# endif
/* ... and every 250 msec after that. */
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 0;
/* Start a virtual timer. It counts down whenever this process is executing. */
setitimer (ITIMER_REAL, &timer, NULL);
}
void start_timer() void start_timer()
{ {
printf("timer started...\n"); printf("timer started...\n");
@@ -44,18 +99,20 @@ int main(ac, av)
char **av; char **av;
{ {
int delay; int delay;
struct timespec end, tsdelay; struct timespec end;
if (ac != 2) { if (ac != 2) {
fprintf(stderr, "usage: %s msecs\n", *av); fprintf(stderr, "usage: %s msecs\n", *av);
exit (1); exit (1);
} }
delay=atoi(*(av+1)); delay=atoi(*(av+1))*10;
start_timer(); start_timer();
tsdelay.tv_sec=delay/MILLISEC; set_intr();
tsdelay.tv_nsec=delay%MILLISEC; set_alarm(delay);
printf("delay %d=%ld:%ld\n", delay, tsdelay.tv_sec, tsdelay.tv_nsec); //tsdelay.tv_sec=delay/MILLISEC;
nanosleep(&tsdelay, NULL); //tsdelay.tv_nsec=delay%MILLISEC;
//printf("delay %d=%ld:%ld\n", delay, tsdelay.tv_sec, tsdelay.tv_nsec);
sleep(5);
set_timer(&end); set_timer(&end);
printf("Time elapsed: %.5f seconds\n", get_timer(end)); printf("Time elapsed: %.5f seconds\n", get_timer(end));

64
tree.c
View File

@@ -39,19 +39,28 @@ NODE *get_node()
return ret; return ret;
} }
void free_node(node) int free_node(node)
NODE *node; NODE *node;
{ {
if (node->left) { int n=0;
free_node(node->left); if (node->type==TREE_NODE) {
# ifdef DEBUG_TREE2
printf("free tree: ");
print_node(node, 3);
# endif
n+=free_node(node->left);
node->left=NULL; node->left=NULL;
} n+=free_node(node->right);
if (node->right) {
free_node(node->right);
node->right=NULL; node->right=NULL;
# ifdef DEBUG_TREE2
printf("free tree: ");
print_node(node, 3);
# endif
} }
node->next=freenodes; node->next=freenodes;
freenodes=node; freenodes=node;
n++;
return n;
} }
int compare_nodes(node1, node2, depth) int compare_nodes(node1, node2, depth)
@@ -290,7 +299,6 @@ NODE *build_tree(desc, size)
node->type=TREE_LEAF; node->type=TREE_LEAF;
} }
} }
return root; return root;
} }
@@ -374,36 +382,55 @@ void gen_reduced_trees(n)
return; return;
} }
void gen_tree(seq, n, nb1, nb0) void gen_tree(seq, n, nb1, nb0, reduced)
char *seq; char *seq;
int n; /* number of nodes */ int n; /* number of nodes */
int nb1; /* number of "1" */ int nb1; /* number of "1" */
int nb0; /* number of "0" */ int nb0; /* number of "0" */
int reduced;
{ {
char name[80]; char name[80];
TREE *tree; TREE *tree;
NODE *node;
int i;
# ifdef DEBUG_TREE # ifdef DEBUG_TREE
printf("gen_tree(n=%d, nb1=%d, nb0=%d)\n", n, nb1, nb0); printf("gen_tree(n=%d, nb1=%d, nb0=%d)\n", n, nb1, nb0);
# endif # endif
if((nb1 + nb0) == 2*n) { /* end */ if ((nb1 + nb0) == 2*n) { /* end */
seq[2*n] = '0'; seq[2*n] = '0';
seq[2*n+1] = 0; seq[2*n+1] = 0;
ntrees++; node=build_tree(seq, 2*n+1);
sprintf(name, "Tree %d", ntrees); if (reduced) {
tree=new_tree(name); for (i=0; i<ntrees; ++i) {
tree->head=build_tree(seq, 2*n+1); if (compare_nodes(node, nth_tree(i)->head, 0)) {
# ifdef DEBUG_TREE
printf("gen_tree: skipping unused tree (%d nodes freed)\n", free_node(node));
# else
free_node(node);
# endif
node=NULL;
break;
}
}
}
if (node) {
ntrees++;
sprintf(name, "Tree %d", ntrees);
tree=new_tree(name);
tree->head=node;
}
return; return;
} }
if(nb1 >= nb0 && nb1 < n) { if (nb1 >= nb0 && nb1 < n) {
seq[nb1+nb0] = '1'; seq[nb1+nb0] = '1';
gen_tree(seq, n, nb1+1, nb0); gen_tree(seq, n, nb1+1, nb0, reduced);
} }
if(nb0 < nb1 && nb1 <=n) { if(nb0 < nb1 && nb1 <=n) {
seq[nb1+nb0] = '0'; seq[nb1+nb0] = '0';
gen_tree(seq, n, nb1, nb0+1); gen_tree(seq, n, nb1, nb0+1, reduced);
} }
} }
@@ -444,10 +471,11 @@ int main(ac, av)
n=atoi(av[2]); n=atoi(av[2]);
if (type == 0) { if (type == 0) {
printf("generating Calalan tree...\n"); printf("generating Calalan tree...\n");
gen_tree(array, n, 0, 0); gen_tree(array, n, 0, 0, 0);
} else { } else {
printf("generating Wedderburn tree...\n"); printf("generating Wedderburn tree...\n");
gen_reduced_trees(n); gen_tree(array, n, 0, 0, 1);
//gen_reduced_trees(n);
} }
print_trees(details); print_trees(details);
exit(0); exit(0);