stage2: Extensively comment the source code
[gaul-genprog.git] / stage2.c
blobb5b4f4ae2fa349b500e81679c529d426636636bc
1 /* GAUL Genetic Programming Tutorial - stage 2 */
3 /* Evolve a simple four function calculator from 2 text files. Input text file
4 * is a list of simple math questions (1+1=, 4-1=, 3*3=, 12/2=). output text
5 * file contains correct answers (2, 3, 9, 6). Each member of the population
6 * would need to input the text file and produce its own output file. The
7 * fitness function would need to compare each population output file the
8 * correct math output file. Input file will only have 2 arguments per question
9 * and only the four basic functions (+,-,*,/). */
11 /* Stage2: Loop, parser code non-evolved, chromosome is genetic program taking (number, character, number) as its input */
13 #include "gaul.h"
16 /* Number of equations in the file. Just to make the code simpler. */
17 #define EQNO 100
19 /* Reference results. */
20 static int refresults[EQNO];
22 /* Loads reference results. */
23 static void
24 load_reference_results(void)
26 /* Open file. */
27 FILE *f = fopen("eq.out", "r");
28 if (!f) {
29 perror("eq.out");
30 exit(EXIT_FAILURE);
33 int eq = 0;
35 /* Read one line at a time. */
36 char line[256];
37 while (fgets(line, sizeof(line), f)) {
38 /* Convert line to number and store it
39 * in the refresults[] array. */
40 refresults[eq++] = atoi(line);
43 /* Close file. */
44 fclose(f);
48 /* Chromosome is a program in the form of evaluation tree. Nodes
49 * of the tree are functions, with children (in-order) being their
50 * parameters; leaves may be integer constants or reference program
51 * variables. The program is evaluated left to right, recursively
52 * from the root downwards.
54 * Functions: ADD, SUB, MUL, DIV, IFEQ
56 * Variables: X (first operand), Y (second operand) and Z
57 * (operator letter - can be also thought of as its ASCII value). */
60 /*** PROGRAM TREE STRUCTURE DEFINITIONS */
63 /* Common header for all nodes. This is contained by actual node
64 * structures specific to each type of function. */
65 struct program_node {
66 enum program_node_type {
67 PNT_FUNCTION,
68 PNT_CONSTANT,
69 PNT_VARIABLE,
70 PNT__MAX
71 } type;
72 struct program_node *child; /* Children in tree. */
73 struct program_node *sibling; /* Sibling in tree. */
76 struct program_function; /* See below for function classes. */
78 struct program_node_function {
79 struct program_node pn;
80 const struct program_function *funct;
83 struct program_node_constant {
84 struct program_node pn;
85 int value;
88 struct program_node_variable {
89 struct program_node pn;
90 char name; // X, Y or Z
94 /*** PROGRAM BUILTIN FUNCTIONS DEFINITIONS */
97 /* The way the program tree itself is called. This describes
98 * the parameters of the program, i.e. the values of the variables. */
99 struct program_call {
100 int X, Y, Z;
104 /* Available functions are described by the program_function structure. */
105 typedef int (*program_function_eval)(struct program_call *pc, int params[]);
106 struct program_function {
107 char *name; /* String description for printing. */
108 int n_params; /* Number of parameters. */
109 program_function_eval eval; /* Evaluation function - takes parameters and produces value. */
112 /* ADD function */
113 static int
114 pf_add_eval(struct program_call *pc, int params[])
116 return params[0] + params[1];
118 static const struct program_function pf_add = {
119 .name = "ADD",
120 .n_params = 2,
121 .eval = pf_add_eval,
124 /* SUB function */
125 static int
126 pf_sub_eval(struct program_call *pc, int params[])
128 return params[0] - params[1];
130 static const struct program_function pf_sub = {
131 .name = "SUB",
132 .n_params = 2,
133 .eval = pf_sub_eval,
136 /* MUL function */
137 static int
138 pf_mul_eval(struct program_call *pc, int params[])
140 return params[0] * params[1];
142 static const struct program_function pf_mul = {
143 .name = "MUL",
144 .n_params = 2,
145 .eval = pf_mul_eval,
148 /* DIV function */
149 static int
150 pf_div_eval(struct program_call *pc, int params[])
152 if (params[1] == 0)
153 return -100000; /* A normally impossible value. */
154 return params[0] / params[1];
156 static const struct program_function pf_div = {
157 .name = "DIV",
158 .n_params = 2,
159 .eval = pf_div_eval,
162 /* IFEQ function */
163 /* The parameter order here is a bit unusual:
164 * IFEQ(A, B, C, D) means if (C == D) then B else A */
165 static int
166 pf_ifeq_eval(struct program_call *pc, int params[])
168 /* The parameters are in this order so that the first
169 * two parameters (and particularly the != case) have
170 * highest chance of having the largest subtrees
171 * (when not using the hinting logic). */
172 return params[2] == params[3] ? params[1] : params[0];
174 static const struct program_function pf_ifeq = {
175 .name = "IFEQ",
176 .n_params = 4,
177 .eval = pf_ifeq_eval,
180 /* List of all program functions, for randomly picking one. */
181 static const struct program_function *program_functions[] = {
182 &pf_add, &pf_sub, &pf_mul, &pf_div, &pf_ifeq
184 static const int program_functions_n = sizeof(program_functions) / sizeof(program_functions[0]);
187 /*** PROGRAM EVALUATION ROUTINES */
190 static int program_node_eval(struct program_call *pc, struct program_node *node);
192 static int
193 program_node_function_eval(struct program_call *pc, struct program_node_function *node)
195 /* Visit all children in order and evaluate them, storing the values
196 * in a params[] array. */
197 int params[node->funct->n_params];
198 int i = 0;
199 for (struct program_node *param_node = node->pn.child; param_node; param_node = param_node->sibling) {
200 assert(i < node->funct->n_params);
201 params[i] = program_node_eval(pc, param_node);
202 i++;
204 assert(i == node->funct->n_params);
206 /* Then, evaluate the function itself with the given parameters. */
207 return node->funct->eval(pc, params);
210 static int
211 program_node_constant_eval(struct program_call *pc, struct program_node_constant *node)
213 return node->value;
216 static int
217 program_node_variable_eval(struct program_call *pc, struct program_node_variable *node)
219 switch (node->name) {
220 case 'X': return pc->X;
221 case 'Y': return pc->Y;
222 case 'Z': return pc->Z;
223 default: return -100000; /* A normally impossible value. */
227 /* Evaluate a given program, returning the resulting return
228 * value of the function at the root of the tree. */
229 static int
230 program_node_eval(struct program_call *pc, struct program_node *node)
232 switch (node->type) {
233 case PNT_FUNCTION:
234 return program_node_function_eval(pc, (struct program_node_function *) node);
235 case PNT_CONSTANT:
236 return program_node_constant_eval(pc, (struct program_node_constant *) node);
237 case PNT_VARIABLE:
238 return program_node_variable_eval(pc, (struct program_node_variable *) node);
240 return -100000;
244 /*** PROGRAM PRETTY-PRINTING ROUTINES */
247 static void program_node_print(FILE *f, struct program_node *node);
249 static void
250 program_node_function_print(FILE *f, struct program_node_function *node)
252 fprintf(f, "%s(", node->funct->name);
253 /* Visit all children in order and print them. */
254 for (struct program_node *param_node = node->pn.child; param_node; param_node = param_node->sibling) {
255 program_node_print(f, param_node);
256 if (param_node->sibling)
257 fputs(", ", f);
259 fputs(")", f);
262 static void
263 program_node_constant_print(FILE *f, struct program_node_constant *node)
265 fprintf(f, "%d:%c", node->value, node->value);
268 static void
269 program_node_variable_print(FILE *f, struct program_node_variable *node)
271 fprintf(f, "%c", node->name);
274 /* Print a given program in human-readable format. */
275 static void
276 program_node_print(FILE *f, struct program_node *node)
278 switch (node->type) {
279 case PNT_FUNCTION:
280 program_node_function_print(f, (struct program_node_function *) node);
281 break;
282 case PNT_CONSTANT:
283 program_node_constant_print(f, (struct program_node_constant *) node);
284 break;
285 case PNT_VARIABLE:
286 program_node_variable_print(f, (struct program_node_variable *) node);
287 break;
292 /*** PROGRAM NODE COPY ROUTINES */
295 static struct program_node *program_node_copy(struct program_node *node);
297 static struct program_node *
298 program_node_function_copy(struct program_node_function *node)
300 struct program_node_function *newnode = malloc(sizeof(*newnode));
301 newnode->pn.type = PNT_FUNCTION;
302 newnode->pn.child = newnode->pn.sibling = NULL;
303 newnode->funct = node->funct;
305 struct program_node *lastchild = NULL;
306 for (struct program_node *param_node = node->pn.child; param_node; param_node = param_node->sibling) {
307 struct program_node *child = program_node_copy(param_node);
308 /* Link the children to the program tree. */
309 if (!lastchild)
310 newnode->pn.child = child;
311 else
312 lastchild->sibling = child;
313 lastchild = child;
316 return (struct program_node *) newnode;
319 static struct program_node *
320 program_node_constant_copy(struct program_node_constant *node)
322 struct program_node_constant *newnode = malloc(sizeof(*newnode));
323 newnode->pn.type = PNT_CONSTANT;
324 newnode->pn.child = newnode->pn.sibling = NULL;
325 newnode->value = node->value;
326 return (struct program_node *) newnode;
329 static struct program_node *
330 program_node_variable_copy(struct program_node_variable *node)
332 struct program_node_variable *newnode = malloc(sizeof(*newnode));
333 newnode->pn.type = PNT_VARIABLE;
334 newnode->pn.child = newnode->pn.sibling = NULL;
335 newnode->name = node->name;
336 return (struct program_node *) newnode;
339 /* Produce a recursive memory copy of the given node and all its children. */
340 static struct program_node *
341 program_node_copy(struct program_node *node)
343 switch (node->type) {
344 case PNT_FUNCTION:
345 return program_node_function_copy((struct program_node_function *) node);
346 case PNT_CONSTANT:
347 return program_node_constant_copy((struct program_node_constant *) node);
348 case PNT_VARIABLE:
349 return program_node_variable_copy((struct program_node_variable *) node);
351 return NULL;
355 /*** PROGRAM LIFETIME ROUTINES */
358 /* Generate a random node, including possibly a sub-tree. The energy
359 * represents desired size of the sub-tree (approximately; it can be
360 * slightly more). */
361 static struct program_node *
362 program_node_random(int energy, struct program_node *parent)
364 /* This function includes some hints so that the solution is pushed
365 * towards the canonical form of something like:
367 * IFEQ(IFEQ(IFEQ(ADD(Y, X), DIV(X, Y), 47:/, Z), SUB(X, Y), Z, 45:-), MUL(X, Y), Z, 42:*)
369 * To enable and disable hints, just flip 0 and 1. Disabling hint
370 * will usually need to be accompanied by significantly raising
371 * population size and/or the number of generations. */
373 /* Prepare information used by the hinting logic. */
375 struct program_node_function *parentf = (struct program_node_function *) parent;
376 bool allow_constant = true, variable_xy = true;
377 if (parent) {
378 parentf = (struct program_node_function *) parent;
379 #if 1 /* Hint importance: low (small improvement) */
380 /* XXX: Hinting - allow constants only as parameters of IF. */
381 allow_constant = (parentf->funct == &pf_ifeq);
382 #endif
383 variable_xy = (parentf->funct != &pf_ifeq);
386 /* If energy is 1, this node will be a "simple" node:
387 * a constant or a variable, not function. */
389 if (energy == 1) {
390 if (allow_constant && random_boolean()) {
391 /* Generate a constant node. */
392 struct program_node_constant *node = malloc(sizeof(*node));
393 node->pn.type = PNT_CONSTANT;
394 node->pn.child = node->pn.sibling = NULL;
395 #if 1 /* Hint importance: high (large population and many generations will still find solution) */
396 /* XXX: Hinting - only constants that correspond to arithmetic operator characters. */
397 node->value = "+-*/"[random_int(4)];
398 #else
399 node->value = random_int(256);
400 #endif
401 return (struct program_node *) node;
403 } else {
404 /* Generate a variable node. */
405 struct program_node_variable *node = malloc(sizeof(*node));
406 node->pn.type = PNT_VARIABLE;
407 node->pn.child = node->pn.sibling = NULL;
408 #if 1 /* Hint importance: high (large population and many generations will still find solution) */
409 /* XXX: Hinting - X, Y anywhere but IFEQ, Z forced there. */
410 if (variable_xy) {
411 node->name = "XY"[random_int(2)];
412 } else {
413 node->name = 'Z';
415 #else
416 node->name = "XYZ"[random_int(3)];
417 #endif
418 return (struct program_node *) node;
422 /* Generate a function node. */
424 /* Pick a random function. */
425 const struct program_function *f = program_functions[random_int(program_functions_n)];
427 /* Create the function node. */
428 struct program_node_function *node = malloc(sizeof(*node));
429 node->pn.type = PNT_FUNCTION;
430 node->pn.child = node->pn.sibling = NULL;
431 node->funct = f;
433 /* Decrease energy by function node. */
434 energy--;
435 if (energy < f->n_params)
436 energy = f->n_params;
438 /* Create parameter children. */
440 #if 1 /* Hint importance: very high (very long time needed to approach correct result) */
441 if (node->funct == &pf_ifeq) {
442 /* XXX: Hinting: IFEQ children template */
443 int children_energy = energy - (f->n_params - 1 - 2);
444 int child_energy = random_int(children_energy);
445 /* "ELSE" branch - multiple nodes */
446 node->pn.child = program_node_random(1 + child_energy, (struct program_node *) node);
447 /* "THEN" branch - multiple nodes */
448 node->pn.child->sibling = program_node_random(1 + children_energy - child_energy, (struct program_node *) node);
449 /* "X in X == Y" branch - simple node */
450 node->pn.child->sibling->sibling = program_node_random(1, (struct program_node *) node);
451 /* "Y in X == Y" branch - simple node */
452 node->pn.child->sibling->sibling->sibling = program_node_random(1, (struct program_node *) node);
453 } else {
454 /* XXX: Hinting: Simple function template - simple nodes as children only */
455 node->pn.child = program_node_random(1, (struct program_node *) node);
456 node->pn.child->sibling = program_node_random(1, (struct program_node *) node);
459 #else
460 /* Generic tree-growing code without templates. */
461 struct program_node *lastchild = NULL;
462 for (int i = 0; i < f->n_params; i++) {
463 /* Remaining energy is randomly distributed between children. */
464 int child_energy = 1 + random_int(energy - (f->n_params - 1 - i));
465 /* Recursively create randomized children. */
466 struct program_node *child = program_node_random(child_energy, (struct program_node *) node);
467 /* Link the children to the program tree. */
468 if (!lastchild)
469 node->pn.child = child;
470 else
471 lastchild->sibling = child;
472 lastchild = child;
474 #endif
476 return (struct program_node *) node;
480 /* Recursively release memory occupied by this node and all its children. */
481 static void
482 program_node_done(struct program_node *node)
484 struct program_node *cnode = node->child;
485 while (cnode) {
486 /* cnode_sibling is temporary variable for storing the
487 * pointer of the next sibling. This is necessary since
488 * the moment we want to move on to the sibling, we cannot
489 * look at the pointer in the current node anymore since
490 * we have already free()d the node. */
491 struct program_node *cnode_sibling = cnode->sibling;
492 program_node_done(cnode);
493 cnode = cnode_sibling;
496 free(node);
500 /*** PROGRAM TREE WALKING (OTHER) */
503 /* Measure size of a program sub-tree in term of number of nodes. */
504 static int
505 program_node_subtree_size(struct program_node *node)
507 if (!node)
508 return 0;
510 int size = 1; /* Self. */
512 for (struct program_node *param_node = node->child; param_node; param_node = param_node->sibling) {
513 if (param_node->child)
514 size += program_node_subtree_size(param_node);
515 else
516 size++;
519 return size;
522 /* Store pointers to all nodes in the given subtree (and their corresponding
523 * fathers and left (previous) siblings) in a flat array nodes[]. */
524 static int
525 program_node_subtree_list(struct program_node *node, struct program_node *nodes[], struct program_node *fathers[], struct program_node *psiblings[])
527 int i = 0;
529 struct program_node *prev_node = NULL;
530 for (struct program_node *param_node = node->child; param_node; prev_node = param_node, param_node = param_node->sibling) {
531 nodes[i] = param_node;
532 fathers[i] = node;
533 psiblings[i] = prev_node;
534 i++;
535 if (param_node->child) {
536 i += program_node_subtree_list(param_node, &nodes[i], &fathers[i], &psiblings[i]);
539 return i;
542 /* Randomly pick a node in the program tree rooted at @node. Also give
543 * (in *father and *psibling) pointers to its father and left (previous)
544 * sibling. */
545 static struct program_node *
546 program_node_subtree_random_pick(struct program_node *node, struct program_node **father, struct program_node **psibling)
548 int size = program_node_subtree_size(node);
550 /* Flat array to collect all nodes. */
551 struct program_node *nodes[size], *fathers[size], *psiblings[size];
552 nodes[0] = node; fathers[0] = NULL; psiblings[0] = NULL;
554 /* Collect all the nodes into the flat array. */
555 int s = program_node_subtree_list(node, &nodes[1], &fathers[1], &psiblings[1]) + 1;
556 assert(s == size);
558 /* Randomly pick an element of the array. */
559 int i = random_int(size);
560 // printf("pick %d/%d\n", i, size);
561 *father = fathers[i];
562 *psibling = psiblings[i];
563 return nodes[i];
567 /*** CHROMOSOME MANAGEMENT */
570 /* How is the program represented from GAUL view? The GAUL operates
571 * in terms of entities (members of the population) which are composed
572 * from chromosomes.
574 * We use only a single chromosome per entity, i.e. chromosomes are
575 * 1:1 with population members for us. The chromosome is then a pointer
576 * to the root node of the program tree corresponding to the entity. */
579 /* A service routine for creating a chromosome (i.e. a single member
580 * of the population. */
581 boolean
582 program_chromosome_constructor(population *pop, entity *embryo)
584 if (!pop) die("Null pointer to population structure passed.");
585 if (!embryo) die("Null pointer to entity structure passed.");
587 if (embryo->chromosome!=NULL)
588 die("This entity already contains chromosomes.");
590 embryo->chromosome = s_malloc(sizeof(struct program_node *));
591 /* Initialize the chromosome with no program. */
592 embryo->chromosome[0] = NULL;
594 return TRUE;
597 /* A service routine for releasing a chromosome (i.e. a single member
598 * of the population. */
599 void
600 program_chromosome_destructor(population *pop, entity *corpse)
602 if (!pop) die("Null pointer to population structure passed.");
603 if (!corpse) die("Null pointer to entity structure passed.");
605 if (corpse->chromosome==NULL)
606 die("This entity already contains no chromosomes.");
608 program_node_done(corpse->chromosome[0]);
609 s_free(corpse->chromosome);
610 corpse->chromosome = NULL;
613 /* A service routine for replicating a chromosome (i.e. a single member
614 * of the population. */
615 void
616 program_chromosome_replicate(const population *pop, entity *src, entity *dest, const int chromosomeid)
618 if (!pop) die("Null pointer to population structure passed.");
619 if (!src || !dest) die("Null pointer to entity structure passed.");
620 if (!src->chromosome || !dest->chromosome) die("Entity has no chromosomes.");
621 if (!src->chromosome[0]) die("Source entity has empty chromosomes.");
622 if (dest->chromosome[0]) die("Target entity has empty chromosomes.");
623 if (chromosomeid != 0) die("Invalid chromosome index passed.");
625 dest->chromosome[0] = program_node_copy((struct program_node *) src->chromosome[0]);
629 /*** GENETIC OPERATORS */
632 /* Initializes a single entity randomly. */
633 static boolean
634 seed_entity(population *pop, entity *entity)
636 entity->chromosome[0] = program_node_random(4 * 4 + 1, NULL);
637 return TRUE;
641 /* Mutates an entity. */
642 static void
643 mutate_entity(population *pop, entity *father, entity *son)
645 // printf("%p (%p) <- %p (%p)\n", son, son->chromosome[0], father, father->chromosome[0]);
647 /* A mutated entity starts off as a 1:1 copy of the original entity. */
648 son->chromosome[0] = program_node_copy((struct program_node *) father->chromosome[0]);
650 /* Randomly pick a node. */
651 struct program_node *mnode_father, *mnode_psibling;
652 struct program_node *mnode = program_node_subtree_random_pick(son->chromosome[0], &mnode_father, &mnode_psibling);
654 /* Mutation means that this node (including a subtree it
655 * potentially holds gets replaced by a random new node. */
657 /* With 50% probability, the new node is a simple node
658 * with energy 1 (variable or constant). Otherwise, it is
659 * assigned a random energy in the range of 2 to 10 and
660 * therefore becomes a function node holding a small subtree
661 * of its own. */
662 int energy = random_boolean() ? 1 : 8.0 * random_double_1() + 2;
664 struct program_node *newnode = program_node_random(energy, mnode_father);
666 /* Link up the new node in stead of the original node. */
667 if (mnode_psibling)
668 mnode_psibling->sibling = newnode;
669 else if (mnode_father)
670 mnode_father->child = newnode;
671 else
672 son->chromosome[0] = newnode;
673 newnode->sibling = mnode->sibling;
675 /* Release the original node. */
676 program_node_done(mnode);
680 /* Makes a crossover between two entities. */
681 static void
682 crossover_entity(population *pop, entity *mother, entity *father, entity *daughter, entity *son)
684 // printf("%p (%p) xx %p (%p) => %p (%p) xx %p (%p)\n", father, father->chromosome[0], mother, mother->chromosome[0], son, son->chromosome[0], daughter, daughter->chromosome[0]);
686 /* The new entities start off as copies of the original entities. */
687 daughter->chromosome[0] = program_node_copy((struct program_node *) mother->chromosome[0]);
688 son->chromosome[0] = program_node_copy((struct program_node *) father->chromosome[0]);
690 /* Randomly pick nodes in the new entities to be swapped together
691 * with the subtrees they hold. */
693 struct program_node *cdnode_father, *cdnode_psibling;
694 struct program_node *cdnode = program_node_subtree_random_pick(daughter->chromosome[0], &cdnode_father, &cdnode_psibling);
695 struct program_node *cdnode_sibling = cdnode->sibling;
697 struct program_node *csnode_father, *csnode_psibling;
698 struct program_node *csnode = program_node_subtree_random_pick(son->chromosome[0], &csnode_father, &csnode_psibling);
699 struct program_node *csnode_sibling = csnode->sibling;
701 /* Swap cdnode and csnode in their respective trees. */
703 if (cdnode_psibling)
704 cdnode_psibling->sibling = csnode;
705 else if (cdnode_father)
706 cdnode_father->child = csnode;
707 else
708 daughter->chromosome[0] = csnode;
709 csnode->sibling = cdnode_sibling;
711 if (csnode_psibling)
712 csnode_psibling->sibling = cdnode;
713 else if (csnode_father)
714 csnode_father->child = cdnode;
715 else
716 son->chromosome[0] = cdnode;
717 cdnode->sibling = csnode_sibling;
720 /* Execute a single entity, interpreting its chromosome supplying it with
721 * equations from a prepared text file. */
722 /* The funciton saves the results to a number array. */
723 static void
724 execute_entity(entity *entity, int results[EQNO])
726 /* Open file. */
727 FILE *f = fopen("eq.in", "r");
728 if (!f) {
729 perror("eq.in");
730 exit(EXIT_FAILURE);
733 int eq = 0;
735 /* Read one line at a time. */
736 char line[256];
737 while (fgets(line, sizeof(line), f)) {
738 /* Parse line. We do not handle errors here. */
739 int arg1, arg2;
740 char op;
741 sscanf(line, "%d%c%d=", &arg1, &op, &arg2);
743 struct program_call pc = { .X = arg1, .Y = arg2, .Z = op };
744 int result = program_node_eval(&pc, entity->chromosome[0]);
746 // printf("X = %d, Y = %d, Z = %d:%c ", pc.X, pc.Y, pc.Z, pc.Z);
747 // program_node_print(stdout, entity->chromosome[0]);
748 // printf("\n -> %d\n", result);
750 /* Store result. */
751 results[eq++] = result;
754 /* Close file. */
755 fclose(f);
758 /* Assign fitness to an entity. */
759 static boolean
760 evaluate_entity(population *pop, entity *entity)
762 /* Get results computed by our entity. */
763 int results[EQNO];
764 execute_entity(entity, results);
766 /* Count number of differences to reference results. */
767 int diffcount = 0;
768 for (int i = 0; i < EQNO; i++) {
769 if (results[i] != refresults[i])
770 diffcount++;
773 /* Compute entity fitness. With no differences, fitness
774 * will be 1; with no match, fitness will be 0. With
775 * e.g. 75% match, fitness will be 0.75. */
776 /* The (double) typecast makes sure / will be floating,
777 * not integer division. */
778 entity->fitness = 1.0 - (double) diffcount / EQNO;
780 /* In addition, we encourage the simplest programs by
781 * subtracting a tree size based term from the fitness. */
782 const int typical_size = 200;
783 const double typical_weight = 0.01;
784 int size = program_node_subtree_size(entity->chromosome[0]);
785 entity->fitness -= size / typical_size * typical_weight;
786 /* Alternative idea, does not work as well: */
787 //entity->fitness -= log(1 + size / typical_size) * typical_weight;
789 return TRUE;
792 int main(int argc, char **argv)
794 /* Load results of equations to compare the entities to. */
795 load_reference_results();
797 /* Run the algorithm several times. */
798 for (int i = 1; i < 10; i++) {
799 /* Make sure different random numbers are tried in each
800 * iteration, but same results are obtained over repeated
801 * program runs. */
802 random_seed(i * 16801 + 1239197);
803 /* The random number generator in GAUL behaves extraordinarily
804 * poorly in case it is used to generate numbers 0..2^k-1 where
805 * k is small. Its behavior improves after some time,
806 * so this drains its initial state by asking for a random
807 * number many times. */
808 for (int j = 0; j < 10000; j++)
809 (void) random_rand();
811 /* Set up the initial population and define the chromosome
812 * routines and genetic operators (names of functions for
813 * assigning fitness, mutation, crossover, etc.). */
814 population *pop = ga_population_new(
815 100 /* const int population_size */,
816 1, /* const int num_chromo */
817 0 /* const int len_chromo */
819 pop->chromosome_constructor = program_chromosome_constructor;
820 pop->chromosome_destructor = program_chromosome_destructor;
821 pop->chromosome_replicate = program_chromosome_replicate;
823 pop->evaluate = evaluate_entity;
824 pop->seed = seed_entity;
825 pop->select_one = ga_select_one_sus;
826 pop->select_two = ga_select_two_sus;
827 pop->mutate = mutate_entity;
828 pop->crossover = crossover_entity;
830 /* Set parameters of the genetic algorithm. */
831 ga_population_set_parameters(
832 pop, /* population *pop */
833 GA_SCHEME_DARWIN, /* const ga_scheme_type scheme */
834 GA_ELITISM_PARENTS_SURVIVE, /* const ga_elitism_type elitism */
835 0.9, /* double crossover */
836 0.4, /* double mutation */
837 0.0 /* double migration */
840 /* Run the genetic algorithm for 10 generations. */
841 ga_evolution(
842 pop, /* population *pop */
843 150 /* const int max_generations */
846 /* Print the winner. */
847 entity *winner = ga_get_entity_from_rank(pop, 0);
848 printf("The solution with seed = %d was:\n", i);
849 program_node_print(stdout, (struct program_node *) winner->chromosome[0]);
850 printf("\nWith score = %f\n", ga_entity_get_fitness(winner));
852 ga_extinction(pop);
855 exit(EXIT_SUCCESS);