走迷宫机器人程序之2--遗传算法

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);
	}
}

    原文作者:遗传算法
    原文地址: https://blog.csdn.net/xianyuxiaoqiang/article/details/50252867
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