需求:求解函数 f(x) = x + 10*sin(5*x) + 7*cos(4*x) 在区间[0,9]的最大值。
 <?php
/*
需求:求解函数 f(x) = x + 10*sin(5*x) + 7*cos(4*x) 在区间[0,9]的最大值。 以我们的目标函数 f(x) = x + 10sin(5x) + 7cos(4x), x∈[0,9] 为例。
假如设定求解的精度为小数点后4位,可以将x的解空间划分为 (9-0)×(1e+4)=90000个等分。
2^16<90000<2^17,需要17位二进制数来表示这些解。换句话说,一个解的编码就是一个17位的二进制串。
一开始,这些二进制串是随机生成的。
一个这样的二进制串代表一条染色体串,这里染色体串的长度为17。
对于任何一条这样的染色体chromosome,如何将它复原(解码)到[0,9]这个区间中的数值呢? 对于本问题,我们可以采用以下公式来解码:x = 0 + decimal(chromosome)×(9-0)/(2^17-1) */
header("Content-Type:text/html;CharSet=UTF-8");
//初始化参数
$elitism = true; //是否精英选择
$population_size = 100; //种群大小
$chromosome_size = 17; //染色体长度
$generation_size = 200; //最大迭代次数
$cross_rate = 0.6; //交叉概率
$mutate_rate = 0.01; //变异概率 //初始化对象,执行算法
$ga_object = new GAEngine($population_size, $chromosome_size, $generation_size, $cross_rate, $mutate_rate, $elitism); $res = $ga_object->run(); //打印结果
echo "迭代{$generation_size}代,最佳个体如下<br>"; echo "染色体:{$res['m']}<br>";
echo "对应的X:{$res['q']}<br>";
echo "结果:{$res['n']}<br>";
echo "最佳个体出现的代:【{$res['p']}】<br>"; //遗传算法主要部分
class GAEngine
{
//初始化参数
public $elitism; //是否精英选择
public $population_size; //种群大小
public $chromosome_size; //染色体长度
public $generation_size; //最大迭代次数
public $cross_rate; //交叉概率
public $mutate_rate; //变异概率 //全局参数
public $G; //当前迭代次数
public $fitness_value; //当前代适应度矩阵
public $best_fitness; //历代最佳适应值
public $fitness_sum; //前i个个体的适应度之和
public $fitness_average; //历代平均适应值矩阵
public $best_individual; //历代最佳个体
public $best_generation; //最佳个体出现代
public $upper_bound = 9; //自变量的区间上限
public $lower_bound = 0; //自变量的区间下限 //对象
public $population_obj; //种群对象 public $populations; //种群数组 //初始化
public function __construct($population_size, $chromosome_size, $generation_size, $cross_rate, $mutate_rate, $elitism)
{
$this->elitism = $elitism;
$this->population_size = $population_size;
$this->chromosome_size = $chromosome_size;
$this->generation_size = $generation_size;
$this->cross_rate = $cross_rate;
$this->mutate_rate = $mutate_rate; //初始化种群
$this->population_obj = new Populations($population_size, $chromosome_size); } //【执行,返回结果】
public function run(){
//初始化种群
$this->populations = $this->population_obj->initPop(); //开始迭代
for($i = 1; $i < $this->generation_size; $i ++){
$this->G = $i;
$this->fitness(); //计算适应度
$this->rank(); //对个体按适应度大小进行排序
$this->selection();//选择操作
$this->crossover(); //交叉操作
$this->mutation(); //变异操作
} //最后,求出二进制基因对应的实数x,以及求出实数对应的结果
$x = $this->upper_bound - bindec($this->best_individual)*($this->upper_bound - $this->lower_bound)/(pow(2, $this->chromosome_size) - 1); return [
'm' => $this->best_individual, //最佳个体
'n' => $this->best_fitness, //最佳适应度
'p' => $this->best_generation, //最佳个体出现的代
'q' => $x //最佳个体基因对应的实数
]; } //【计算适应度】
public function fitness(){
//所有个体适应度初始化为0
//遍历每个个体的基因,求出对应的实数,然后再计算出结果,即适应度
for($i = 0; $i < $this->population_size; $i ++){
// $gens = strrev($this->populations[$i]['gens']);//染色体字符串与实际的自变量x二进制串顺序是相反的
$x = $this->upper_bound - bindec($this->populations[$i]['gens'])*($this->upper_bound - $this->lower_bound)/(pow(2, $this->chromosome_size) - 1); $fx = $x + 10*sin(5*$x) + 7*cos(4*$x);//函数值 $this->fitness_value[$i] = $fx; }
} //【排序】
//对个体按适应度的大小进行排序,并且保存最佳个体
public function rank(){
//$this->fitness_value[] 保存适应度的数组,根据此数组进行排序,还要修改对应个体的位置
//冒泡,从小到大排序
for($i = 0; $i < $this->population_size -1; $i ++){
for($j = $i + 1; $j < $this->population_size; $j ++){
if($this->fitness_value[$i] > $this->fitness_value[$j]){
//交换适应度
$tmp = $this->fitness_value[$i];
$this->fitness_value[$i] = $this->fitness_value[$j];
$this->fitness_value[$j] = $tmp; //交换种群个体位置
$tmp = $this->populations[$i];
$this->populations[$i] = $this->populations[$j];
$this->populations[$j] = $tmp;
}
}
} //计算前i个给个体的适应度之和
$fitness_sum[0] = $this->fitness_value[0];
for($i = 1; $i < $this->population_size; $i ++){
$fitness_sum[$i] = $fitness_sum[$i - 1] +$this->fitness_value[$i];
}
$this->fitness_sum = $fitness_sum; //第G代迭代, 个体的平均适应度
$this->fitness_average[$this->G] = ($fitness_sum[$this->population_size - 1] / $this->population_size); //更新最大适应度和对应的迭代次数,保存最佳个体(最佳个体适应度最大)
if($this->fitness_value[$this->population_size - 1] > $this->best_fitness){
$this->best_fitness = $this->fitness_value[$this->population_size - 1];
$this->best_generation = $this->G;
$this->best_individual = $this->populations[$this->population_size -1]['gens'];
} } //【选择】
public function selection(){
$population_new = [];//保存被选中的个体 //二分查找实现轮盘赌功能
for($i = 0; $i < $this->population_size; $i ++){
$r = (rand(0,10)/10 ) * $this->fitness_sum[$this->population_size - 1];//生成一个随机数,在[0,总适应度] 之间
$first = 1;
$last = $this->population_size;
$mid = round( ($last + $first) / 2 );
$idx = -1; //排中法选择个体
while(($first <= $last) && ($idx == -1)){
if($r > $this->fitness_sum[$mid]){
$first = $mid;
}elseif ( $r < $this->fitness_sum[$mid]){
$last = $mid;
}else{
$idx = $mid;
break;
}
$mid = round( ($last + $first) / 2 );
if(($last - $first) == 1){
$idx = $last;
break;
} } //产生新的个体
//echo $idx.'=';
$population_new[$i]['gens'] = $this->populations[$idx]['gens'];
} //是否精英选择
if($this->elitism){
$p = $this->population_size - 1;
}else{
$p = $this->population_size;
} for($i = 0; $i < $p; $i ++){
if(isset($population_new[$i]))
$this->populations[$i] = $population_new[$i];
} } //【交叉】
public function crossover(){
//步长为2, 遍历种群
for($i = 0; $i < $this->population_size; $i+=2){
//rand < 交叉概率,对2个个体的染色体进行交叉操作
$r = $this->randFloat();//产生0~1的随机数
if($r < $this->cross_rate){
// $r =$this->randFloat();
// $cross_pos = round($r * $this->chromosome_size);
$cross_pos = rand(0, $this->chromosome_size);
if($cross_pos ==0 || $cross_pos == $this->chromosome_size)
continue;
//对 cross_pos及之后的二进制串进行交换
$x = $this->populations[$i]['gens'];
$y = $this->populations[$i+1]['gens'];
$tmp1 = substr($x,0, $cross_pos).substr($y,$cross_pos);
$tmp2 = substr($y,0,$cross_pos).substr($x, $cross_pos); $this->populations[$i]['gens'] = $tmp1;
$this->populations[$i+1]['gens'] = $tmp2;
}
}
} //【变异】
public function mutation(){
for($i =0; $i < $this->population_size; $i ++){
if($this->randFloat() < $this->mutate_rate){
$mutate_pos = rand(0,$this->chromosome_size -1);
$this->populations[$i]['gens'][$mutate_pos] = 1 - $this->populations[$i]['gens'][$mutate_pos];
} }
} public function show($data){
echo '<pre>';
var_dump($data);
echo '<hr>';
} //随机产生0-1的小数
function randFloat($min=0, $max=1){
return $min + mt_rand()/mt_getrandmax() * ($max-$min);
} } //种群
class Populations
{
public $population_size;//种群大小
public $chromosome_size;//染色体长度 //初始化参数
public function __construct($population_size, $chromosome_size)
{
$this->population_size = $population_size;
$this->chromosome_size = $chromosome_size;
} //初始化种群
public function initPop(){
$pop = [];
for($i = 0; $i < $this->population_size; $i ++){
for($j = 0; $j < $this->chromosome_size; $j ++){
$pop[$i]['gens'] .= rand(0, 10) % 2;//产生1-0随机数
}
} return $pop;
} }

参考:

