算法(二)之遗传算法(SGA)

遗传算法(Genetic Algorithm)又叫基因进化算法或进化算法,是模拟达尔文的遗传选择和自然淘汰的生物进化过程的计算模型,属于启发式搜索算法一种。

下面通过下面例子的求解,来逐步认识遗传算法的操作过程。我参考了博客(http://blog.csdn.net/b2b160/article/details/4680853/),这个博客没提供代码,为了新手更好的学习,我用java实现了程序

例:求下述二元函数的最大值:

(1) 个体编码
           遗传算法的运算对象是表示个体的符号串,所以必须把变量 x1, x2 编码为一种
符号串。本题中,用无符号二进制整数来表示。
           因 x1, x2 为 0 ~ 7之间的整数,所以分别用3位无符号二进制整数来表示,将它们连接在一起所组成的6位无符号二进制数就形成了个体的基因型,表示一个可行解。
           例如,基因型 X=101110 所对应的表现型是:x=[ 5,6 ]。
 个体的表现型x和基因型X之间可通过编码和解码程序相互转换。

 /**
*
*/
package com.math.algorithm; /**
* @author summer
*
*/
public class Codec { static final int CODEC_LEN = 3; public static String encode(int x,int y){ return MathUtils.toBinaryString(x,CODEC_LEN)+
MathUtils.toBinaryString(y,CODEC_LEN);
} public static double[] decode(String s){ double[] r = new double[2];
String s1 = s.substring(0, s.length()/2) ;
String s2 = s.substring(s1.length());
r[0] = MathUtils.toInt(s1);
r[1] = MathUtils.toInt(s2);
return r;
} public static void main(String[] args){ System.out.println(encode(5,6));
System.out.println(encode(1,2));
double[] r =decode("101110");
System.out.println("x="+r[0]+" y="+r[1]);
r =decode("001010");
System.out.println("x="+r[0]+" y="+r[1]);
} }

(2) 初始群体的产生
          遗传算法是对群体进行的进化操作,需要给其淮备一些表示起始搜索点的初始
      群体数据。
         本例中,群体规模的大小取为4,即群体由4个个体组成,每个个体可通过随机
     方法产生。
          如:011101,101011,011100,111001

/**
*
*/
package com.math.algorithm; import java.util.List;
import java.util.Random; /**
* @author summer
*
*/
public class GeneGroupInit { static final int SIZE = 4;
static final int MAX_VAL = 8; public static void init(List<String> gene){ gene.clear();
Random r = new Random();
for(int i=0;i<SIZE;i++){
int x = r.nextInt(MAX_VAL);
if(x ==0)
x = r.nextInt(MAX_VAL);
int y = r.nextInt(MAX_VAL);
if( y ==0)
y = r.nextInt(MAX_VAL);
System.out.println("init x="+x+" y="+y + " norm="+(MathUtils.norm(x,y)));
gene.add(Codec.encode(x,y)); }
}
}

(3) 适应度汁算
          遗传算法中以个体适应度的大小来评定各个个体的优劣程度,从而决定其遗传
       机会的大小。
          本例中,目标函数总取非负值,并且是以求函数最大值为优化目标,故可直接
       利用目标函数值作为个体的适应度。

public static double evaluate(double[] g){

        return MathUtils.norm(g);
}

(4)  选择运算
          选择运算(或称为复制运算)把当前群体中适应度较高的个体按某种规则或模型遗传到下一代群体中。一般要求适应度较高的个体将有更多的机会遗传到下一代
      群体中。                   
本例中,我们采用与适应度成正比的概率来确定各个个体复制到下一代群体中
     的数量。其具体操作过程是:
         •  先计算出群体中所有个体的适应度的总和  Sfi  ( i=1.2,…,M );
         •  其次计算出每个个体的相对适应度的大小 fi / Sfi ,它即为每个个体被遗传
             到下一代群体中的概率,
         •  每个概率值组成一个区域,全部概率值之和为1;
         •  最后再产生一个0到1之间的随机数,依据该随机数出现在上述哪一个概率区
             域内来确定各个个体被选中的次数。

package com.math.algorithm;

import java.util.ArrayList;
import java.util.List;
import java.util.Random; /**
* @author summer
*
*/
public class Choose { public static double evaluate(double[] g){ return MathUtils.norm(g);
} public static double decodeAndEvaluate(String s){ double[] e = Codec.decode(s);
return evaluate(e);
} public static List<String> choose(List<String> gene){ List<String> cgene = new ArrayList<String>();
int[] index = new int[gene.size()];
double[] evals = new double[gene.size()];
double sum = 0;
double x =0;
int idx = 0;
Random r= new Random();
for(int i=0;i<gene.size();i++){ double eval = decodeAndEvaluate(gene.get(i));
evals[i] = eval;
if(x<eval){
x = eval;
idx = i;
}
sum += eval;
} index[0] = idx;
double prop = 0;
for(int i=0;i<evals.length;i++){
prop += evals[i];
evals[i] = prop/sum;
} for(int i=1;i<gene.size();i++){
double t = r.nextDouble();
int j;
for(j=0;j<evals.length;j++){
if(t < evals[j]){
break;
}
} index[i] = j; }
cgene.addAll(gene);
gene.clear();
for(int i:index){
gene.add(cgene.get(i));
} return cgene;
}
}

(5)  交叉运算
        交叉运算是遗传算法中产生新个体的主要操作过程,它以某一概率相互交换某
    两个个体之间的部分染色体。
       本例采用单点交叉的方法,其具体操作过程是:
       • 先对群体进行随机配对;
       • 其次随机设置交叉点位置;
       • 最后再相互交换配对染色体之间的部分基因。

 /**
*
*/
package com.math.algorithm; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random; import org.apache.commons.lang.StringUtils; /**
* 交叉算子
* @author summer
*
*/
public class OnePointCrossover { public static List<String> cross(List<String> gene,double pcross){ Random r = new Random();
List<String> genes = new ArrayList<String>();
genes.addAll(gene);
//Collections.shuffle(genes);
int pos ;
int size = genes.get(0).length();
String[] parent = new String[2];
String[] son ; gene.clear();
for(int i=0;i<genes.size();i=i+2){ parent[0] = genes.get(i);
parent[1] = genes.get(i+1); if(MathUtils.check(pcross,0.000001)){
pos = r.nextInt(size-1)+1;
}else{
pos = size;
} if(pos == size){
son = parent;
}else{
son = operate(parent,pos);
} Collections.addAll(gene, son);
}
return genes;
}
//110100 000100
//001000 111000 private static String[] operate(String[] parent,int pos){ String[] son = new String[2];
son[0] = StringUtils.overlay(parent[0],StringUtils.left(parent[1],pos),0,pos);
son[1] = StringUtils.overlay(parent[1],StringUtils.left(parent[0],pos),0,pos); return son;
} public static void main(String[] args){
List<String> parent= new ArrayList<String>();
Collections.addAll(parent,new String[]{"110111","001000","101110","010001"});
GeneticAlgorithm.print(parent);
List<String> son = cross(parent,0.85);
System.out.println(son);
System.out.println(parent);
}
}

