【智能算法】PSO粒子羣優化算法(C++實現)

粒子羣優化算法(Particle Swarm Optimization, PSO)是進化計算的一個分支,是一種模擬自然界的生物活動的演化算法。

PSO模擬了自然界鳥羣捕食的過程,通過羣體之間的協作來找到問題的全局最優解。

 

PSO的主要流程如下:

這裏有一個動態圖模擬粒子羣優化算法的演化過程:

來自WIKIPEDIA

具體代碼如下:

1、定義參數

#define PI 3.14159265358979323846
#define POPSIZE 20                         //粒子個數
#define MAXINTERATION 2000                 //最大迭代次數
#define NVARS 10                           //參數個數
#define WMAX 0.9                           //慣量權重最大值
#define WMIN 0.4                           //慣量權重最小值

struct particle {                          //單個粒子
	double pBest[NVARS];
	double v[NVARS];
	double x[NVARS];
	double upper[NVARS];
	double lower[NVARS];
};

double w;                                  //慣量權重
double c1 = 2.0;                           //加速因子1
double c2 = 2.0;                           //加速因子2
double absbound;                           //上下界絕對值
double vmax;                               //最大速度
double gBest[NVARS];                       //全局最優解
particle particles[POPSIZE];               //粒子羣

2、函數定義

double evalfunc(double[], int);            //評估函數
double avg(double[], int);                 //求平均數
double stddev(double[], int);              //求標準差
void initialize(int);                      //初始化函數
double randval(double, double);            //求範圍(lower,upper)之間的隨機數
void evaluate(int);                        //評估粒子適應值
void update(int, int);                     //利用更新公式更新每個粒子的速度和位置以及歷史最優位置
void fit(void);                            //更新羣體歷史最優位置

3、評估函數

double evalfunc(double parameter[], int FUNC = 1) {
	/*          10個評估函數            */
	/* 通過參數FUNC來選擇想要的評估函數 */
	if (FUNC == 1) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			val += parameter[i] * parameter[i];
		}
		return val;
	}

	if (FUNC == 2) {
		double val1 = 0;
		double val2 = 0;
		for (int i = 0; i < NVARS; i++) {
			val1 += abs(parameter[i]);
			val2 = val2*abs(parameter[i]);
		}
		return (val1 + val2);
	}

	if (FUNC == 3) {
		double val1 = 0;
		int i, j;
		for (i = 0; i < NVARS; i++) {
			double val2 = 0;
			for (j = 0; j < i; j++) {
				val2 += parameter[j];
			}
			val1 += val2*val2;
		}
		return val1;
	}

	if (FUNC == 4) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			if (abs(parameter[i]) > val)
				val = abs(parameter[i]);
		}
	}

	if (FUNC == 5) {
		double val = 0;
		for (int i = 0; i < NVARS - 1; i++) {
			val += 100 * (parameter[i + 1] - parameter[i] * parameter[i])*(parameter[i + 1] - parameter[i] * parameter[i]) + (parameter[i] - 1)*(parameter[i] - 1);
		}
		return val;
	}

	if (FUNC == 6) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			val += floor(parameter[i] + 0.5)*floor(parameter[i] + 0.5);
		}
		return val;
	}

	if (FUNC == 7) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			val += i*pow(parameter[i], double(i));
		}
		return (val + randval(0, 1));
	}

	if (FUNC == 8) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			val += (-(parameter[i] * sin(sqrt(abs(parameter[i])) / 180 * PI)));
		}
		return val;
	}

	if (FUNC == 9) {
		double val = 0;
		for (int i = 0; i < NVARS; i++) {
			val += (parameter[i] * parameter[i] - 10 * cos(2 * PI*parameter[i] / 180 * PI) + 10.0);
		}
		return val;
	}

	if (FUNC == 10) {
		double val1 = 0;
		double val2 = 0;
		for (int i = 0; i < NVARS; i++) {
			val1 += parameter[i] * parameter[i];
			val2 += cos(2 * PI*parameter[i] / 180 * PI);
		}
		return ((-20)*exp((-0.2)*sqrt(val1 / NVARS)) - exp(val2 / NVARS) + 20 + exp(1));
	}
}

4、一些計算指標及隨機數函數

double avg(double parameter[], int n) {
	double num = 0;
	for (int i = 0; i < n; i++) {
		num += parameter[i];
	}
	return num / n;
}


double stddev(double parameter[], int n) {
	double num = avg(parameter, n);
	double sum = 0.0;
	for (int i = 0; i < n; i++) {
		sum += (parameter[i] - num)*(parameter[i] - num);
	}
	return sqrt(sum / n);
}


double randval(double low, double high) {
	return (low + (high - low)*rand()*1.0 / RAND_MAX);
}	double num = 0;
	for (int i = 0; i < n; i++) {
		num += parameter[i];
	}
	return num / n;
}


double stddev(double parameter[], int n) {
	double num = avg(parameter, n);
	double sum = 0.0;
	for (int i = 0; i < n; i++) {
		sum += (parameter[i] - num)*(parameter[i] - num);
	}
	return sqrt(sum / n);
}


double randval(double low, double high) {
	return (low + (high - low)*rand()*1.0 / RAND_MAX);
}

5、初始化函數

