Index: work/gpstroke/cap.c =================================================================== --- work/gpstroke/cap.c (revision 7379) +++ work/gpstroke/cap.c (revision 7380) @@ -2,6 +2,7 @@ #include #include #include +#include #include "c24lib/image/image.h" #include "c24lib/image/draw.h" #include "c24lib/image/pnm.h" @@ -11,7 +12,7 @@ #define MAX_STROKES 64 int max_strokes = 16; -image_t *ref; +image_t *ref, *canvas; typedef struct { int x1, y1, x2, y2, th; @@ -22,40 +23,127 @@ stroke_t str[MAX_STROKES]; } pcb_t; +/* Random value between from and to, inclusive */ int myrand(int from, int to) { - return from + rand() % (to - from); + return from + rand() % (to - from + 1); } +static inline void rand_stroke(stroke_t *s) +{ + s->x1 = myrand(0, ref->sx-1); + s->x2 = myrand(0, ref->sx-1); + s->y1 = myrand(0, ref->sy-1); + s->y2 = myrand(0, ref->sy-1); + s->th = myrand(1, 20); +} + void *pcb_create(void) { pcb_t *p = malloc(sizeof(pcb_t)); int n; - p->len = myrand(1, max_strokes); - for(n = 0; n < p->len; n++) { - p->str[n].x1 = myrand(0, ref->sx-1); - p->str[n].x2 = myrand(0, ref->sx-1); - p->str[n].y1 = myrand(0, ref->sy-1); - p->str[n].y2 = myrand(0, ref->sy-1); - p->str[n].th = myrand(1, 20); - } + p->len = myrand(1, max_strokes/2); + for(n = 0; n < p->len; n++) + rand_stroke(&p->str[n]); return p; } +static inline void pcb_clear(image_t *img) +{ + int n; + pixel_t *p = img->pixmap; + for(n = 0; n < img->sx * img->sy; n++,p++) { + *p = pixel_white; + } +} + +static inline long int pcb_diff(const image_t *img1, const image_t *img2) +{ + long int diff = 0; + int n; + const pixel_t *p1 = img1->pixmap; + const pixel_t *p2 = img2->pixmap; + for(n = 0; n < img1->sx * img1->sy; n++,p1++,p2++) { + if ((p1->r != p2->r) || (p1->g != p2->g) || (p1->b != p2->b)) + diff++; + } + return diff; +} + +static inline void pcb_draw(image_t *img, pcb_t *p) +{ + int n; + + draw_color(pixel_black); + for(n = 0; n < p->len; n++) + draw_pcb_line(img, p->str[n].x1, p->str[n].y1, p->str[n].x2, p->str[n].y2, p->str[n].th); +} + double pcb_score(void *data) { pcb_t *p = data; - return p->len; + double scr; + + pcb_clear(canvas); + pcb_draw(canvas, data); + scr = pcb_diff(canvas, ref); + return scr + (p->len+1)*100.0; } +static inline void pcb_mutate_add(pcb_t *p) +{ + if (p->len >= MAX_STROKES) + return; + rand_stroke(&p->str[p->len]); + p->len++; +} -void pcb_mutate(void *data) +static inline void pcb_mutate_del(pcb_t *p) { + int rem, idx; + if (p->len < 2) + return; + + idx = myrand(0, p->len-1); + rem = p->len - idx - 1; + if (rem > 0) + memmove(p->str+idx, p->str+idx+1, rem*sizeof(stroke_t)); + p->len--; } +#define tune(dst, min, max, delta) \ + if ((dst + delta >= min) && (dst + delta <= max)) dst += delta; + +static inline void pcb_mutate_chg(pcb_t *p) +{ + int idx = myrand(0, p->len); + int fld = myrand(0, 5); + int dir = (rand() % 2) ? +1 : -1; + + switch(fld) { + case 0: tune(p->str[idx].x1, 0, ref->sx, dir); break; + case 1: tune(p->str[idx].x2, 0, ref->sx, dir); break; + case 2: tune(p->str[idx].y1, 0, ref->sy, dir); break; + case 3: tune(p->str[idx].y2, 0, ref->sy, dir); break; + case 4: tune(p->str[idx].th, 0, (ref->sx + ref->sy)/8, dir); break; + case 5: rand_stroke(&p->str[idx]); break; + } +} + +void pcb_mutate(void *data) +{ + int n=myrand(0, 100); + if (n > 65) + pcb_mutate_chg(data); + else if (n % 2) + pcb_mutate_add(data); + else + pcb_mutate_del(data); +} + void pcb_clone(void *dst, void *src) { memcpy(dst, src, sizeof(pcb_t)); @@ -62,30 +150,53 @@ } + +const char *pcb_dump(void *data, int population_id, int individual_id) +{ + pcb_t *p = data; + image_t *img = canvas; + static char s[256]; + FILE *f; + int n; + + snprintf(s, sizeof(s), "/tmp/stroke_%04d_%02d.str", population_id, individual_id); + f = fopen(s, "w"); + for(n = 0; n < p->len; n++) + fprintf(f,"stroke %d %d %d %d %d\n", p->str[n].x1, p->str[n].y1, p->str[n].x2, p->str[n].y2, p->str[n].th); + fclose(f); + + pcb_clear(img); + pcb_draw(img, data); + snprintf(s, sizeof(s), "/tmp/stroke_%04d_%02d.pnm", population_id, individual_id); + pnm_save(img, s); + return s; +} + + gp_pop_t pop = { - .len = 16, - .weak_kill = 5, - .clone_times = 2, + .len = 16*3, + .weak_kill = 5*3, + .clone_times = 2*3, .create = pcb_create, .score = pcb_score, .mutate = pcb_mutate, - .clone = pcb_clone + .clone = pcb_clone, + .dump = pcb_dump }; int main() { - image_t *img; - - img = image_new(240, 240); - draw_color(pixel_red); + int n; + srand(time(NULL)); + ref = pnm_load("wiki2.pnm"); + canvas = image_new(ref->sx, ref->sy); - draw_pcb_line(img, 30, 30, 200, 150, 10); - draw_pcb_line(img, 150, 150, 30, 30, 10); + gp_setup(&pop); - draw_pcb_line(img, 10, 100, 50, 100, 10); - - draw_pcb_line(img, 10, 100, 10, 150, 10); - - - pnm_save(img, "test.pnm"); + for(n = 0; n < 10000; n++) { + gp_iterate(&pop); + if ((pop.pop_cnt % 20) == 0) + gp_dump(stdout, &pop, 1); + } + pnm_save(ref, "/tmp/ref.pnm"); } Index: work/gpstroke/gp.c =================================================================== --- work/gpstroke/gp.c (revision 7379) +++ work/gpstroke/gp.c (revision 7380) @@ -1,4 +1,5 @@ #include +#include #include "gp.h" @@ -21,6 +22,7 @@ pop->indiv[n].data = pop->create(); pop->indiv[n].fitness = pop->score(pop->indiv[n].data); } + pop->pop_cnt = 0; gp_sort(pop); } @@ -28,6 +30,8 @@ { int n, s, delay; + pop->pop_cnt++; + /* kill the weakest few and replace them with the strongests */ for(delay = s = 0, n = pop->len - pop->weak_kill - 1; n < pop->len; n++) { pop->clone(pop->indiv[n].data, pop->indiv[s].data); @@ -42,5 +46,19 @@ for(n = s; n < pop->len; n++) pop->indiv[n].fitness = pop->score(pop->indiv[n].data); gp_sort(pop); + } + +void gp_dump(FILE *f, gp_pop_t *pop, int max_dump) +{ + int n; + for(n = 0; n < pop->len; n++) { + const char *dmp = NULL; + if ((pop->dump != NULL) && (n < max_dump)) + dmp = pop->dump(pop->indiv[n].data, pop->pop_cnt, n); + if (dmp == NULL) + dmp = "n/a"; + fprintf(f, " #%03d %f %s\n", n, pop->indiv[n].fitness, dmp); + } +} Index: work/gpstroke/gp.h =================================================================== --- work/gpstroke/gp.h (revision 7379) +++ work/gpstroke/gp.h (revision 7380) @@ -1,3 +1,5 @@ +#include + typedef struct { void *data; double fitness; @@ -13,10 +15,14 @@ void (*mutate)(void *data); void (*clone)(void *dst, void *src); double (*score)(void *data); + const char *(*dump)(void *data, int population_id, int individual_id); /* internal */ gp_indiv_t *indiv; + int pop_cnt; } gp_pop_t; void gp_setup(gp_pop_t *pop); void gp_iterate(gp_pop_t *pop); +void gp_dump(FILE *f, gp_pop_t *pop, int max_dump); + Index: work/gpstroke/pcb_draw.c =================================================================== --- work/gpstroke/pcb_draw.c (revision 7379) +++ work/gpstroke/pcb_draw.c (revision 7380) @@ -15,7 +15,7 @@ for(n = 0; n < th; n++) { if ((xx >= 0) && (xx <= dst->sx) && (yy >= 0) && (yy <= dst->sy)) { pixel_t *pixel = (dst->pixmap) + (int) xx + dst->sx * (int) yy; - *pixel = pixel_green; + *pixel = pixel_black; } xx += nx; yy += ny; @@ -54,7 +54,8 @@ nx = -vy; ny = vx; - draw_thick_line(dst, x1, y1, x2, y2, vx, vy, nx, ny, th); + if ((x1 != x2) || (y1 != y2)) + draw_thick_line(dst, x1, y1, x2, y2, vx, vy, nx, ny, th); // draw_color(pixel_red); // draw_line(dst, x1+nx*th/2.0, y1+ny*th, x2+nx*th, y2+ny*th/2.0);