PHP写算法-遗传算法

本文尝试用PHP语言编写遗传算法

遗传算法的具体介绍,请自行搜索,本文也没有完全按照网络上的写法做,作者水平有限,使用的中间算法也都不怎么高明,请各位带着批评看文章。

本文采用的遗传算法步骤
- ①初始种群
- ②淘汰
- ③交叉
- ④变异
- ⑤重建种群并迭代②-④步
- ⑥画图等额外操作

源码地址:https://github.com/kk1987n/GeneticAlgorithmPHP.git

第一节 故事前情与算法梗概

一、故事前情

本文引入某大神关于扇贝的故事,PHP代码大致也是这么写的。
某海滩上有一群扇贝无忧虑的生活着,上帝闲来无事派bob过来用遗传算法整这群扇贝,bob来了之后,给扇贝提了要求:
①你们只能有16个扇贝,每一代我要杀死2个,哪2个贝壳上的图案最不像谷歌浏览器图标我就杀谁;
②剩余的14个中有4个扇贝两两结合生2个孩子,再凑够16个,如此循环;
这些扇贝很是苦恼啊,可是又有什么办法呢,一些扇贝离开了,之后正好留下来16个,就是这些扇贝,创造了后来的chrome扇贝。

二、算法梗概

遗传算法模拟达尔文孟德斯鸠这类神人的遗传学规律,对种群进行筛选,繁殖,变异,如此经过多代,即可培育出那些符合规则的目标。
遗传算法的

第一步 要建立初始种群

初始种群可以是随机建立的,比如故事中最开始的16个扇贝。

第二步 建立淘汰机制

为此我们为扇贝增加一个适应度属性,也就是扇贝背上的图案,与我们的chrome图标有多像;
这里适应度计算标准为,像素点个数*通道数/像素点4通道差值(绝对值)之和S,4通道包含透明通道。
我们使用的是32px*32px的chrome图标,所以适应度F=32*32*4/差值和S。

第三步 淘汰

适应度冒泡排序,最差的2个,unset掉

第四步 交叉

所谓交叉,就是基因组合,就是父亲母亲基因各取一半,组成一个新的扇贝。
经过淘汰之后,还剩下14个,程序千7个选1个,后7个选1个,组合出1个新扇贝(这步循环2次,组成2个新扇贝)。
新扇贝的每个像素点,以50%的几率从父亲或母亲那里获取其像素点的颜色值。

第五步 变异

新扇贝随机选取2个像素点,随机其颜色值

第六步 重建种群

把新扇贝加入到原先的14个扇贝中,组成新的1代。

第二节 类设计

一、颜色类color

包含4个属性rgba

namespace Ga\Pix\base;
/**
 * 颜色点<br>
 * 包含四个数学,r:红色,g:绿色,b:蓝色,a:透明度
 * @author Linko
 * @email [email protected]
 * @link https://github.com/kk1987n/GeneticAlgorithmPHP.git
 * @date 2018/04/24
 */
class Color {

    public $r;
    public $g;
    public $b;
    public $a;

    public function __construct($rgba = array()) {
        if (empty($rgba)) {
            $this->setRand();
        } else {
            $this->r = $rgba[0];
            $this->g = $rgba[1];
            $this->b = $rgba[2];
            $this->a = $rgba[3];
        }
    }

    /**
     * 设置随机值
     * @return type
     */
    public function setRand() {
        $this->r = rand(0, 255);
        $this->g = rand(0, 255);
        $this->b = rand(0, 255);
        $this->a = rand(0, 127);
        return array($this->r, $this->g, $this->b, $this->a);
    }

    /**
     * 适应率公式,像素点差额的和
     * 当前像素与对比像素之间的差别
     * @param type $Pix
     * @return type
     */
    public function fitness(Color $Pix) {
        $r = abs($this->r - $Pix->r);
        $g = abs($this->g - $Pix->g);
        $b = abs($this->b - $Pix->b);
        $a = abs($this->a - $Pix->a);
        return $r + $g + $b + $a * 2;
    }

}

二、扇贝类Scallop

包含32*32个颜色对象,扇贝的适应度,扇贝的代数和名字,基因变异次数,以及要对比的基础图像信息。


namespace Ga\Pix\base;

use Ga\Pix\Config;

/**
 * 扇贝,一个扇贝包含多个颜色点,这些颜色点属于扇贝的基因
 * @author Linko
 * @email [email protected]
 * @link https://github.com/kk1987n/GeneticAlgorithmPHP.git
 * @date 2018/04/24
 */
