遗传算法是解决复杂问题的一种搜索策略,是一种智能计算。他模拟自然界中的种群进化。从这点看,它和神经网络这些算法的起源很像,都是使用计算机去模拟一些自然法则和运作规律。同样,和神经网络一样,遗传算法也是一种基于概率的算法。当然,在现代启发式算法中,很多算法都都是基于概率的,比如神经网络,粒子群算法,模拟退火等。这类方法的要解决的一个问题就是NP问题,要求得结果是满意解,而非最优解。理解这点,我觉得很重要。
本文中的GA实现的例子来自于http://www.theprojectspot.com/tutorial-post/creating-a-genetic-algorithm-for-beginners/3 一文。有兴趣的读者,也可以参考原文的实现。
遗传算法工作的时候,可以分为以下几个步骤:
1.初始化:首先需要初始化一个种群,大小可以根据需要随意,几个个体或者几千个个体都可以。种群的中个体的产生是随机的。
2.评估:每一个种群成员需要计算他们的适应度,就和自然界里的生物对自然环境的适应度一样。这里的适应度计算是一个关键,一个基本原则是,把对解决当前问题有意义的个体的适应度应该设置得比较高,否则应该给一个低的适应度。适应度计算函数很影响遗传算法性能。因为每一次进化,每一次迭代,每一个个体都要不停得被评估,如果这个方法很慢,搜索性能就会比较差。
3.选择:选择适应度比较高的个体进入下一个进化阶段。适应度低的可以抛弃。
4.交叉:将选中的个体进行基因交叉,产生下一代种群。这个过程就和自然界中生物体有性生殖一样,做DNA的交叉。
5.变异:和自然界一样,DNA是会变异的,变异操作可以帮助我们跳出局部最优。
6.重复:不停重复以上评估、选择、交叉、变异,直到找到一个满意的个体作为算法的最终解。
下面来看一个实现,首先看一下个体:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
package
simpleGa
;
public class Individual { static int defaultGeneLength = 64 ; private byte [ ] genes = new byte [defaultGeneLength ] ; private int fitness = 0 ; // 随机的个体 public void generateIndividual ( ) { for ( int i = 0 ; i < size ( ) ; i ++ ) { byte gene = ( byte ) Math. round ( Math. random ( ) ) ; genes [i ] = gene ; } } // Use this if you want to create individuals with different gene lengths public static void setDefaultGeneLength ( int length ) { defaultGeneLength = length ; } public byte getGene ( int index ) { return genes [index ] ; } public void setGene ( int index, byte value ) { genes [index ] = value ; fitness = 0 ; } public int size ( ) { return genes. length ; } public int getFitness ( ) { if (fitness == 0 ) { fitness = FitnessCalc. getFitness ( this ) ; } return fitness ; } @Override public String toString ( ) { String geneString = "" ; for ( int i = 0 ; i < size ( ) ; i ++ ) { geneString += getGene (i ) ; } return geneString ; } } |
每一个个体需要计算它的适应度:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
package
simpleGa
;
public class FitnessCalc { static byte [ ] solution = new byte [ 64 ] ; // 设置一个候选解 public static void setSolution ( byte [ ] newSolution ) { solution = newSolution ; } // 设置一个候选解 就是参数类型不一样,这里做个转换 static void setSolution ( String newSolution ) { solution = new byte [newSolution. length ( ) ] ; // Loop through each character of our string and save it in our byte // array for ( int i = 0 ; i < newSolution. length ( ) ; i ++ ) { String character = newSolution. substring (i, i + 1 ) ; if (character. contains ( "0" ) || character. contains ( "1" ) ) { solution [i ] = Byte. parseByte (character ) ; } else { solution [i ] = 0 ; } } } // 计算某一个个体的适应度 static int getFitness (Individual individual ) { int fitness = 0 ; // 个体和候选解比较,约接近候选集,适应度越高 for ( int i = 0 ; i < individual. size ( ) && i < solution. length ; i ++ ) { if (individual. getGene (i ) == solution [i ] ) { fitness ++; } } return fitness ; } // 适应度的最大值 static int getMaxFitness ( ) { int maxFitness = solution. length ; return maxFitness ; } } |
基于个体而产生的种群:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
package
simpleGa
;
public class Population { Individual [ ] individuals ; // 建立一个总群 public Population ( int populationSize, boolean initialise ) { individuals = new Individual [populationSize ] ; // 初始化种群 if (initialise ) { // 建立每一个个体 for ( int i = 0 ; i < size ( ) ; i ++ ) { Individual newIndividual = new Individual ( ) ; newIndividual. generateIndividual ( ) ; saveIndividual (i, newIndividual ) ; } } } public Individual getIndividual ( int index ) { return individuals [index ] ; } public Individual getFittest ( ) { Individual fittest = individuals [ 0 ] ; // 取得适应度最高的个体作为种群的适应度 for ( int i = 0 ; i < size ( ) ; i ++ ) { if (fittest. getFitness ( ) <= getIndividual (i ). getFitness ( ) ) { fittest = getIndividual (i ) ; } } return fittest ; } // Get population size public int size ( ) { return individuals. length ; } // Save individual public void saveIndividual ( int index, Individual indiv ) { individuals [index ] = indiv ; } } |
基于以上的个体和种群,就可以进行遗传算法的主要工作,交叉,变异等等。来看一下核心的算法实现:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
package
simpleGa
;
public class Algorithm { private static final double uniformRate = 0.5 ; private static final double mutationRate = 0.015 ; private static final int tournamentSize = 5 ; private static final boolean elitism = true ; // 进化一个种群 public static Population evolvePopulation (Population pop ) { Population newPopulation = new Population (pop. size ( ), false ) ; // 保留最优秀的个体 if (elitism ) { newPopulation. saveIndividual ( 0, pop. getFittest ( ) ) ; } // 交叉种群 int elitismOffset ; if (elitism ) { elitismOffset = 1 ; } else { elitismOffset = 0 ; } // 交叉产生新的个体 for ( int i = elitismOffset ; i < pop. size ( ) ; i ++ ) { //确保不要把最差的个体选进来 Individual indiv1 = tournamentSelection (pop ) ; Individual indiv2 = tournamentSelection (pop ) ; Individual newIndiv = crossover (indiv1, indiv2 ) ; newPopulation. saveIndividual (i, newIndiv ) ; } // 变异 for ( int i = elitismOffset ; i < newPopulation. size ( ) ; i ++ ) { mutate (newPopulation. getIndividual (i ) ) ; } return newPopulation ; } // 交叉 private static Individual crossover (Individual indiv1, Individual indiv2 ) { Individual newSol = new Individual ( ) ; // Loop through genes for ( int i = 0 ; i < indiv1. size ( ) ; i ++ ) { // 以一定概率交叉 if ( Math. random ( ) <= uniformRate ) { newSol. setGene (i, indiv1. getGene (i ) ) ; } else { newSol. setGene (i, indiv2. getGene (i ) ) ; } } return newSol ; } // 变异 private static void mutate (Individual indiv ) { // Loop through genes for ( int i = 0 ; i < indiv. size ( ) ; i ++ ) { if ( Math. random ( ) <= mutationRate ) { // 以一定概率变异 byte gene = ( byte ) Math. round ( Math. random ( ) ) ; indiv. setGene (i, gene ) ; } } } // 选择用于交叉的个体,确保最差的个体不会进来 private static Individual tournamentSelection (Population pop ) { Population tournament = new Population (tournamentSize, false ) ; for ( int i = 0 ; i < tournamentSize ; i ++ ) { int randomId = ( int ) ( Math. random ( ) * pop. size ( ) ) ; tournament. saveIndividual (i, pop. getIndividual (randomId ) ) ; } Individual fittest = tournament. getFittest ( ) ; return fittest ; } } |
以上就是全部的实现,最后,测试这些代码