品鑒同事發來的遺傳算法
阿新 • • 發佈:2018-03-19
get str pri elf list true vol 遺傳算法 rand
<?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;
品鑒同事發來的遺傳算法