(6)  变异运算
         变异运算是对个体的某一个或某一些基因座上的基因值按某一较小的概率进
     行改变,它也是产生新个体的一种操作方法。
        本例中,我们采用基本位变异的方法来进行变异运算,其具体操作过程是:
        • 首先确定出各个个体的基因变异位置,下表所示为随机产生的变异点位置,
          其中的数字表示变异点设置在该基因座处;
        • 然后依照某一概率将变异点的原有基因值取反。

对群体P(t)进行一轮选择、交叉、变异运算之后可得到新一代的群体p(t+1)。

 /**
*
*/
package com.math.algorithm; import java.util.ArrayList;
import java.util.List;
import java.util.Random; /**
* @author summer
*
*/
public class Mutation { static Random rnd = new Random(); public static List<String> mutation(List<String> gene,double MUTATION_RATE){ List<String> genes = new ArrayList<String>();
genes.addAll(gene);
int pos;
for(int i=0;i<gene.size();i++){ if(check(MUTATION_RATE)){ String g = gene.get(i);
pos = rnd.nextInt(g.length());
gene.set(i, operate(g,pos));
}
}
return genes;
} private static String operate(String g,int pos){ if(pos > g.length() || pos<0)
return g;
else{
char[] gc = g.toCharArray();
if(gc[pos] == '0')
gc[pos] = '1';
else{
gc[pos] = '0';
} return new String(gc);
}
} public static boolean check(double pcross){ return MathUtils.check(pcross, 0.00000001);
} public static void main(String[] args){ String s ="010101";
s = operate(s,2);
System.out.println(s);
s = operate(s,3);
System.out.println(s);
}
}