  知乎:https://www.zhihu.com/question/23293449

  MATLAB的实现GitHub地址:https://github.com/yanshengjia/artificial-intelligence/tree/master/genetic-algorithm-for-functional-maximum-problem

附录:把个体单独抽出来放到一个类中

 <?php
/*
需求:求解函数 f(x) = x + 10*sin(5*x) + 7*cos(4*x) 在区间[0,9]的最大值。 以我们的目标函数 f(x) = x + 10sin(5x) + 7cos(4x), x∈[0,9] 为例。
假如设定求解的精度为小数点后4位,可以将x的解空间划分为 (9-0)×(1e+4)=90000个等分。
2^16<90000<2^17,需要17位二进制数来表示这些解。换句话说,一个解的编码就是一个17位的二进制串。
一开始,这些二进制串是随机生成的。
一个这样的二进制串代表一条染色体串,这里染色体串的长度为17。
对于任何一条这样的染色体chromosome,如何将它复原(解码)到[0,9]这个区间中的数值呢? 对于本问题,我们可以采用以下公式来解码:x = 0 + decimal(chromosome)×(9-0)/(2^17-1) */
header("Content-Type:text/html;CharSet=UTF-8");
//初始化参数
$elitism = true; //是否精英选择
$population_size = 100; //种群大小
$chromosome_size = 17; //染色体长度
$generation_size = 200; //最大迭代次数
$cross_rate = 0.6; //交叉概率
$mutate_rate = 0.01; //变异概率 //初始化对象,执行算法
$ga_object = new GAEngine($population_size, $chromosome_size, $generation_size, $cross_rate, $mutate_rate, $elitism); $res = $ga_object->run(); //打印结果
echo "迭代{$generation_size}代,最佳个体如下<br>"; echo "染色体:{$res['m']}<br>";
echo "对应的X:{$res['q']}<br>";
echo "结果:{$res['n']}<br>";
echo "最佳个体出现的代:【{$res['p']}】<br>"; //遗传算法主要部分
class GAEngine
{
//初始化参数
public $elitism; //是否精英选择
public $population_size; //种群大小
public $chromosome_size; //染色体长度
public $generation_size; //最大迭代次数
public $cross_rate; //交叉概率
public $mutate_rate; //变异概率 //全局参数
public $G; //当前迭代次数
public $fitness_value; //当前代适应度矩阵
public $best_fitness; //历代最佳适应值
public $fitness_sum; //前i个个体的适应度之和
public $fitness_average; //历代平均适应值矩阵
public $best_individual; //历代最佳个体
public $best_generation; //最佳个体出现代
public $upper_bound = 9; //自变量的区间上限
public $lower_bound = 0; //自变量的区间下限 //对象
public $population_obj; //种群对象 public $populations; //种群数组 //初始化
public function __construct($population_size, $chromosome_size, $generation_size, $cross_rate, $mutate_rate, $elitism)
{
$this->elitism = $elitism;
$this->population_size = $population_size;
$this->chromosome_size = $chromosome_size;
$this->generation_size = $generation_size;
$this->cross_rate = $cross_rate;
$this->mutate_rate = $mutate_rate; //初始化种群
$this->population_obj = new Populations($population_size, $chromosome_size); } //【执行,返回结果】
public function run(){
//初始化种群
$this->populations = $this->population_obj->initPop(); //开始迭代
for($i = 1; $i <= $this->generation_size; $i ++){
$this->G = $i;
$this->fitness(); //计算适应度
$this->rank(); //对个体按适应度大小进行排序
$this->selection();//选择操作
$this->crossover(); //交叉操作
$this->mutation(); //变异操作
} //最后,求出二进制基因对应的实数x,以及求出实数对应的结果
$x = $this->upper_bound - bindec($this->best_individual)*($this->upper_bound - $this->lower_bound)/(pow(2, $this->chromosome_size) - 1); return [
'm' => $this->best_individual, //最佳个体
'n' => $this->best_fitness, //最佳适应度
'p' => $this->best_generation, //最佳个体出现的代
'q' => $x //最佳个体基因对应的实数
]; } //【计算适应度】
public function fitness(){
//所有个体适应度初始化为0
//遍历每个个体的基因,求出对应的实数,然后再计算出结果,即适应度
for($i = 0; $i < $this->population_size; $i ++){
// $gens = strrev($this->populations[$i]['gens']);//染色体字符串与实际的自变量x二进制串顺序是相反的
$x = $this->upper_bound - bindec($this->populations[$i]->chromosomes)*($this->upper_bound - $this->lower_bound)/(pow(2, $this->chromosome_size) - 1); $fx = $x + 10*sin(5*$x) + 7*cos(4*$x);//函数值 // $this->fitness_value[$i] = $fx;
$this->populations[$i]->fitness = $fx; }
} //【排序】
//对个体按适应度的大小进行排序,并且保存最佳个体
public function rank(){
//冒泡,从小到大排序
for($i = 0; $i < $this->population_size -1; $i ++){
for($j = $i + 1; $j < $this->population_size; $j ++){
if($this->populations[$i]->fitness > $this->populations[$j]->fitness){
//交换个体
$tmp = $this->populations[$i];
$this->populations[$i] = $this->populations[$j];
$this->populations[$j] = $tmp;
}
}
} //计算前i个给个体的适应度之和
$fitness_sum[0] = $this->populations[0]->fitness;
for($i = 1; $i < $this->population_size; $i ++){
$fitness_sum[$i] = $fitness_sum[$i - 1] + $this->populations[$i]->fitness;
}
$this->fitness_sum = $fitness_sum; //第G代迭代, 个体的平均适应度
$this->fitness_average[$this->G] = ($fitness_sum[$this->population_size - 1] / $this->population_size); //更新最大适应度和对应的迭代次数,保存最佳个体(最佳个体适应度最大)
if($this->populations[$this->population_size - 1]->fitness > $this->best_fitness){
$this->best_fitness = $this->populations[$this->population_size - 1]->fitness;
$this->best_generation = $this->G;
$this->best_individual = $this->populations[$this->population_size -1]->chromosomes;
} } //【选择】
public function selection(){
$population_new = [];//保存被选中的个体 //二分查找实现轮盘赌功能
for($i = 0; $i < $this->population_size; $i ++){
$r = (rand(0,10)/10 ) * $this->fitness_sum[$this->population_size - 1];//生成一个随机数,在[0,总适应度] 之间
$first = 1;
$last = $this->population_size;
$mid = round( ($last + $first) / 2 );
$idx = -1; //排中法选择个体
while(($first <= $last) && ($idx == -1)){
if($r > $this->fitness_sum[$mid]){
$first = $mid;
}elseif ( $r < $this->fitness_sum[$mid]){
$last = $mid;
}else{
$idx = $mid;
break;
}
$mid = round( ($last + $first) / 2 );
if(($last - $first) == 1){
$idx = $last;
break;
} } //产生新的个体
//echo $idx.'=';
$population_new[$i] = $this->populations[$idx];
} //是否精英选择
if($this->elitism){
$p = $this->population_size - 1;
}else{
$p = $this->population_size;
} for($i = 0; $i < $p; $i ++){
if(isset($population_new[$i]))
$this->populations[$i] = $population_new[$i];
} } //【交叉】
public function crossover(){
//步长为2, 遍历种群
for($i = 0; $i < $this->population_size; $i+=2){
//rand < 交叉概率,对2个个体的染色体进行交叉操作
$r = $this->randFloat();//产生0~1的随机数
if($r < $this->cross_rate){
// $r =$this->randFloat();
// $cross_pos = round($r * $this->chromosome_size);
$cross_pos = rand(0, $this->chromosome_size);
if($cross_pos ==0 || $cross_pos == $this->chromosome_size)
continue;
//对 cross_pos及之后的二进制串进行交换
$x = $this->populations[$i]->chromosomes;
$y = $this->populations[$i+1]->chromosomes;
$tmp1 = substr($x,0, $cross_pos).substr($y,$cross_pos);
$tmp2 = substr($y,0,$cross_pos).substr($x, $cross_pos); $this->populations[$i]->chromosomes = $tmp1;
$this->populations[$i+1]->chromosomes = $tmp2;
}
}
} //【变异】
public function mutation(){
for($i =0; $i < $this->population_size; $i ++){
if($this->randFloat() < $this->mutate_rate){
$mutate_pos = rand(0,$this->chromosome_size -1);
$this->populations[$i]->chromosomes[$mutate_pos] = 1 - $this->populations[$i]->chromosomes[$mutate_pos];
} }
} public function show($data){
echo '<pre>';
var_dump($data);
echo '<hr>';
} //随机产生0-1的小数
function randFloat($min=0, $max=1){
return $min + mt_rand()/mt_getrandmax() * ($max-$min);
} } //种群
class Populations
{
public $population_size;//种群大小
public $chromosome_size;//染色体长度 //初始化参数
public function __construct($population_size, $chromosome_size)
{
$this->population_size = $population_size;
$this->chromosome_size = $chromosome_size;
} //初始化种群
public function initPop(){
$pop = [];
for($i = 0; $i < $this->population_size; $i ++){
$pop[] = new Individuals($this->chromosome_size);
} return $pop;
}
} //个体
class Individuals
{
public $chromosomes; //染色体
public $fitness; //适应度
public $value; //实数 public $chromosome_size; public function __construct($chromosome_size)
{
$this->chromosome_size = $chromosome_size; for($j = 0; $j < $this->chromosome_size; $j ++){
$this->chromosomes .= rand(0, 10) % 2;//产生1-0随机数
}
} }

[PHP] 遗传算法求函数最大值一般实现的更多相关文章

