String Evolver, My First Genetic Algorithm

When reading Evolutionary Computation for Modeling and Optimization[1], I found following problem in section 1.2.3:

A string evolver is an evolutionary algorithm that tries to match a reference string from a population of random strings. The underlying character set of the string evolver is the alphabet from which the strings are drawn.

The solution given in the context is:

  1. Start with a reference string and a population of random strings.
  2. The fitness of a string is the number of positions in which it has the same character as the reference string.
  3. To evolve the population, split it into small random groups called tournaments.
  4. Copy the most fit string(break ties by picking at random among the most fit strings) over the least fit string in each tournament.
  5. Then change one randomly chosen character in each copy(mutation).
  6. Repeat until an exact match with the reference string is obtained.

When trying this solution, I noticed that it won't converge even after a long time. Therefore, I modified the crossover and mutation strategy.A subset of population(strings) will be selected based on fitness in a tournament, and the bottom-ranked 50% of each tournament will be deleted. New population is formed by crossing the remaining high 20 individuals in a tournament, while the high-ranked parents are kept unchanged[2]. Finally, a random selected string in a tournament will be mutated.


My codes are:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define POP 20 
#define TNMT 4	    // Total number of tournaments
#define MAXSTR 80
char strPop[POP][MAXSTR]; // population of strings
char* REF="Hello,world!"; // Reference string
char* mostFit[TNMT]; 	  // the most fit string of each tournament
char* leastFit[TNMT]; 	// the least fit string of each 

tournament

char GenRandChar()
{
	return (char)(32+rand()%96);
}

char * GenRandStr(char* str, unsigned int len)
{
	int i;
	for(i=0;i<len-1;++i)
	{
		str[i]=GenRandChar();
	}
	str[i]='';
	return str;
}

// Copy the most fit string(break ties by picking at 
// random among the most fit strings) over the least 
// fit string in each tournament.
unsigned int CrossoverM2L(char* strMostFit, char* strLeastFit, unsigned int len)
{
	int i,p;
	char tmp;

	// Generate random position. Make sure the string
	// won't be broken at the first or last character.
	p=rand()%(len-2)+1;
	for(i=0;i<p;++i)
	{
		tmp=strMostFit[i];
		strMostFit[i]=strLeastFit[i];
		strLeastFit[i]=tmp;
	}
	return p;
}

// Change one randomly chosen character in each copy.
unsigned int Mutate(char* str,unsigned int len)
{
	int p;

	p=rand()%len;
	str[p]=GenRandChar();
	return p;
}

// Count the number of identical chars between ref and str.
unsigned int GetFitness(char* str,unsigned int len)
{
	int i;
	int cnt=0;
	for(i=0;i<len;++i)
	{
		if(REF[i]==str[i])
			cnt++;
	}
	
	return cnt;
}

// Find out the most and least fit strings in a tournament.
// 	tourn -- the number of tourn, starting from 0.
void GetFitOfTnmt(char* mostFit[],char* leastFit[],unsigned int tourn)
{
	int i,fit;
	char* str;
	int most_fit,least_fit;

	// Make sure the most and least fit strings are different
	mostFit[tourn]=strPop[tourn*POP/TNMT];
	most_fit=GetFitness(mostFit[tourn],strlen(REF));
	leastFit[tourn]=strPop[tourn*POP/TNMT+1];
	least_fit=GetFitness(leastFit[tourn],strlen(REF));
	for(i=1;i<POP/TNMT;++i)
	{
		str=strPop[tourn*POP/TNMT+i];
		fit=GetFitness(str,strlen(REF));
		if(most_fitfit)
		{
			least_fit=fit;
			leastFit[tourn]=str;
		}
	}
}

// Get the most fit string of the population
char* GetMostFit(char* mostFit[])
{
	int i,fit;
	char* strFit=mostFit[0];
	int most_fit=GetFitness(strFit,strlen(REF));
	for(i=1;i<TNMT;++i)
	{
		fit=GetFitness(mostFit[i],strlen(REF));
		if(most_fit<fit)
		{
			most_fit=fit;
			strFit=mostFit[i];
		}
	}
	
	return strFit;
}