从上表中可以看出,群体经过一代进化之后,其适应度的最大值、平均值都得
    到了明显的改进。事实上,这里已经找到了最佳个体“111111”。

 /**
*
*/
package com.math.algorithm; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* @author summer
*
*/
public class GeneticAlgorithm { static final double CROSS_RATE = 0.85;
static final double MUTATION_RATE = 0.003;
static List<String> gene = new ArrayList<String>(GeneGroupInit.SIZE); public static void init(){ GeneGroupInit.init(gene);
} public static List<String> choose(){ return Choose.choose(gene);
} public static List<String> cross(){ return OnePointCrossover.cross(gene, CROSS_RATE);
} public static List<String> mutation(){ return Mutation.mutation(gene,MUTATION_RATE);
} static void print(){
for(String s:gene)
System.out.println(s);
} static void print(List<String> cgene){
for(String s:cgene)
System.out.println(s);
} public static void computer(){ System.out.println("+++++++++++++init+++++++++++++");
init();
print();
System.out.println("+++++++++++++choose+++++++++++++");
List<String> gene = choose();
print(gene);
System.out.println("-----------");
print();
System.out.println("+++++++++++++cross+++++++++++++");
gene = cross();
print(gene);
System.out.println("-----------");
print();
System.out.println("+++++++++++++mutation+++++++++++++");
gene = mutation();
print(gene);
System.out.println("-----------");
print();
} public static void main(String[] args){ final int N = 10;
Map<Integer,List<String>> result = new HashMap<Integer,List<String>>();
for(int i=0;i<N;i++){
System.out.println("************************************");
computer();
result.put(i,new ArrayList<String>(gene));
}
Map<String,Double> evaluateMap = new HashMap<String,Double>();
String idx = "";
double max = 0;
double[] evaluate = new double[N];
for(Map.Entry<Integer,List<String>> e : result.entrySet()){ max = 0;
List<String> val = e.getValue();
for(int i=0;i<val.size();i++){
String v = val.get(i);
double eval = Choose.decodeAndEvaluate(v);
evaluate[i] = eval;
if(eval > max){
max = eval;
idx = v;
} }
evaluateMap.put(idx,max);
System.out.println(val + " max=" + max);
} } }

程序运算结果:

[110111, 110111, 110001, 110111] max=85.0
[110110, 110110, 110110, 110110] max=72.0
[011010, 101100, 101100, 100100] max=41.0
[001011, 111110, 011101, 111110] max=85.0
[111111, 111111, 101011, 111111] max=98.0
[100011, 101110, 100010, 101111] max=74.0
[110111, 110111, 101111, 110111] max=85.0
[111001, 010111, 010110, 111001] max=53.0
[010110, 100100, 100111, 011100] max=65.0
[111100, 110001, 111101, 011000] max=74.0

[注意]      
        需要说明的是,表中有些栏的数据是随机产生的。这里为了更好地说明问题,
   我们特意选择了一些较好的数值以便能够得到较好的结果,而在实际运算过程中
   有可能需要一定的循环次数才能达到这个最优结果。

