我在C ++中实现了模拟退火,以在某个范围内最小化(x-2)^2+(y-1)^2
。
我得到了不同的输出,这对于这种启发式方法是不可接受的。似乎解决方案正在趋同但从未完全接近解决方案。
我的代码:
#include <bits/stdc++.h>
using namespace std;
double func(double x, double y)
{
return (pow(x-2, 2)+pow(y-1, 2));
}
double accept(double z, double minim, double T,double d)
{
double p = -(z - minim) / (d * T);
return pow(exp(1), p);
}
double fRand(double fMin, double fMax)
{
double f = (double)rand() / RAND_MAX;
return fMin + f * (fMax - fMin);
}
int main()
{
srand (time(NULL));
double x = fRand(-30,30);
double y = fRand(-30,30);
double xm = x, ym=y;
double tI = 100000;
double tF = 0.000001;
double a = 0.99;
double d=(1.6*(pow(10,-23)));
double T = tI;
double minim = func(x, y);
double z;
double counter=0;
while (T>tF) {
int i=1;
while(i<=30) {
x=x+fRand(-0.5,0.5);
y=y+fRand(-0.5,0.5);
z=func(x,y);
if (z<minim || (accept(z,minim,T,d)>(fRand(0,1)))) {
minim=z;
xm=x;
ym=y;
}
i=i+1;
}
counter=counter+1;
T=T*a;
}
cout<<"min: "<<minim<<" x: "<<xm<<" y: "<<ym<<endl;
return 0;
}
如何才能让它达到解决方案?
答案 0 :(得分:1)
我认为在实施模拟退火算法时有一些问题是错误的。
在每次迭代中,您应该查看当前最小值的一些邻居z,并且如果f(z)
问题在于,在accept
函数中,参数d
太低了 - 它将始终返回0.0
并且永远不会触发接受条件。尝试类似1e-5
的内容;它不必在物理上是正确的,它只需要在降低温度的同时降低。
在更新外循环中的温度后,你应该放x=xm
和y=ym
,然后再做内循环或者不是搜索当前解决方案的邻居,你基本上会随意乱走(你也没有检查任何边界。)
这样做,我通常得到一些像这样的输出:
min: 8.25518e-05 x: 2.0082 y: 0.996092
希望它有所帮助。