  1. hdu 5105 求函数极值 函数求导/三分法

    http://acm.hdu.edu.cn/showproblem.php?pid=5105 给定a,b,c,d,l,r,表示有一个函数f(x)=|a∗x3+b∗x2+c∗x+d|(L≤x≤R),求函 ...

  2. java从键盘输入若干数,求其最大值,最小值,平均值。等等

    总结:有一定基础的人,应该发现第一个程序可以运行,其实它有个致命的错误.有谁能一眼看出来呢?第二个程序是对的. 这个题目求最大值,最小值,平均值我不会求,不知道这个if判断放在类的外面还是main函数 ...

  3. 求int最大值以及int二进制

    求int最大值:(((unsigned int)(~0))>>1) 求int的2进制串 string str = ""; int iNum = 100; for(int ...

  4. //给定N个整数序列{A1,A2,A3...An},求函数f(i,j)=(k=i~j)Ak的求和

    //给定N个整数序列{A1,A2,A3...An},求函数f(i,j)=(k=i~j)Ak的求和 # include<stdio.h> void main() { ,sum1; ]={,- ...

  5. Problem J: 求个最大值

    Problem J: 求个最大值 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 871  Solved: 663[Submit][Status][Web ...

  6. HDU - 1754 I Hate It (线段树单点修改,求区间最大值)

    很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老师有 ...

  7. 【Java例题】2.4求函数

    4.输入x,编程试求函数 y=sin(x^2)/(1-cosx)的值. 这里的"^"表示乘方. package study; import java.util.Scanner; p ...

  8. noi.openjudge 二分法求函数的零点

    二分法求函数的零点 总时间限制: 1000ms 内存限制: 65536kB 描述 有函数:f(x) = x5 - 15 * x4+ 85 * x3- 225 * x2+ 274 * x - 121 已 ...

  9. HDU1166(线段树 +更新单点,求区间总和)、HDU1754(线段树 + 更新单点,求区间最大值)

    线段树简单应用 先附上几张图便与理解,大佬文章传送门1.传送门2 HDU1166:题目描述 线段树 +更新单点,求区间总和 代码如下(递归版) #include<iostream> #in ...

随机推荐

  1. java练习---8

    //程序员:罗元昊 2017.10.16 题目3.7 import java.util.Scanner; public class L { @SuppressWarnings("resour ...

  2. shiro解析ini文件

    来吧,看看shiro是怎么解析ini文件的,这里假设ini文件在classpath下,名字叫做shiro.ini Factory<org.apache.shiro.mgt.SecurityMan ...

  3. gulp压缩js文件报错日志

    输出 gulp-uglify 压缩js文件时报错信息 gulp.task('es6', function () { return gulp.src('src/main/webapp/bower_com ...

  4. 前端工程师和设计师必备的chrome插件

    Google Chrome是最好用的几个浏览器之一,今天我来分享下自己收集的一系列Chrome插件,希望对大家的学习和工作有帮助. 注:你可以通过复制链接或者在谷歌商店搜索相应插件的名称来获取以下插件 ...

  5. [ PyQt入门教程 ] PyQt5基本控件使用:单选按钮、复选框、下拉框

    本文主要介绍PyQt5界面最基本使用的单选按钮.复选框.下拉框三种控件的使用方法进行介绍. 1.RadioButton单选按钮/CheckBox复选框.需要知道如何判断单选按钮是否被选中. 2.Com ...

  6. WPF后台设置颜色字体等

    Button TempButton = new Button();                                                TempButton.Tag = “按 ...

  7. Spring aop 影响本地事务的回滚总结

    1  @Before   不会,因为还没执行到service的业务逻辑 2  @ After    默认情况下,报错会影响事务回滚., 当设置@Order属性并设置值优先级大小, 即使报错也不会回滚了 ...

  8. 4如何用PHP给MySQL数据库添加记录

    首先连接数据库(依旧用第二篇的方法) 假设数据库表里只有id,name,email三列 添加以下代码 $inputemail=写你要的email;$inputname=写你要的name;//先设定你要 ...

  9. 数据结构之堆栈C++版

    /* 堆栈本身就是一种线性数据结构,说白了他与容器线性表是一种数据类型,不要认为他多高大上. 实时上他还没有线性表复杂,下面简单的实现一下堆栈. 事实上整个核心操作都是在操作指向堆栈的顶部元素的指针 ...

  10. Django中自定义admin---Xadmin的实现

    在Django框架中,自带一个后台管理页面admin,这个管理页面很全,但是,有些并不是我们需要的,所以我们可以根据admin的实现流程来自定义自己的需求,即根据admin的实现方式来实现自定制--X ...