最优化算法之粒子群算法PSO

基本概念

粒子群算法(PSO)属于群智能算法的一种,1995 年由Eberhart 博士和kennedy 博士提出,源于对鸟群捕食的行为研究。该算法是通过模拟鸟群捕食行为设计的。假设区域里就只有一块食物(即通常优化问题中所讲的最优解),鸟群的任务是找到这个食物源。鸟群在整个搜寻的过程中,通过相互传递各自的信息,让其他的鸟知道自己的位置,通过这样的协作,来判断自己找到的是不是最优解,同时也将最优解的信息传递给整个鸟群,最终,整个鸟群都能聚集在食物源周围,即我们所说的找到了最优解,即问题收敛。
粒子群算法具有收敛速度快、参数少、算法简单易实现的优点(对高维度优化问题,比遗传算法更快收敛于最优解),但是也会存在陷入局部最优解的问题。

基本原理

位置和速度

粒子群算法通过设计一种无质量的粒子来模拟鸟群中的鸟,粒子仅具有两个属性:速度和位置,速度代表移动的快慢,位置代表移动的方向。鸟被抽象为没有质量和体积的微粒(点),并延伸到N维空间,粒子i在N维空间的位置表示为矢量Xi=(x1,x2,…,xN),飞行速度表示为矢量Vi=(v1,v2,…,vN)。每个粒子都有一个由目标函数决定的适应值(fitness value),并且知道自己到目前为止发现的最好位置(pbest)和现在的位置Xi。这个可以看作是粒子自己的飞行经验。除此之外,每个粒子还知道到目前为止整个群体中所有粒子发现的最好位置(gbest)(gbest是pbest中的最好值),这个可以看作是粒子同伴的经验。粒子就是通过自己的经验和同伴中最好的经验来决定下一步的运动。

速度和位置的更新

SO初始化为一群随机粒子(随机解)。然后通过迭代找到最优解。在每一次的迭代中,粒子通过跟踪两个“极值”(pbest,gbest)来更新自己。在找到这两个最优值后,粒子通过下面的公式来更新自己的速度和位置。
在这里插入图片描述

对于公式(1):
公式(1)的第①部分称为【记忆项】,表示上次速度大小和方向的影响;
公式(1)的第②部分称为【自身认知项】,是从当前点指向粒子自身最好点的一个矢量,表示粒子的动作来源于自己经验的部分;
公式(1)的第③部分称为【群体认知项】,是一个从当前点指向种群最好点的矢量,反映了粒子间的协同合作和知识共享。粒子就是通过自己的经验和同伴中最好的经验来决定下一步的运动。
以上面两个公式为基础,再来看一个公式:
在这里插入图片描述

公式(2)和 公式(3)被视为标准PSO算法。

算法流程

在这里插入图片描述

学习因子c1、c2分析

公式(2)和(3)中pbest和gbest分别表示微粒群的局部和全局最优位置。
当C1=0时,则粒子没有了认知能力,变为只有社会的模型(social-only):
在这里插入图片描述

称为全局PSO算法。粒子有扩展搜索空间的能力,具有较快的收敛速度,但由于缺少局部搜索,对于复杂问题
比标准PSO 更易陷入局部最优。
当C2=0时,则粒子之间没有社会信息,模型变为只有认知(cognition-only)模型:
在这里插入图片描述

称为局部PSO算法。由于个体之间没有信息的交流,整个群体相当于多个粒子进行盲目的随机搜索,收敛速度慢,因而得到最优解的可能性小。

示例演示

用粒子群算法求解求解函数y=-x*(x-1) 在0,2上最大值。

#include <iostream>
#include <random>
#include <ctime>

using namespace std;

class AlgorithmPSO 
{
public:
	AlgorithmPSO()
	{

	}
	~AlgorithmPSO()
	{
		delete[] m_y;
		delete[] m_x;
		delete[] m_v;
		delete[] m_pbest;
	}

    //适应度计算函数,每个粒子都有它的适应度
     void fitnessFunction()
	 {
        for(int i=0;i<m_n;i++)
		{
            m_y[i] = -1.0f * m_x[i] * (m_x[i]-2.0);
        }
     }
    
	 //初始化
	 void init()
	 { 
        m_x = new double[m_n];
        m_v = new double[m_n];
        m_y = new double[m_n];
        m_pbest = new double[m_n];
        /***
         * 本来是应该随机产生的,为了方便演示,我这里手动随机落两个点,分别落在最大值两边
         */
        m_x[0] = 0.0;
        m_x[1] = 2.0;
        m_v[0] = 0.01;
        m_v[1] = 0.02;
        fitnessFunction();
        //初始化当前个体最优位置,并找到群体最优位置
        for(int i=0;i<m_n;i++)
		{
            m_pbest[i] = m_y[i];
            if(m_y[i]>gbest) gbest=m_y[i];
        }
       std::cout << ("Algorithm Starting , gbest:") << gbest << std::endl;
    }

    double getMAX(double a,double b)
	{
        return a>b?a:b;
    }

    //粒子群算法
    void PSO(int max)
	{
        for(int i=0;i<max;i++)
		{
            double w=0.4;
            for(int j=0;j<m_n;j++)
			{
                //更新位置和速度,下面就是我们之前重点讲解的两条公式。
				default_random_engine e;
				e.seed(time(0));
				std::normal_distribution<double> Normal_d(0, 1);
				double rd = Normal_d(e);

                m_v[j] = w * m_v[j]+c1 * rd * (m_pbest[j]-m_x[j]) + c2 * rd * (gbest-m_x[j]);
                if(m_v[j]>vmax) m_v[j] = vmax;//控制速度不超过最大值
                m_x[j] += m_v[j];
                
                //越界判断,范围限定在[0, 2]
                if(m_x[j]>2) m_x[j] = 2;
                if(m_x[j]<0) m_x[j] = 0;
                
            }
            fitnessFunction();
            //更新个体极值和群体极值
            for(int j=0;j<m_n;j++)
			{
                m_pbest[j]  =getMAX(m_y[j],m_pbest[j]);
                if(m_pbest[j]>gbest) gbest=m_pbest[j];
                std::cout << "Particle n" << j << ": x = " << m_x[j] <<"  " <<"v = " <<m_v[j] << std::endl;
            }
           std::cout  << (i+1)  << "iter , gbest = "  <<  gbest << std::endl;
        }
        
    }
private:
	int m_n = 2; //粒子个数,这里为了方便演示,我们只取两个,观察其运动方向
	double* m_y;
	double* m_x;
	double* m_v;
	double c1 = 2;
	double c2 = 2;
	double* m_pbest;
	double gbest;
	double vmax = 0.1; //速度最大值
};

int main()
{
	AlgorithmPSO ts;
	ts.init();
	ts.PSO(20);//为了方便演示,我们暂时迭代20次。
	return EXIT_SUCCESS;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值