模拟退火算法(SA)

这些天疫情在家里自己看高级人工智能,写了一个模拟退火算法做函数优化的例子,防止以后忘了…
优化函数: f ( x ) = x 4 2 x 3 + 32 x 2 + 6 x f(x)=x^{4}-2x^{3}+32x^{2}+6x
函数图像:
在这里插入图片描述
c++源码:

#include<iostream>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
using namespace std;
double E(const vector<double> &X)
{
	const double X2=X[0]*X[0];
	return (X2*X2-2*X2*X[0]-32*X2+6*X[0]);
}
double random(double start=0,double end=1)
{
	return (rand()/(double)RAND_MAX)*(end-start)+start;
}
void drop(double &t0)
{
	static double tc=10.0;
	tc-=0.05;
	t0-=(tc>0.05?tc:0.05);
	if(t0<=1)  //常温 
		t0=1;
}
double P(double Ei,double Ej,double t)
{
	return exp(-(Ej-Ei)/t);
}
int main()
{
	srand(time(NULL));
	vector<double> v0={-10.0};  //粒子初始位置(随意设置,不要过大过小即可)
	double t0=1200;  //初始温度 
	const double alpha=0.1;  //活跃度系数(连续邻域->离散邻域) 
	int cnt=0;
	while(cnt<=20000)
	{
		vector<double> vn;
		vn.push_back(rand()&1?v0[0]-alpha*t0:v0[0]+alpha*t0);  //alhpa*t0为t0温度下粒子活跃度 
		double Ei=E(v0),Ej=E(vn);
		if(Ei>Ej||P(Ei,Ej,t0)>random())
		{
			v0[0]=vn[0];
		}
		drop(t0);
		cnt++;
		if(cnt%100==0)
		{
			vector<double>::iterator it=v0.begin();
			for(;it!=v0.end();it++)
			{
				cout<<cnt<<"th result and tempreture:[ "<<*it<<" , "<<t0<<" ]"<<endl;
			}
		}
	}
	return 0;
}

这几天,深入研究了一下,发现了上次写的模型有一些小问题,例如降温函数,以及邻域函数的随机性问题,以及缺少内循环,导致了需要大量的迭代才能得到一个精确度不是很高的解,于是我更改了源代码,去优化难度更大的二维函数,发现效果特别好。
被优化的二维函数: f ( x ) = x 4 + y 4 8 x 3 + 5 y 3 32 x 2 74 y 2 f(x)=x^{4}+y^{4}-8x^{3}+5y^{3}-32x^{2}-74y^{2}
等高线图:
在这里插入图片描述
c++源码:
主要将原离散二次降温函数更改为了 1 l o g ( 1 + t ) \frac{1}{log(1+t)} , t t 为时间从1开始增长,不设置末温,但是根据函数理论上讲是0,不过永远不可能达到(有点绝对零度的意思?)。
在外循环中加入100次内循环,并且在邻域选择加入了随机性。效果很好,而且鲁棒性和精确度都很高。

#include<iostream>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
using namespace std;
double E(const vector<double> &X)  
{
	double x2=X[0]*X[0],y2=X[1]*X[1];
	
	return x2*x2+y2*y2-8*x2*X[0]+5*y2*X[1]-32*x2-74*y2;
}
double random(double start=0,double end=1)
{
	return (rand()/(double)RAND_MAX)*(end-start)+start;
}
void drop(double &t0)
{
	static double tot=1;
	t0=t0/log(tot+1);
	tot++;
}
double P(double Ei,double Ej,double t)
{
	return exp(-(Ej-Ei)/t);
}
int main()
{
	srand(time(NULL));
	vector<double> v0={random(-100000,100000),random(-100000,100000)};  //粒子初始位置(随意设置,不要过大过小即可)
	double t0=120000;  //初始温度 
	const double alpha=10;  //活跃度系数(连续邻域->离散邻域) 
	int cnt=0;
	while(cnt<=30)
	{
		const int k=100;
		for(int i=0;i<=k-1;i++)
		{ 
			vector<double> vn={v0[0]-alpha*t0*random(-1,1),v0[1]-alpha*t0*random(-1,1)};  //alhpa*t0为t0温度下粒子活跃度 
			double Ei=E(v0),Ej=E(vn);
			if(Ei>Ej||P(Ei,Ej,t0)>random())
			{
				v0[0]=vn[0];
				v0[1]=vn[1];
			}
		}
		drop(t0);
		cnt++;
		if(cnt%1==0)
		{
			cout<<cnt<<"th result and tempreture:[ ";
			vector<double>::iterator it=v0.begin();
			for(;it!=v0.end();it++)
			{
				cout<<*it<<" ";
			}
			cout<<"] , "<<t0<<endl;
		}
	}
	return 0;
}
发布了4 篇原创文章 · 获赞 0 · 访问量 210

猜你喜欢

转载自blog.csdn.net/qq_42378281/article/details/104480919
今日推荐