chromosome.h
#define MAX_BITS_PER_GENE 8
typedef struct chromo_tag
{
unsigned int bits_per_gene;
unsigned int gene_num;
char * data_p;
} chromo_t;
int init_chromo( chromo_t *chromo_p, unsigned int bits_per_gene, unsigned int gene_num );
int free_chromo( chromo_t *chromo_p );
char get_gene( chromo_t *chromo_p, unsigned int gene_index );
int set_gene( chromo_t *chromo_p, unsigned int gene_index, char new_gene );
population.h
#include "chromosome.h"
#define BITS_PER_GENE 2 // todo1: muti gene. todo2: input from config file
#define GEN_NUM 30 // todo1: muti gene. todo2: input from config file
#define MOVE_UP (char)0x00
#define MOVE_DOWN (char)0x40
#define MOVE_LEFT (char)0x80
#define MOVE_RIGHT (char)0xC0
#define MAX_GENERATION 1000
#define MutationRate 0.001
#define CrossoverRate 0.7
typedef struct individual_tag
{
chromo_t chromo;
float score; // the score of the individual(0~100)
}individual_t;
typedef struct population_tag
{
individual_t *individual_array;
unsigned int individual_num;
}population_t;
typedef struct rouletteWheelPiece_tag
{
float low;
float high;
}piece_t;
typedef struct rouletteWheel_tag
{
unsigned int num;
piece_t *data_p;
}rouletteWheel_t;
int init_population( population_t *popu_p, unsigned int individual_num);
int free_population( population_t *popu_p );
int crossover( population_t *parents_p, population_t *children_p );
int updateScore( individual_t *indi );
int mutation( population_t *parents_p );
chromosome.c
#include "common.h"
#include "chromosome.h"
int init_chromo( chromo_t *chromo_p, unsigned int bits_per_gene, unsigned int gene_num )
{
unsigned int size = ( bits_per_gene * gene_num + 8 ) / 8;
chromo_p->bits_per_gene = 0;
chromo_p->data_p = NULL;
chromo_p->gene_num = 0;
if( MAX_BITS_PER_GENE < bits_per_gene )
{
error_output( "Too long bits per gene." );
return 1;
}
chromo_p->data_p = malloc( size );
if( chromo_p->data_p == NULL )
{
error_output( "init_chomo: malloc fail." );
return 1;
}
memset(chromo_p->data_p, 0, size);
chromo_p->bits_per_gene = bits_per_gene;
chromo_p->gene_num = gene_num;
return 0;
}
int free_chromo( chromo_t *chromo_p )
{
if( chromo_p->data_p != NULL )
{
free( chromo_p->data_p );
chromo_p->data_p = NULL;
chromo_p->bits_per_gene = 0;
chromo_p->gene_num = 0;
}
return 0;
}
// this function only support no more than 1 byte
// the returned gene is starting from the first bit
char get_gene( chromo_t *chromo_p, unsigned int gene_index )
{
char part1, part2;
unsigned int level1,level2;
if( gene_index >= chromo_p->gene_num )
{
error_output( "get_gene: out of range." );
return 0;
}
// get first part of start byte
level1 = gene_index * chromo_p->bits_per_gene;
level2 = level1 - level1 / 8 * 8;
level1 = level1 / 8;
part1 = chromo_p->data_p[level1];
part1 = part1 << level2;
// get second part of continue byte
if( level2 + chromo_p->bits_per_gene > 8 )
{
part2 = chromo_p->data_p[level1 + 1];
// make sure start with 0
part2 = part2 >> 1;
part2 &= 0x7F;
part2 = part2 >> ( 8 - level2 - 1 );
// clear part2 of part1
part1 &= 0xFF << level2;
return part1 | part2;
}
return part1;
}
// this function only support no more than 1 byte
// the new_gene should start from the first bit and end with all "1"
int set_gene( chromo_t *chromo_p, unsigned int gene_index, char new_gene )
{
char part1 = 0xFF, part2 = 0xFF;
char tmp = 0xFF;
unsigned int level1,level2;
if( gene_index >= chromo_p->gene_num )
{
error_output( "set_gene: out of range." );
return 1;
}
// set first part of start byte
level1 = gene_index * chromo_p->bits_per_gene;
level2 = level1 - level1 / 8 * 8;
level1 = level1 / 8;
part1 = (new_gene >> level2) | ( tmp << (8 - level2) ) ;
// clear old value
if( level2 + chromo_p->bits_per_gene < 8 )
{
tmp = 0xFF << (8 - level2);
tmp |= 0x7F >> (level2 + chromo_p->bits_per_gene - 1);
chromo_p->data_p[level1] &= tmp;
}
else
{
chromo_p->data_p[level1] &= ( tmp << (8 - level2) );
}
if( level2 > 0 )
{
// make sure start with 0
part1 = new_gene >> 1;
part1 &= 0x7F;
part1 = part1 >> (level2-1);
if( level2 + chromo_p->bits_per_gene < 8 )
{
tmp = 0xFF << (8 - level2);
tmp |= 0x7F >> (level2 + chromo_p->bits_per_gene - 1);
tmp = ~tmp;
part1 &= tmp;
chromo_p->data_p[level1] |= part1;
}
else
{
chromo_p->data_p[level1] |= part1;
}
}
// set second part of continue byte
if( level2 + chromo_p->bits_per_gene > 8 )
{
// clear old value
tmp = 0x7F >> (level2 + chromo_p->bits_per_gene - 8 - 1);
chromo_p->data_p[level1 + 1] &= tmp;
part2 = (new_gene << ( 8 - level2 )) & (0xFF << ( 16 - level2 - chromo_p->bits_per_gene ));
chromo_p->data_p[level1 + 1] |= part2;
}
return 0;
}
population.c
#include "population.h"
#include "common.h"
int init_population( population_t *popu_p, unsigned int individual_num)
{
unsigned int i;
int ret;
popu_p->individual_array = NULL;
popu_p->individual_num = 0;
popu_p->individual_array = malloc( sizeof(individual_t) * individual_num );
if( popu_p->individual_array == NULL )
{
error_output( "init_population: malloc error." );
goto ERROR_END;
}
for( i=0; i<individual_num; i++ )
{
// todo1: muti gene. todo2: input from config file
ret = init_chromo( &popu_p->individual_array[i].chromo, BITS_PER_GENE, GEN_NUM );
if( ret != 0 )
{
goto ERROR_END;
}
popu_p->individual_array[i].score = 0;
}
popu_p->individual_num = individual_num;
return 0;
ERROR_END:
free_population(popu_p);
return 1;
}
int free_population( population_t *popu_p )
{
unsigned int i;
if( popu_p->individual_array != NULL )
{
for( i=0; i<popu_p->individual_num; i++ )
{
free_chromo(&popu_p->individual_array[i].chromo);
}
free( popu_p->individual_array );
popu_p->individual_array = NULL;
popu_p->individual_num = 0;
}
return 0;
}
int rouletteWheelSelection(rouletteWheel_t *rw_p)
{
int ran = getRand(100);
float cur = rw_p->data_p[rw_p->num -1].high / 100 * ran;
int i;
for( i=0; i<rw_p->num; i++ )
{
if( rw_p->data_p[i].high >= cur )
{
return i;
}
}
return 0;
}
int crossover_sub(chromo_t *a, chromo_t *b)
{
unsigned int bytenum = ( a->bits_per_gene * a->gene_num + 8 ) / 8;
int ran = getRand(bytenum);
int i;
char tmp;
for( i=ran; i<bytenum; i++ )
{
tmp = b->data_p[i];
b->data_p[i] = a->data_p[i];
a->data_p[i] = tmp;
}
return 0;
}
int crossover( population_t *parents_p, population_t *children_p )
{
int j;
int index1;
int index2;
int child_index=0;
int ran;
rouletteWheel_t rw;
// init rouletteWheel
rw.num = parents_p->individual_num;
rw.data_p = malloc( sizeof(piece_t) * rw.num );
rw.data_p[0].low = 0;
rw.data_p[0].high = parents_p->individual_array[0].score;
if( rw.data_p == NULL )
{
error_output( "crossover: malloc error." );
return 1;
}
for( j=1; j<rw.num; j++ )
{
rw.data_p[j].low = rw.data_p[j-1].high;
rw.data_p[j].high = rw.data_p[j].low + parents_p->individual_array[j].score;
}
while( child_index < children_p->individual_num-1 )
{
index1 = rouletteWheelSelection(&rw);
index2 = rouletteWheelSelection(&rw);
ran = getRand(100);
if( ran > CrossoverRate * 100 )
{
continue;
}
if( index1 == index2 )
{
// this guy is luky
chromo_t * fromchromo = &parents_p->individual_array[index1].chromo;
chromo_t * tochromo = &children_p->individual_array[child_index].chromo;
memcpy( tochromo->data_p, fromchromo->data_p,(tochromo->bits_per_gene * tochromo->gene_num + 8)/8 );
child_index++;
}
else
{
// crossover
chromo_t * fromA = &parents_p->individual_array[index1].chromo;
chromo_t * fromB = &parents_p->individual_array[index2].chromo;
chromo_t toA,toB;
chromo_t * tochromo = &children_p->individual_array[child_index].chromo;
individual_t indA;
individual_t indB;
init_chromo(&toA, fromA->bits_per_gene, fromA->gene_num);
init_chromo(&toB, fromB->bits_per_gene, fromB->gene_num);
indA.chromo = toA;
indB.chromo = toB;
memcpy( toA.data_p, fromA->data_p,(toA.bits_per_gene * toA.gene_num + 8)/8 );
memcpy( toB.data_p, fromB->data_p,(toB.bits_per_gene * toB.gene_num + 8)/8 );
crossover_sub(&toA, &toB);
// only one the the two can live
updateScore(&indA);
updateScore(&indB);
if( indA.score >= indB.score )
{
memcpy( tochromo->data_p, toA.data_p,(tochromo->bits_per_gene * tochromo->gene_num + 8)/8 );
}
else
{
memcpy( tochromo->data_p, toB.data_p,(tochromo->bits_per_gene * tochromo->gene_num + 8)/8 );
}
child_index++;
free_chromo(&toA);
free_chromo(&toB);
}
if( child_index >= children_p->individual_num-1 )
{
// finish
break;
}
}
return 0;
}
// 0 : not success
// 1 : success (with score 100)
int updateScore( individual_t *indi )
{
unsigned int i,j,cur_col, cur_row;
float score1;
float score2;
input_data_t indata;
chromo_t *chromo_p = &indi->chromo;
indata = initInputData("input.txt",2);
cur_col = 0;
cur_row = 1;
for( j=0; j<chromo_p->gene_num; j++ )
{
char gene;
char direction;
gene = get_gene(chromo_p, j);
direction = decode_gene(gene);
switch(direction)
{
case MOVE_UP:
moveUp( &indata, &cur_col, &cur_row );
break;
case MOVE_DOWN:
moveDown( &indata, &cur_col, &cur_row );
break;
case MOVE_LEFT:
moveLeft( &indata, &cur_col, &cur_row );
break;
case MOVE_RIGHT:
moveRight( &indata, &cur_col, &cur_row );
break;
default:
debug_output("updateScore: error direction.");
break;
}
if( cur_col == indata.col_num - 1 )
{
debug_output("updateScore: success!");
indi->score = 100.0; // the sucess score
freeInputData(&indata);
return 1;
}
}
// set the score
score1 = ( indata.col_num -1 - cur_col ) * 1.0 / indata.col_num * 100.0;
score1 = 100.0 - score1;
score2 = ( indata.row_num -1 - cur_row ) * 1.0 / (indata.row_num - 1) * 100.0;
score2 = 100.0 - score2;
indi->score = score1 * score2 / 100.0;
freeInputData(&indata);
return 0;
}
int mutation( population_t *parents_p )
{
int i;
int gene_index;
int bit_index;
char gene;
char tmp;
chromo_t *chromo_p;
for( i=0; i<parents_p->individual_num; i++ )
{
int ran = getRand(10000);
if( ran >= 10000 * MutationRate )
{
continue;
}
chromo_p = &parents_p->individual_array[i].chromo;
gene_index = getRand(chromo_p->gene_num);
gene = get_gene(chromo_p, gene_index);
bit_index = getRand(chromo_p->bits_per_gene);
if( bit_index > 0 )
{
tmp = ( 0x7F >> (bit_index-1) ) & ( 0xFF << (8-bit_index-1) );
}
else
{
tmp = 0xC0;
}
if( gene & tmp )
{
gene &= ~tmp;
}
else
{
gene |= tmp;
}
set_gene(chromo_p, gene_index, gene);
}
}