品鉴同事发来的遗传算法

<?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;

 

posted @ 2018-03-19 15:02  李照耀  阅读(161)  评论(0编辑  收藏  举报