0

我在 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;
}

我怎样才能让它达到解决方案?

4

1 回答 1

2

在模拟退火算法的实现中,我认为有几件事是错误的。

在每次迭代中,您应该查看当前最小值的一些邻居 z 并在 f(z) < 最小值时更新它。如果 f(z) > 最小值,您也可以接受新点,但具有接受概率函数。

问题是在你的accept函数中,参数d太低了——它总是会返回0.0并且永远不会触发接受条件。尝试类似的东西1e-5;它不必在物理上是正确的,它只需要在降低“温度”的同时降低。

更新外循环中的温度后,您应该在执行内循环之前放置x=xmand y=ym,而不是搜索当前解决方案的邻居,您基本上会随机四处游荡(您也没有检查任何边界)。

这样做,我通常会得到一些这样的输出:

min: 8.25518e-05 x: 2.0082 y: 0.996092

希望它有所帮助。

于 2015-11-18T18:04:46.740 回答