class Scallop {

    public $pixs = array(); //扇贝上的像素点
    public $fitness; //当前扇贝的适应度
    public $generation; //扇贝第几代
    public $scpName; //扇贝的名字,每一个扇贝都有唯一的名字,用数字标识
    public $variationCnt; //基因变异个数
    public $baseImgPixs; //基础图片
    public $baseImgWidth; //基础图片宽度
    public $baseImgHeight; //基础图片高度

    public function __construct($Generation, $scpName = 0, $baseImgWidth = 0, $baseImgHeight = 0) {
    }


    /**
     * 初始化当前扇贝
     * 分两步
     * 1、创建扇贝每个像素点的颜色值
     * 2、计算当前扇贝的fitness(适应度)
     */
    public function initScp() {
        for ($x = 0; $x < $this->baseImgHeight; $x++) {
            for ($y = 0; $y < $this->baseImgWidth; $y++) {
                $this->pixs[$x][$y] = new Color();
            }
        }
        $this->calFitness();
    }

    /**
     * 计算适应率
     * 像素数*通道数/像素通道差额和
     * @return int
     */
    public function calFitness() {
    }

    /**
     * 杂交
     * 此处杂交父母基因各区50%概率
     * @param Scallop $scpA
     * @param Scallop $scpB
     * @return boolean
     */
    public function createScpByParent(Scallop $scpA, Scallop $scpB) {
    }

    /**
     * 变异
     * 根据变异像素数,为随机点设置新的颜色
     * @return boolean
     */
    public function variation() {
    }

    /**
     * 画出当前扇贝
     * 到文件
     * @return type
     */
    public function drawScp() {}

}

三、种群类Population

包含当前第几代,基础图片信息,种群内扇贝数等很多信息,种群进行了循环迭代


namespace Ga\Pix\base;

use Ga\Pix\base\Scallop;
use Ga\Pix\Config;

/**
 * 这是一个种群<br>
 * 这是1个种群,种群内包含多个扇贝
 * 
 * @author Linko
 * @email [email protected]
 * @link https://github.com/kk1987n/GeneticAlgorithmPHP.git
 * @date 2018/04/24
 */
class Population {

    public $baseImgPixs; //基础对比图
    public $baseImgWidth; //基础图宽度
    public $baseImgHeight; //基础图高度
    public $scallops = array(); //扇贝
    public $scpCnt; //种群内扇贝的数量
    public $chdCnt; //每次迭代产生的孩子数量
    public $generation; //当前是第几代
    public $scpName = 1; //创建的扇贝的名字,每一个扇贝都有唯一的名字,用数字标识
    public $fitness = array(); //适应度-用来画曲线

    public function __construct($Generation = 1) {
    }

    /**
     * 初始种群,最开始的随机种群,这是第一代种群
     */
    public function initPop() {
    }

    /**
     * 代数迭代
     */
    public function start() {
        for ($x = 0; $x < Config::GenerationMaX; $x++) {
            echo $this->generation . PHP_EOL;
            $this->generation++;
            $this->killScp(); //杀死原种群中适应度最差的几个,补充上孩子
            $children = $this->birthChild(); //结合生出孩子
            $this->addToScp($children);
            $this->calFitness(); //计算适应度总和
            if ($this->generation % Config::drawByCnt == 0) {
                foreach ($this->scallops as $scp) {
                    $scp->drawScp();
                }
            }
        }
    }

    /**
     * 生小孩
     */
    public function birthChild() {
    }

    /**
     * 交叉扇贝
     */
    public function crossScp(Scallop $scpA, Scallop $scpB) {
    }

    /**
     * 杀死较差的扇贝
     */
    public function killScp() {
    }


    /**
     * 把没被杀死的父辈,和孩子合起来
     * @param type $children
     */
    public function addToScp($children) {
    }
}

这三个类组成了程序的核心部分,其余都是辅助类,包括加载机制,入口文件,分发器等等。。。

几张效果图

一万代适应度曲线
1万代适应度曲线
1万代生成的效果图
1万代生成的效果图
一百万代适应度曲线
100万代适应度曲线
100万代生成的效果图
100万代生成的效果图(太多了,只看后边的了。)

源码地址:https://github.com/kk1987n/GeneticAlgorithmPHP.git
转载请注明:阿鑫-PHP写算法

猜你喜欢

转载自blog.csdn.net/kk1946n/article/details/80094185