算法(二)之遗传算法(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. EF封装类 增加版,增加从缓存中查找数据方法,供参考!

    EF封装类 增加版,增加从缓存中查找数据方法,供参考! 这个类是抽象类,我这里增加了需要子类验证的方法ValidateEntity,方便扩展,若想直接使用该类,可以将该类更改成静态类,里面所有的方法都 ...

  2. Sprint第三个冲刺(第七天)

    项目基本上可以说完成了,只是还有些小bug要修复.

  3. ok6410 android driver(10)

    From this essay, we go to a new discussion "Android Hardware Abstraction Layer". In this e ...

  4. thread_fork/join并发框架2

    转自  http://blog.csdn.net/mr_zhuqiang/article/details/48300229 三.使用异步方式 invokeAll(task1,task2); 是同步方式 ...

  5. 在Winform开发框架中实现对数据库的加密支持

    在很多情况下,我们需要对数据库进行加密,特别是Access数据库.Sqlite数据库,这些直接部署在客户端的数据,因为数据也是客户的资产,数据库总是存在很多相关的秘密或者重要的业务数据,所以一般来说, ...

  6. Unity3D入门基本概念整理

    1. (1)在场景中添加资源 只需单击工程视图 (Project View) 中的网格(Mesh)并拖动至层级视图 (Hierarchy) 或场景视图 (Scene View),便可将其添加至场景 ( ...

  7. 用javascript去掉字符串空格的办法

    今天遇到了以关于JavaScript 中怎么去掉 字符串中前后两段的空格 ,我只好向就得js中也后Trim() 函数,后来试试了不 行,就网上找了下解决方法,其中用到了正则表达式 ,整理了下: < ...

  8. C#组态控件Iocomp应用案例

    Iocomp组件需要在vs2010环境下使用,目前用到的是4.04版本.在两个项目中用到了它,一个是锅炉监控系统,另一个是绝缘靴检测系统. 锅炉监测系统 这个节目基本都是使用Iocomp控件完成. 出 ...

  9. 004_URL 路由 - 定制路由系统 & 使用区域

    定制路由系统 路由系统是灵活可配置的,当然还可以通过下面这两种方式定制路由系统,来满足其他需求. 1.  通过创建自定义的RouteBase实现: 2.  通过创建自定义路由处理程序实现. 创建自定义 ...

  10. 【jQuery基础学习】08 编写自定义jQuery插件

    目的:虽然jQuery各种各样的功能已经很完善了,但是我们还是要学会自己去编写插件.这样我们可以去封装一些项目中经常用到的专属的代码,以便后期维护和提高开发效率. jQuery插件的类型: 封装对象方 ...