void initialize(int FUNC = 1) {
	/*  初始化每個粒子的速度、位置並將  */
	/*  該位置設定爲當前歷史最優位置找  */
	/*  到所有粒子的最優位置並設定爲當  */
	/*  前羣體歷史最優位置              */
	int i, j;
	double lbound[NVARS];
	double ubound[NVARS];

	for (i = 0; i < NVARS; i++) {
		lbound[i] = (-absbound);
		ubound[i] = absbound;
	}

	for (i = 0; i < NVARS; i++) {
		for (j = 0; j < POPSIZE; j++) {
			particles[j].upper[i] = ubound[i];
			particles[j].lower[i] = lbound[i];
			particles[j].v[i] = randval(lbound[i], ubound[i]);
			particles[j].x[i] = randval(lbound[i], ubound[i]);
			particles[j].pBest[i] = particles[j].x[i];
		}
	}

	double pval = evalfunc(particles[0].pBest);
	int num;
	for (i = 1; i < POPSIZE; i++) {
		if (pval > evalfunc(particles[i].pBest)) {
			pval = evalfunc(particles[i].pBest);
			num = i;
		}
		else continue;
	}
	for (j = 0; j < NVARS; j++) {
		gBest[j] = particles[num].pBest[j];
	}
}

6、評估

void evaluate(int FUNC = 1) {
	/*  通過傳入參數FUNC來調用不同的評  */
	/*  估函數並對粒子位置進行評估並更  */
	/*  新粒子歷史最優位置              */
	int i, j;
	double pval[POPSIZE], nval[POPSIZE];

	for (i = 0; i < POPSIZE; i++) {
		pval[i] = evalfunc(particles[i].pBest, FUNC);
		nval[i] = evalfunc(particles[i].x, FUNC);

		if (pval[i] > nval[i]) {
			for (j = 0; j < NVARS; j++) {
				particles[i].pBest[j] = particles[i].x[j];
			}
		}
	}
}

7、更新函數

void update(int interation, int w_change_method = 1) {
	/*  通過參數w_change_method來選擇不 */
	/*  同的慣性權重衡量規則來根據羣體  */
	/*  歷史最優位置更新粒子速度以及位置*/
	int i, j;
	double v, x;

	if (w_change_method == 1) {
		w = WMAX - (WMAX - WMIN) / MAXINTERATION*(double)interation;
	}
	else if (w_change_method == 2) {
		w = randval(0.4, 0.6);
	}
	else if (w_change_method == 3) {
		w = WMAX - (WMAX - WMIN)*((double)interation / MAXINTERATION)*((double)interation / MAXINTERATION);
	}
	else if (w_change_method == 4) {
		w = WMIN + (WMAX - WMIN)*((double)interation / MAXINTERATION - 1)*((double)interation / MAXINTERATION - 1);
	}
	else {
		cout << "Dont have this weight change method!";
		return;
	}

	for (i = 0; i < NVARS; i++) {
		for (j = 0; j < POPSIZE; j++) {
			v = w*particles[j].v[i] + c1*randval(0, 1)*(particles[j].pBest[i] - particles[j].x[i]) + c2*randval(0, 1)*(gBest[i] - particles[j].x[i]);
			if (v > vmax)particles[j].v[i] = vmax;
			else if (v < (-vmax))particles[j].v[i] = (-vmax);
			else particles[j].v[i] = v;

			x = particles[j].x[i] + particles[j].v[i];
			if (x > particles[j].upper[i])particles[j].x[i] = particles[j].upper[i];
			else if (x < particles[j].lower[i])particles[j].x[i] = particles[j].lower[i];
			else particles[j].x[i] = x;
		}
	}
}

8、適應函數

void fit(void) {
	/*         更新羣體最優位置         */
	int i, j;
	double gval = evalfunc(gBest);
	double pval[POPSIZE];

	for (i = 0; i < POPSIZE; i++) {
		pval[i] = evalfunc(particles[i].pBest);

		if (gval > pval[i]) {
			for (j = 0; j < NVARS; j++) {
				gBest[j] = particles[i].pBest[j];
			}
		}
	}
}

9、main函數

int main() {
	srand(time(NULL));
	double all_gBest[100];
	int i, j, k;
	int FUNC;
	int w_change_method;
	cout << "*********************************************************************************************************************************" << endl;
	cout << "*******************************  十個" << NVARS << "維函數用4種不同的權重控制方法運行一百次的平均結果及標準差" << "  *******************************" << endl;
	cout << "                線性遞減法" << "                      隨機權重法" << "                      凹函數遞減法" << "                    凸函數遞減法" << endl;
	cout << " 函數" << endl;
	cout << "           平均值" << "          標準差"
		<< "          平均值" << "          標準差"
		<< "          平均值" << "          標準差"
		<< "          平均值" << "          標準差";
	cout << endl << endl;
	for (FUNC = 1; FUNC <= 10; FUNC++) {
		cout << " " << std::left << "f" << setw(4) << FUNC;
		switch (FUNC)
		{
		case 1:absbound = 100.0; break;
		case 2:absbound = 10.0; break;
		case 3:absbound = 100.0; break;
		case 4:absbound = 100.0; break;
		case 5:absbound = 30.0; break;
		case 6:absbound = 100.0; break;
		case 7:absbound = 1.28; break;
		case 8:absbound = 500.0; break;
		case 9:absbound = 5.12; break;
		case 10:absbound = 32.0; break;
		default:
			break;
		}
		vmax = absbound*0.15;
		for (w_change_method = 1; w_change_method <= 4; w_change_method++) {
			for (j = 0; j < 100; j++) {
				initialize();
				evaluate(FUNC);
				for (int i = 0; i < MAXINTERATION; i++) {
					update(i, w_change_method);
					evaluate(FUNC);
					fit();
				}
				double evalue = evalfunc(gBest);
				if (evalue == 0) {
					j--;
					continue;
				}
				all_gBest[j] = evalue;
			}
			cout << setw(16) << avg(all_gBest, 100);
			cout << setw(16) << stddev(all_gBest, 100);
		}
		cout << endl;
	}
	cout << "*********************************************************  算法運行結束  ********************************************************" << endl;
	cout << "*********************************************************************************************************************************" << endl;
	system("pause");
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章