<?php
class GA{
public static $length ;
public static $count;
public static $population;
/**
* GA constructor.
* @param $length
* @param $count
* 长度
* 生成的数量
*/
public function __construct($length,$count){
self::$length = $length;
self::$count = $count;
self::$population = self::gen_population($length,$count);
}
public static function gen_population($length, $count){
$population = [];
for($i=0;$i<$count;$i++){
$population[] = self::gen_chromosome($length);
}
return $population;
}
public static function gen_chromosome($length){
$str = 0;
for($i=0;$i<$length;$i++){
$str |=(1<<$i)*mt_rand(0,1);
}
return $str;
}
/**
* @param float $retain_rate
* @param float $random_select_rate
* @param float $mutation_rate
* 进化
*/
public function evolve($retain_rate = 0.2,$random_select_rate = 0.5,$mutation_rate = 0.01){
$parents = self::selection($retain_rate,$random_select_rate);
self::crossover($parents);
self::mutation($mutation_rate);
}
/**
* @param $retain_rate
* @param $random_select_rate
* @return array
* 选择
*/
public static function selection($retain_rate, $random_select_rate){
$graded = [];
foreach(self::$population as $v){
$graded[] = [self::fitness($v),$v];
}
rsort($graded);
$graded = array_column($graded,1);
$retain_length = intval(count($graded)*$retain_rate);
$parents = array_slice($graded,0,$retain_length);
foreach(array_slice($graded,$retain_length,count($graded)-$retain_length) as $v){
//lcg_value()随机生成0-1浮点数
if(lcg_value() < $random_select_rate){
$parents[] = $v;
}
}
return $parents;
}
public static function fitness($chromosome){
$x = self::decode($chromosome);
return $x + 10*sin(5*$x) + 7*cos(4*$x);
}
public static function decode($chromosome){
return $chromosome * 9.0 / (pow(2,self::$length)-1);
}
/**
* @param $parents
* 交叉
*染色体的交叉、繁殖,生成新一代的种群
*/
public static function crossover($parents){
//新出生的孩子,最终会被加入存活下来的父母之中,形成新一代的种群。
$children = [];
//需要繁殖的孩子的量
$target_count = count(self::$population)-count($parents);
while(count($children) < $target_count){
$male = rand(0,count($parents)-1);
$female = rand(0,count($parents)-1);
if($male != $female){
$cross_pos = rand(0,self::$length);
//生成掩码,方便位操作
$mask = 0;
for($i=0;$i<$cross_pos;$i++){
$mask |= (1<<$i);
}
$male = $parents[$male];
$female = $parents[$female];
$child = (($male & $mask) | ($female & ~$mask)) & ((1<<self::$length)-1);
$children[] = $child;
}
}
self::$population = array_merge($parents,$children);
}
/**
* @param $rate
* 变异
* 对种群中的所有个体,随机改变某个个体中的某个基因
*/
public static function mutation($rate){
foreach(self::$population as $k => $v){
if(lcg_value() < $rate){
$j = rand(0,self::$length-1);
self::$population[$k] ^= 1 << $j;
}
}
}
public function result(){
foreach(self::$population as $v){
$graded[] = [self::fitness($v),$v];
}
rsort($graded);
$graded = array_column($graded,1);
return self::decode($graded[0]);
}
public static function println($data){
echo "<br>".$data."<br>";
}
}
if(!function_exists("array_column"))
{
function array_column($array=array(),$value="",$key="",$key_prefix="")
{
//模拟实现PHP5.5的array_column
$list=array();//初始化返回数组
$is_need_all=$value==="*";//是否需要获取整个数组
$is_need_key=$key!=="";//是否需要key
if($is_need_key)
{
//说明有key 直接取当前遍历的 value 字段 或者当前遍历元素
$key=$key_prefix.$key;//拼接前缀
foreach($array as $v)
{
$tmp= $is_need_all ? $v : (isset($v[$value])?$v[$value]:"");
$list[$v[$key]]=$tmp;
}
}
else
{
//说明没有key直接把数组元素返回到数组中去
foreach($array as $v)
{
$tmp= $is_need_all ? $v : (isset($v[$value])?$v[$value]:"");
$list[]=$tmp;
}
}
return $list;
}
}
$t1 = microtime(true);
$ga = new GA(17,100);
for($i=1;$i<=100;$i++){
$ga->evolve();
}
//var_dump($ga::$population);
echo $ga->result()."<br>";
$t = microtime(true)-$t1;
echo "time:".$t;