算法(二)之遗传算法(SGA)的更多相关文章

  1. TensorFlow 入门之手写识别(MNIST) softmax算法 二

    TensorFlow 入门之手写识别(MNIST) softmax算法 二 MNIST Fly softmax回归 softmax回归算法 TensorFlow实现softmax softmax回归算 ...

  2. 分布式共识算法 (二) Paxos算法

    系列目录 分布式共识算法 (一) 背景 分布式共识算法 (二) Paxos算法 分布式共识算法 (三) Raft算法 分布式共识算法 (四) BTF算法 一.背景 1.1 命名 Paxos,最早是Le ...

  3. Floyd算法(二)之 C++详解

    本章是弗洛伊德算法的C++实现. 目录 1. 弗洛伊德算法介绍 2. 弗洛伊德算法图解 3. 弗洛伊德算法的代码说明 4. 弗洛伊德算法的源码 转载请注明出处:http://www.cnblogs.c ...

  4. Dijkstra算法(二)之 C++详解

    本章是迪杰斯特拉算法的C++实现. 目录 1. 迪杰斯特拉算法介绍 2. 迪杰斯特拉算法图解 3. 迪杰斯特拉算法的代码说明 4. 迪杰斯特拉算法的源码 转载请注明出处:http://www.cnbl ...

  5. Prim算法(二)之 C++详解

    本章是普里姆算法的C++实现. 目录 1. 普里姆算法介绍 2. 普里姆算法图解 3. 普里姆算法的代码说明 4. 普里姆算法的源码 转载请注明出处:http://www.cnblogs.com/sk ...

  6. Kruskal算法(二)之 C++详解

    本章是克鲁斯卡尔算法的C++实现. 目录 1. 最小生成树 2. 克鲁斯卡尔算法介绍 3. 克鲁斯卡尔算法图解 4. 克鲁斯卡尔算法分析 5. 克鲁斯卡尔算法的代码说明 6. 克鲁斯卡尔算法的源码 转 ...

  7. 加密算法 - RSA算法二

    RSA算法原理(二)  声明: 本文转自阮一峰 (http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html) 有了这些知识, ...

  8. Graham算法—二维点集VC++实现

    一.凸包定义 通俗的说就是:一组平面上的点,求一个包含所有点的最小凸多边形,这个最小凸多边形就是凸包. 二.Graham算法思想 概要:Graham算法的主要思想就是,最终形成的凸包,即包围所有点的凸 ...

  9. python-Day4-迭代器-yield异步处理--装饰器--斐波那契--递归--二分算法--二维数组旋转90度--正则表达式

    本节大纲 迭代器&生成器 装饰器  基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...

  10. 北京地铁换乘算法(二维坐标系,图的深度搜索)开源下载Android源码、性能最优解

    距离2012年11月2日下午2:05:31 已经过去158751270这么多秒了,不小心暴露了我的当前时间. java代码贴出来. private static long gettimelong() ...

随机推荐

  1. 【转】Bloom Filter布隆过滤器的概念和原理

    转自:http://blog.csdn.net/jiaomeng/article/details/1495500 之前看数学之美丽,里面有提到布隆过滤器的过滤垃圾邮件,感觉到何其的牛,竟然有这么高效的 ...

  2. Sprint Three 回顾与总结&发表评论&团队贡献分

    ● 一.回顾与总结 (1)回顾 燃尽图: Sprint计划-流程图: milestones完成情况如下: (2)总结 从sprint one到three,我们团队配合十分默契,互相帮助,虽然遇到了不少 ...

  3. 由node-webkit想到

    本人做为.NET的死忠也有些许年头.微软这几年被谷歌苹果之流打的有点招架不住..NET的前景也难免堪忧.虽然我认为就强类型语言方面,C#绝对是最强者.但是新技术的发展确实是可怕的,看看苹果几年就把no ...

  4. Ubuntu 12.04下解决Tomcat自启动问题

    当我们安装好Tomcat使用后发现,每次启动都需要在终端中手动键入sudo /var/tomcat/bin/startup.sh,那么我们怎么解决这个问题呢 http://hovertree.com/ ...

  5. 消灭Bug!18款最佳的问题跟踪管理应用程序

    摘要:工欲善其事,必先利其器,对于开发者来说,处理Bug是一件比较头疼的事,那么如何高效地解决Bug,选择一款合适的Bug跟踪处理工具会让你事半功倍. 对于开发者来说,Bug往往是他们最头疼的问题.有 ...

  6. ActiveReports 报表应用教程 (7)---交叉报表及数据透视图实现方案

    在 ActiveReports 中可以通过矩阵控件非常方便的实现交叉报表,同时还可以设置数据的分组.排序.过滤.小计.合计等操作,可以满足您报表的智能数据分析等需求.在矩阵控件中组的行数和列数由每个行 ...

  7. 利用jquery实现网页禁止鼠标右键、禁止复制

    很多时候,网站的内容辛苦写法被轻松复制,为了不让自己的劳动成果外流,可以利用禁止鼠标右键等方式保护自己的原创内容! 方式1:禁止鼠标右键操作 <script src="http://l ...

  8. 研究jdk关于TreeMap 红黑树算法实现

    因为TreeMap的实现方式是用红黑树这种数据结构进行存储的,所以呢我主要通过分析红黑树的实现在看待TreeMap,侧重点也在于如何实现红黑树,因为网上已经有非常都的关于红黑树的实现.我也看了些,但是 ...

  9. Eclipse 出现Some sites could not be found. See the error log for more detail.错误 解决方法

    Eclipse 出现Some sites could not be found.  See the error log for more detail.错误 解决方法 Some sites could ...

  10. 【翻译】Netscaler真实表现性能调整

    源地址:https://msandbu.wordpress.com/2014/10/31/netscaler-and-real-performance-tuning/ 作者显然不是以英语为母语的,所以 ...