// Sort the strings in a tournament by fitness.
void SortTournByFit(unsigned int tourn)
{
	int tmpInt;
	unsigned int fit[POP/TNMT];
	int i,j;
	int len=strlen(REF);
	char tmpStr[MAXSTR];

	// Get the fitness of each string in this tournament
	for(i=0;i<POP/TNMT;i++)
	{
		fit[i]=GetFitness(strPop[tourn*POP/TNMT+i],len);
	}

	// Sort strings by fitness
	for(i=0;i<POP/TNMT;i++)
	{
		for(j=i+1;j<POP/TNMT;j++)
		{
			if(fit[i]<fit[j])
			{
				tmpInt=fit[i];
				fit[i]=fit[j];
				fit[j]=tmpInt;

				strcpy(tmpStr,strPop[tourn*POP/TNMT+i]);
				strcpy(strPop[tourn*POP/TNMT+i],strPop[tourn*POP/TNMT+j]);
				strcpy(strPop[tourn*POP/TNMT+j],tmpStr);
			}
		} // end of for j
	} // end of for i
}

// Crossover the top half strings.
// Remove the second half strings after sorting, keep the top half, 
// and generate children by crossing over top half strings.
void CrossoverByFit(unsigned int tourn)
{
	int i,j,p,len;
	char* strTmp;

	SortTournByFit(tourn);

	// Generate random position. Make sure the string
	// won't be broken at the first or last character.
	len=strlen(REF);
	p=rand()%(len-2)+1;
	
	for(i=0;i<(int)POP/TNMT/2;i+=2)
	{
		for(j=0;j
p;--j)
		{
			strPop[(tourn+1)*POP/TNMT-1-i][j]=strPop[tourn*POP/TNMT+i+1][j];
			strPop[(tourn+1)*POP/TNMT-2-i][j]=strPop[tourn*POP/TNMT+i][j];
		}
	}
}


// Print population by tournaments.
void DumpPop()
{
	int i,j;
	char* curStr;
	for(i=0;i<TNMT;i++)
	{
		printf("Tournament %d:\n",i);
		for(j=0;j<POP/TNMT;j++)
		{
			curStr=strPop[i*POP/TNMT+j];
			printf("\t%s\tFitness: %d\n",curStr,GetFitness(curStr,strlen(curStr)));
		}
		printf("\n");
	}
}

//
// MAIN START HERE
//
int main()
{
	int LEN=strlen(REF);

	int i,j,p;
	long cnt=0;
	char * strFit=NULL;
	
	// Initionlization
	for(i=0;i<POP;++i)
	{
		GenRandStr(strPop[i],LEN);
	}
	
	printf("---------------- Original Population ---------------\n");
	DumpPop();
	
	for(i=0;i<TNMT;++i)
		GetFitOfTnmt(mostFit,leastFit,i);
		
	strFit=GetMostFit(mostFit);
	while(GetFitness(strFit,LEN) != LEN)
	//while(GetFitness(strFit,LEN)<5)
	{
		printf("\n---------------- Generation %d ----------------\n",cnt);
		DumpPop();

		printf("%s\tReference\n",REF);
		printf("%s\tGen: %d\tFitness: %d\n",strFit,cnt++,GetFitness(strFit,LEN));
		for(i=0;i<TNMT;++i)
		{
			// Crossover
			//CrossoverM2L(mostFit[i],leastFit[i],LEN);
			CrossoverByFit(i);
			
			// Mutation
			p=rand()%(POP/TNMT);
			Mutate(strPop[i*POP/TNMT+p],LEN);

			// Re-calculate the fitness
			GetFitOfTnmt(mostFit,leastFit,i);
		}
		strFit=GetMostFit(mostFit);
	}

	strFit=GetMostFit(mostFit);
	printf("\n---------------- Generation %d ----------------\n",cnt);
	DumpPop();
	printf("%s\tReference\n",REF);
	printf("%s\tGen: %d\tFitness: %d\n",strFit,cnt++,GetFitness(strFit,LEN));

	return 0;
}

And the output is:

---------------- Generation 0 ----------------
Tournament 0:
	F~AKK[b;tV]	Fitness: 0
	\\agA_q>vr	Fitness: 0
	OGG&Gy*(|yj	Fitness: 0
	6s[rEA8|45/	Fitness: 0
	W.e[:bYXlCz	Fitness: 0

Tournament 1:
	6n?y9o??VN#	Fitness: 0
	8mmZ~f:Dfn<	Fitness: 0
	i-nV!P`{oQ	Fitness: 0
	8%p%)\3-j;(	Fitness: 0
	92S2}&jU"f	Fitness: 0

Tournament 2:
	38IrA~lrHq|	Fitness: 0
	RF51Vo7V9]v	Fitness: 0
	Z(tUX<w|!{m	Fitness: 1
	qNoPy'a;OS]	Fitness: 0
	1`]em-+SM~~	Fitness: 0

Tournament 3:
	o^f(T&zQC3Q	Fitness: 0
	($g[j@ Asi	Fitness: 0
	@gb#E`!QGUb	Fitness: 0
	%H/>N)Kt_Pm	Fitness: 0
	i>Z+F0@6/'L	Fitness: 0

Hello,world!	Reference
Z(tUX<w|!{m	Gen: 0	Fitness: 1

---------------- Generation 1 ----------------
Tournament 0:
	F~AKK[b;tVx	Fitness: 0
	\\agA_q>vr	Fitness: 0
	OGG&Gy*(|yj	Fitness: 0
	\\agA_q>5]	Fitness: 0
	F~AKK[b;tCr	Fitness: 0

Tournament 1:
	6n?y9o??VN#	Fitness: 0
	kmmZ~f:Dfn<	Fitness: 0
	i-nV!P`{oQ	Fitness: 0
	8mm%9o??VN#	Fitness: 0
	6n?2~f:Dfn<	Fitness: 0

Tournament 2:
	Z(tUX<w|!{m	Fitness: 1
	RF51Vo7V9]v	Fitness: 0
	38IrA~lrHq|	Fitness: 0
	RFoUX<w|r{m	Fitness: 2
	Z(]1Vo7V9]v	Fitness: 0

Tournament 3:
	o^f(T&zQC3Q	Fitness: 0
	($g[j@ Asi	Fitness: 0
	@gb#E`!QGUb	Fitness: 0
	($/(T&zQC3Q	Fitness: 0
	@^Z[j@ Asi	Fitness: 0

Hello,world!	Reference
RFoUX<w|r{m	Gen: 1	Fitness: 2

---------------- Generation 2 ----------------
Tournament 0:
	F~AKK[b;tVx	Fitness: 0
	\\agA_q>vr	Fitness: 0
	OGG&Gy*(|yj	Fitness: 0
	\\agA_q>v]	Fitness: 0
	F~AeK[b;tVr	Fitness: 0

Tournament 1:
	Pn?y9o??VN#	Fitness: 0
	kmmZ~f:Dfn<	Fitness: 0
	i-nV!P`{oQ	Fitness: 0
	kmmZ~f??VN#	Fitness: 0
	6n?y9o:Dfn<	Fitness: 0

Tournament 2:
	RFoDX<w|r{m	Fitness: 2
	Z(tUX<w|!{m	Fitness: 1
	38IrA~lrHq|	Fitness: 0
	Z(t1X<w|r{m	Fitness: 2
	RFo1X<w|!{m	Fitness: 1

Tournament 3:
	o^f(T&zQC3Q|	Fitness: 0
	($g[j@ Asi	Fitness: 0
	@gb#E`!QGUb	Fitness: 0
	($f(T&zQC3Q	Fitness: 0
	o^g[j@ Asi	Fitness: 0

Hello,world!	Reference
RFoDX<w|r{m	Gen: 2	Fitness: 2

---------------- Generation 3 ----------------
Tournament 0:
	F~AKK[b;tVx	Fitness: 0
	\\agA_q>vr	Fitness: 0
	OGG&Gy*(|yj	Fitness: 0
	\\KK[b;tVx	Fitness: 0
	F~Aag~_q>vr	Fitness: 0

Tournament 1:
	Pn?y9o??VN#	Fitness: 0
	kmmZ~f:Dfn<@	Fitness: 0
	i-nV!P`{oQ	Fitness: 0
	km?y9o??VN#	Fitness: 0
	PnmZ~f:Dfn<	Fitness: 0

Tournament 2:
	RFoDX<w|r{m	Fitness: 2
	Z(t1X<w|r{m	Fitness: 2
	Z(tUX~w|!{m	Fitness: 1
	Z(oDX<w|r{m	Fitness: 2
	RFI1X<w|r{m	Fitness: 2

Tournament 3:
	o^f(T&zQC3Q|	Fitness: 0
	($g[j@ Asi	Fitness: 0
	@gb#E`!QGUb	Fitness: 0
	($g[W@ QC3Q|	Fitness: 0
	o^f(T&zAsi	Fitness: 0

Hello,world!	Reference
RFoDX<w|r{m	Gen: 3	Fitness: 2

---------------- Generation 4 ----------------
Tournament 0:
	F~AKK[b;tVx	Fitness: 0
	\\JgA_q>vr	Fitness: 0
	OGG&Gy*(|yj	Fitness: 0
	\\KK[b;tVx	Fitness: 0
	F~AagA_q>vr	Fitness: 0

Tournament 1:
	Pn?y9o??VN#	Fitness: 0
	kmmZ~f:Dfn<@	Fitness: 0
	i-nV!P`{oQ	Fitness: 0
	kmmZ~o??VN#	Fitness: 0
	Pnsy9f:Dfn<@	Fitness: 0

Tournament 2:
	RFoDX<w|r{m	Fitness: 2
	Z(t1X<w|r{m	Fitness: 2
	Z(oDXFw|r{m	Fitness: 2
	Z(t1X<w|r{m	Fitness: 2
	RFoDX<w|r{m	Fitness: 2

Tournament 3:
	o^f(T'zQC3Q|	Fitness: 0
	($g[j@ Asi	Fitness: 0
	@gb#E`!QGUb	Fitness: 0
	($g[j@ AsQ|	Fitness: 0
	o^f(T&zQC3i	Fitness: 0

Hello,world!	Reference
RFoDX<w|r{m	Gen: 4	Fitness: 2

      ......
      ......

---------------- Generation 2342 ----------------
Tournament 0:
	Hpllk,world!	Fitness: 10
	Hpllo,world!	Fitness: 11
	Hpllo,world!	Fitness: 11
	Hpllo,world!	Fitness: 11
	Hpllo,world!	Fitness: 11

Tournament 1:
	Hello,worlF!	Fitness: 11
	Hello,worlf!	Fitness: 11
	Hello,worlf!	Fitness: 11
	Hello,worlf!	Fitness: 11
	Hello,worlf!	Fitness: 11

Tournament 2:
	Hello,worldh	Fitness: 11
	Hello,worldJ	Fitness: 11
	Hello,worldh	Fitness: 11
	Hello,worldh	Fitness: 11
	Hello,worVdJ	Fitness: 10

Tournament 3:
	He:lo,w4rld!	Fitness: 10
	He:lo,w0rld!	Fitness: 10
	He:lo,w4rld!	Fitness: 10
	He:lo,w0rld!	Fitness: 10
	He:2o,w4rld!	Fitness: 9

Hello,world!	Reference
Hpllo,world!	Gen: 2342	Fitness: 11

---------------- Generation 2343 ----------------
Tournament 0:
	Hp|lo,world!	Fitness: 10
	Hpllo,world!	Fitness: 11
	Hpllo,world!	Fitness: 11
	Hpllo,world!	Fitness: 11
	Hpllo,world!	Fitness: 11

Tournament 1:
	Hello,worlF!	Fitness: 11
	Hello,wo&lf!	Fitness: 10
	Hello,worlf!	Fitness: 11
	Hello,worlF!	Fitness: 11
	Hello,worlf!	Fitness: 11

Tournament 2:
	Hello,worldh	Fitness: 11
	Hello,worldJ	Fitness: 11
	Hello,worldh	Fitness: 11
	Hello,wor&dh	Fitness: 10
	Hello,worldJ	Fitness: 11

Tournament 3:
	He:lo,w4rld!	Fitness: 10
	He:lo,w0rld!	Fitness: 10
	He:lo,w4rld!	Fitness: 10
	He:lo,w0rld!	Fitness: 10
	He:lozw4rld!	Fitness: 9

Hello,world!	Reference
Hpllo,world!	Gen: 2343	Fitness: 11

---------------- Generation 2344 ----------------
Tournament 0:
	Hpllo,world!	Fitness: 11
	Hpllo,world!	Fitness: 11
	H\llo,world!	Fitness: 11
	Hpllo,world!	Fitness: 11
	Hpllo,world!	Fitness: 11

Tournament 1:
	Hello,worlF!	Fitness: 11
	Hello,worlf!	Fitness: 11
	Hello,world!	Fitness: 12
	Hello,worlF!	Fitness: 11
	Hello,wo&lf!	Fitness: 10

Tournament 2:
	Hello,world 	Fitness: 11
	Hello,worldJ	Fitness: 11
	Hello,worldh	Fitness: 11
	Hello,worldh	Fitness: 11
	Hello,worldJ	Fitness: 11

Tournament 3:
	He:lo,w44ld!	Fitness: 9
	He:lo,w0rld!	Fitness: 10
	He:lo,w4rld!	Fitness: 10
	He:lo,w0rld!	Fitness: 10
	He:lo,w4rld!	Fitness: 10

Hello,world!	Reference
Hello,world!	Gen: 2344	Fitness: 12


-----------------------------------------------------------------

References:

[1]: Daniel Ashlock, Evolutionary Computation for Modeling and Optimization, Springer, 2005.

[2]: FORREST, S., WEIMER, W., NGUYEN, T., AND GOUES, C. L., A Genetic Programming Approach to Automated Software Repair, In GECCO (July 2009).

### 回答1: Surface Evolver是一个用于模拟和优化曲面的软件工具,它可以被用于各种应用领域,如材料科学、物理学、化学、工程学等。该软件使用能量最小化的方法来计算曲面的形状,并且可以通过添加适当的约束条件来控制曲面的形态。Surface Evolver还提供了一些高级功能,如自动网格生成、自适应网格细化、物理仿真等,使得它成为一个非常强大的工具。它的使用需要一定的数学和计算机科学基础。 ### 回答2: Surface Evolver是一个计算机模拟软件,用于建模和研究膜、泡沫、液滴和其他曲面形状的力学性质。它的名字源于“表面”和“演化者”,因为它的核心功能是通过模拟表面曲线的演化来计算表面的能量最小值。 Surface Evolver采用有限元法和能量最小化原理,通过数值计算来模拟表面的演化过程。用户可以通过提供初始形状和定义边界条件、约束和能量函数等参数,来控制和模拟表面的行为和形态演化。软件使用C语言编写,提供了方便的命令行界面和可视化工具,以及丰富的文档和教程,方便用户进行建模、求解和分析。 Surface Evolver可以应用于各种科学和工程领域的研究,如物理学、材料学、生物学、土木工程和计算机图形学等。它可以用来研究和优化薄膜的形态和稳定性,分析液滴和泡沫的表面张力和形状变化,解决各种曲面形状的力学问题等。通过它,可以更好地理解和预测复杂形态的力学行为,为实际工程和科学问题提供有力的支持。 总之,Surface Evolver是一个功能强大的表面模拟软件,它通过数值计算和演化原理来模拟和研究表面形态和力学性质,为科学研究和工程应用提供了有力的工具和平台。 ### 回答3: Surface Evolver是一个用于计算曲面形态和接触力学性质的软件程序。它的主要目的是模拟物质表面的能量最小化过程,为研究各种形态的曲面和界面系统提供数值分析方法。 Surface Evolver使用有限元法和梯度下降等数值计算方法,通过对表面张力、体积、接触角和面积等物理参数进行管理,能够模拟出表面形态、液滴的接触角、相分离界面、形态相变等各种现象。 使用Surface Evolver可以模拟并优化各种曲面,比如液滴形态、气泡膜、材料界面的稳定性等。这对于研究表面活性物质、纳米颗粒、薄膜和涂层等领域具有重要的应用价值。 Surface Evolver还可以用于研究生物系统中的形态发生过程,比如细胞分裂和组织发展等。通过改变曲面形态的能量,Surface Evolver可以模拟细胞膜和细胞间的相互作用,对细胞形态和组织形成过程进行定性和定量的分析。 总之,Surface Evolver是一个强大的数值计算工具,能够模拟和优化各种曲面形态和界面系统,对于研究材料科学、物理学、生物学等领域具有重要的意义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值