用JS简单实现一个群智能算法(布谷鸟搜索算法(CS))

有时我们会遇到一些非凸、不可微、不可导的问题,传统的算法无法解决这些问题。这时,我们可以用群智能算法(比如遗传算法、粒子群算法、布谷鸟算法等等)在符合要求的时间内找到一个近似解,这个解未必是最优解,但足够解决问题了。

群智能算法

群智能算法是一种新兴的演化计算技术,是受到群体生物启发的算法。这里不具体阐述。

布谷鸟算法(CS)

我不再赘述布谷鸟算法,在谷歌学术有大把论文介绍这个算法,在各大博客也有很多文章介绍这个算法。不过基本上都是用MATLAB跑算法。

JS实现CS

我学习CS的时候是用MATLAB写的,JS缺失了大量的方法(即MATLAB中的函数),所以我用了其它方法实现CS,可能会和论文的代码流程不太一致。我试着从0开始写一个算法,为了节约时间就选用了js(js是动态数据类型)。

        function CS(testFunction) {
            //属性,算法参数
            this.NP = 30;
            this.D = 30;
            this.MaxIterations = 10000;
            this.pa = 0.25;

            //方法
            this.getCS = getCS;
            this.getCuckoos = getCuckoos;
            this.emptyNests = emptyNests;
            this.getBestNest = getBestNest;
            this.simplebounds = simplebounds;
            this.benchmarkFunction = testFunction;

            this.nest = [];//合格的种群
            this.newnest = [];//新种群
            this.fitness = [];
            this.LB = []; this.UP = [];
            this.best; this.fmin;

        }
        function getCS(np, d, G, lb, up) {
            //初始化
            this.D = d; this.NP = np; this.MaxIterations = G;
            for (let i = 0; i < this.NP; i++) {
                this.fitness[i] = this.LB * 1000000;
            }
            for (let i = 0; i < this.D; i++) { this.LB[i] = lb };
            for (let i = 0; i < this.D; i++) { this.UP[i] = up };
            for (let i = 0; i < this.NP; i++) {
                this.nest[i] = this.Lb + (this.Ub - this.Lb) * Math.random();
            }
            this.newnest = this.nest;
            this.getBestNest();
            let t = 0;
            while (t < this.MaxIterations) {
                t++;
                this.getCuckoos();
                this.getBestNest();
                this.emptyNests();
                this.getBestNest();
            }
        }
        //全局
        function getCuckoos() {
            beta = 3 / 2;
            //sigma = Math.pow((gamma(1 + beta) * Math.sin(Math.PI * beta / 2) / (gamma((1 + beta) / 2) * beta * Math.pow(2, ((beta - 1) / 2))), (1 / beta));
            //js没有gamma函数,我一下子写不出来,所以用手算的值代替
            sigma = Math.pow((1.3293 * Math.sin(Math.PI * beta / 2) / (1.3293 / 2) * beta * Math.pow(2, ((beta - 1) / 2))), (1 / beta));
            for (let i = 0; i < this.n; i++) {
                let s = this.newnest[i];
                let u = randomNormalSize(0, 1, this.D) * sigma;
                let v = randomNormalSize(0, 1, this.D);
                let step = Math.pow((u / Math.abs(v)), (1 / beta));
                stepsize = 0.01 * step * (s - this.best);
                s = s + stepsize * randomNormalSize(0, 1, this.D);
                this.newnest[i] = simplebounds(s);
            }
        }
        //局部
        function emptyNests() {
            let K = [];
            for (let i = 0; i < this.NP; i++) { K[i] = Math.random() > this.pa ? 0 : 1; }
            let s = this.nest;
            let s1 = s.sort(function () {
                return Math.random() > 0.5 ? -1 : 1
            })
            let s2 = s.sort(function () {
                return Math.random() > 0.5 ? -1 : 1
            })
            let stepsize = Math.random() * (s1 - s2);
            this.newnest = this.nrst + stepsize * K;
            for (let i = 0; i < this.NP; i++) {
                this.newnest[i] = simplebounds(this.newnest[i]);
            }
        }
        //评价
        function getBestNest() {
            let newfit = 1000;
            for (let i = 0; i < this.NP; i++) {
                newfit = this.benchmarkFunction(this.newnest[i]);
                if (newfit < this.fitness[i]) {
                    this.fitness[i] = newfit;
                    this.nest[i] = this.newnest[i];
                }
            }
            let temp = this.fitness[0];
            let t = 0;
            for (let i = 1; i < this.NP; i++) {
                if (this.fitness[i] < temp) {
                    temp = this.fitness[i];
                    t = i;
                }
            }
            this.fmin = temp; this.best = this.nest[t];
        }
        //越界处理
        function simplebounds(s) {
            for(let i in s){
                if(s[i]>this.UP[i]){
                    s[i]=this.UP[i];
                }else if(s[i]<this.LP[i]){
                    s[i]=this.LP[i];
                }
            }
            return s;
        }

        //由于js没有产生正态分布随机数,所以写了这个函数用于产生随机数 normal
        function randomNormal(mean, std) {
            let u = 0.0, v = 0.0, w = 0.0, c = 0.0;
            do {
                //获得两个(-1,1)的独立随机变量
                u = Math.random() * 2 - 1.0;
                v = Math.random() * 2 - 1.0;
                w = u * u + v * v;
            } while (w == 0.0 || w >= 1.0)
            //这里就是 Box-Muller转换
            c = Math.sqrt((-2 * Math.log(w)) / w);
              let random = mean + (u * c) * std;
            return random;
        }
        //用于生产服从正态分布的随机数矩阵
        function randomNormalSize(mean, std, size) {
            let random = [];
            for (let i = 0; i < size; i++) {
                random[i] = randomNormal(mean, std);
            }
            return random;
        }
        //gamma函数
        //如果x为整数,gamma(x)=(x-1)!
        //gamma(x) = integral from 0 to inf of t^(x-1) exp(-t) dt.
        // function gamma(x){
        //没有想好如何用js求积分
			//return gamma;
        // }

        //测试函数
        //计算平方和累加,输入解
        function testFunction(n) {
            let x = 0;
            for (let i in n) {
                x += Math.pow(n[i], 2);
            }
            return x;
        }

        testCs = new CS(testFunction);
        testCs.getCS(30,30,1000,-10,10);
        document.write("The bast value is: ",testCs.fmin);

很多数学工具js没有进行封装,要写原生代码,不太友好,若非必要,可以使用其他语言完成复杂的算法

结果是0,有兴趣的小伙伴可以写其它的测试函数测试一下这个算法。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤影墨客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值