模拟退火算法(SA)

这些天疫情在家里自己看高级人工智能,写了一个模拟退火算法做函数优化的例子,防止以后忘了…
优化函数: f ( x ) = x 4 − 2 x 3 + 32 x 2 + 6 x f(x)=x^{4}-2x^{3}+32x^{2}+6x f(x)=x42x3+32x2+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} f(x)=x4+y48x3+5y332x274y2
等高线图:
在这里插入图片描述
c++源码:
主要将原离散二次降温函数更改为了 1 l o g ( 1 + t ) \frac{1}{log(1+t)} log(1+t)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;
}
当在Android应用中遇到"You need to use a Theme.AppCompat theme (or descendant) with this activity."这个错误时,这意味着你在创建或修改某个Activity的XML布局文件时,尝试使用了一个不兼容的的主题。AppCompat主题是Android Support Library的一部分,专为那些使用了较旧API版本但仍然需要新特性(如Action Bar)的应用设计的,它提供了对旧版本API的向下兼容。 解决这个问题通常需要按照以下步骤操作: 1. **检查XML布局**:确认你的Activity标签是否设置了`android:theme`属性,如果设置了,请检查其值是否为`Theme.AppCompat`或其子主题。例如: ```xml <activity android:name=".YourActivity" android:theme="@style/AppTheme"> ``` 如果没有,添加这个主题。 2. **更新样式文件**:如果你有一个单独的`.xml`样式文件(如`styles.xml`),确保`<style>`标签中定义的默认主题或者`<application>`下的主题也指向`Theme.AppCompat`。 3. **继承AppCompatActivity**:如果你的Activity不是直接继承自`Activity`而是其他类,考虑将父类改为`AppCompatActivity`,因为它内部已经包含了AppCompat所需的兼容性增强。 4. **添加依赖**:如果你还没有在build.gradle文件中的dependencies部分添加`appcompat-v7`库,记得添加: ```gradle implementation 'com.android.support:appcompat-v7:version_number' ``` 用实际的版本号替换`version_number`。 5. **运行并检查**:清理并重新构建项目,然后在模拟器或设备上运行,看看错误是否已经被修复。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值