作者: abruzzi 链接:http://abruzzi.javaeye.com/blog/266677 发表时间: 2008年11月13日
声明:本文系JavaEye网站发布的原创博客文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任!
在维基(wiki)中关于自然选择的词条的搜索结果如下:
遗传算法(Genetic Algorithm)由密歇根大学的约翰·霍兰德(John Holland)和他的同事于二十世纪六十年代在对细胞自动机(cellular automata)进行研究时率先提出。是一种全局优化算法,应用领域比较广泛。
遗传算法借鉴了达尔文的进化论,也使用了一些达尔文定义的术语,如选择,遗传,变异,适应度等。当然,也引入了一些后来自然科学家提出的概念,如基因,DNA,染色体等。
好和坏的区别:
如果一个个体适应自身所在的环境,则此个体为“好”,反之为“坏”。在遗传算法中,这个概念由“适应度”来表示。当然,适应度跟具体要解决的问题有关。通常,适应度计算函数会返回一个0-1之间的浮点数。
进化论的本质:
遗传算法的自然语言描述:
最后计算的结果即为最优解集合。
由于操作之前,个体对自己将来会进化成什么样的结果是一无所知的,所以需要有一个结束点,一个度量方式。当然,自然界是没有结束点的,生物只能说适应了目前的环境,但是它会一直进化,直到适应了新的环境或者灭绝。
一个基于JAVA的遗传算法的实现是JGAP(Java Genetic Algorithm Package)。参见:http://jgap.sourceforge.net/
遗传算法就是遍历搜索空间或连接池,从中找出最优的解。搜索空间中全部都是个体,而群体为搜索空间的一个子集。
并不是所有被选择了的染色体都要进行交叉操作和变异操作,而是以一定的概率进行,一般在程序设计中交叉发生的概率要比变异发生的概率选取得大若干个数量级。大部分遗传算法的步骤都很类似,常使用如下参数:
JGAP对很多参数设置进行了隐藏,封装。使用者只需要提供自己的Fitness函数即可,当然如果你对GA比较熟悉的话,可以对这些隐式参数进行修改。
JGAP中自带的例子中有这样一个例子:MinimizingMakeChangeFitnessFunction.java,我们下来就以这个例子来说一说这个GA包的用法。
下面是一个例子,我删除了一些注释和版权信息等,并做了一些简单的格式化
package examples;
import org.jgap.*;
public class MinimizingMakeChangeFitnessFunction
extends FitnessFunction {
private final int m_targetAmount;
public static final int MAX_BOUND = 4000;
public MinimizingMakeChangeFitnessFunction(int a_targetAmount) {
if (a_targetAmount < 1 || a_targetAmount >= MAX_BOUND) {
throw new IllegalArgumentException(
"Change amount must be between 1 and " + MAX_BOUND + " cents.");
}
m_targetAmount = a_targetAmount;
}
public double evaluate(IChromosome a_subject) {
boolean defaultComparation = a_subject.getConfiguration().
getFitnessEvaluator().isFitter(2, 1);
int changeAmount = amountOfChange(a_subject);
int totalCoins = getTotalNumberOfCoins(a_subject);
int changeDifference = Math.abs(m_targetAmount - changeAmount);
double fitness;
if (defaultComparation) {
fitness = 0.0d;
} else {
fitness = MAX_BOUND/2;
}
if (defaultComparation) {
fitness += changeDifferenceBonus(MAX_BOUND/2, changeDifference);
} else {
fitness -= changeDifferenceBonus(MAX_BOUND/2, changeDifference);
}
if (defaultComparation) {
fitness -= computeCoinNumberPenalty(MAX_BOUND/2, totalCoins);
} else {
fitness += computeCoinNumberPenalty(MAX_BOUND/2, totalCoins);
}
return Math.max(1.0d, fitness);
}
protected double changeDifferenceBonus(double a_maxFitness,
int a_changeDifference) {
if (a_changeDifference == 0) {
return a_maxFitness;
} else {
if (a_changeDifference * a_changeDifference >= a_maxFitness / 2) {
return 0.0d;
} else {
return a_maxFitness / 2 - a_changeDifference * a_changeDifference;
}
}
}
protected double computeCoinNumberPenalty(double a_maxFitness, int a_coins) {
if (a_coins == 1) {
return 0;
} else {
return (Math.min(a_maxFitness, a_coins * a_coins));
}
}
public static int amountOfChange(IChromosome a_potentialSolution) {
int numQuarters = getNumberOfCoinsAtGene(a_potentialSolution, 0);
int numDimes = getNumberOfCoinsAtGene(a_potentialSolution, 1);
int numNickels = getNumberOfCoinsAtGene(a_potentialSolution, 2);
int numPennies = getNumberOfCoinsAtGene(a_potentialSolution, 3);
return (numQuarters * 25) + (numDimes * 10) + (numNickels * 5) +
numPennies;
}
public static int getNumberOfCoinsAtGene(IChromosome a_potentialSolution,
int a_position) {
Integer numCoins =
(Integer) a_potentialSolution.getGene(a_position).getAllele();
return numCoins.intValue();
}
public static int getTotalNumberOfCoins(IChromosome a_potentialsolution) {
int totalCoins = 0;
int numberOfGenes = a_potentialsolution.size();
for (int i = 0; i < numberOfGenes; i++) {
totalCoins += getNumberOfCoinsAtGene(a_potentialsolution, i);
}
return totalCoins;
}
}
FitnessFunction 是一个抽象类,MinimizingMakeChangeFitnessFunction集成该类,并对evaluate方法给出具体实现,这个方法就是所谓的适应度函数。
确定染色体的结构及基因
第一步,决定“染色体”的结构和性质,如染色体包含多少个基因,以及这些基因有什么表现形式(如人类基因记载了人的肤色,面貌特征等信息)。这个例子中,程序会生成一堆零钱,这些零钱包含了一些种类的美国硬币,而钱数正好与用户的输入向匹配。这个例子中,染色体的表现形式就是一堆硬币。每个染色体中有四个基因(15分,10分,5分和1分)
这个染色体可以看作是一个串:STRING[4] = {"quarter","dime","nickel","pennie"},第一个位置上的数目为3(等位基因),则表示15×3 = 45,第二个位置上为5(等位基因),则表示10×5 = 50分,等等。
适应度函数的实现---什么算“好”
在这个例子中,我们认为,硬币的总数目恰好等于用户指定的数目(如85,34等),而且硬币的数目尽可能的少,想必学习过算法设计与分析课程的有点熟悉吧(贪婪算法的一个例子就是这个大名鼎鼎的“找钱问题”)。
在就是一些处理字符串,计算总数之类的方法,总的没有什么难以理解的地方,就不消多说了,如果还不明白可以留言,我会耐心回答的,呵呵。
总之:在使用JGAP时,关键问题有两点:
小结:
遗传算法的应用领域还是比较广泛的,不过解决的问题可以统称为全局优化相关的问题 。大家可以在参考文献给出的链接中获取更多的信息。
参考文献:
中文维基:http://zh.wikipedia.org/w/index.php?title=%E8%87%AA%E7%84%B6%E9%80%89%E6%8B%A9&variant=zh-cn
IBM developeWorks:http://www-128.ibm.com/developerworks/cn/java/j-lo-robocode1/index.html