算法(二)之遗传算法(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. SQL Server 2005 Service Broker

    一.引言 SQL Server 2005 的一个主要成就是可以实现可靠.可扩展且功能完善的数据库应用程序.与 .NET Framework 2.0 公共语言运行库 (CLR) 的集成使开发人员可以将重 ...

  2. ADO.NET完整增删改

    完整增添 删除 修改 运用中间变量运用.bool has=false 1增加 需要使用cmd.Parameters这个集合 占位符: @key 代表这个位置用这个占位符占住了 SqlConnectio ...

  3. 【状态模式】 State Pattern

    我们先设计一个场景,饮料自动售卖机,来设计一下它的出售流程. 流程图中,我们可把这个过程看成几个状态: 投币状态,选择饮料状态,售出状态,出售完毕状态. ,有了这个四个状态,我们设计一下界面(很粗略) ...

  4. 如何理解css中的float

    最近一段时间一直在为一个即将上线的新站进行一些前端开发.自然,对CSS的使用是必不可少的了.我们在CSS 中很多时候会用到浮动来布局.常见的有 float:left 或者 float:right .简 ...

  5. sencha 报错问题汇总

    store的url必填 否则报错:Uncaught TypeError: Cannot read property 'indexOf' of undefined ext-all.js store必须在 ...

  6. C#调用NPOI组件读取excel表格数据转为datatable写入word表格中并向word中插入图片/文字/书签 获得书签列表

    调用word的com组件将400条数据导入word表格中耗时10分钟简直不能忍受,使用NPOI组件耗时4秒钟.但是NPOI中替换书签内容的功能不知道是不支持还是没找到. 辅助类 Excel表格数据与D ...

  7. Jsoup实现java模拟登陆

    Jsoup实现java模拟登陆 2013-10-29 14:52:05|  分类: web开发|举报|字号 订阅     下载LOFTER我的照片书  |     1:如何获取cookies. 1.1 ...

  8. Python迭代器:捕获Generator的返回值

    但是用for循环调用generator时,发现拿不到generator的return语句的返回值.如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的v ...

  9. DirectX 9 SDK安装后在vs2010里编译BaseClasses出错问题解决方法

    打开你的dx的sdk安装目录,例如: D:/DX90SDK/Samples/C++/DirectShow/ 这里就有一个叫baseclasses的工程,为安全起见,请先备份此工程. 1,双击basec ...

  10. 【GOF23设计模式】命令模式

    来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_命令模式.数据库事务机制底层架构实现.撤销和回复 package com.test.command; public cla ...