模拟退火方法

这个例子展示了如何为模拟退火函数创建和管理选项simulannealbnd使用optimoptions在全局优化工具箱中。

优化问题设置

simulannealbnd搜索的最小使用模拟退火的函数。在这个例子中,我们使用simulannealbnd最小化目标函数dejong5fcn.该函数是两个变量的实值函数,存在许多局部极小值,难以优化。只有一个全局最小值x = (-32、-32),在那里f (x) = 0.998.要定义我们的问题,我们必须定义由范围指定的目标函数、起始点和界限x(i) <= 64为每一个x(我).

ObjectiveFunction = @dejong5fcn;起始点= [-30 0];lb = [-64 -64];ub = [64 64];

这个函数plotobjective在工具箱中绘制目标函数的范围-64 <= x1 <= 64,-64 <= x2 <= 64.

plotobjective (ObjectiveFunction (-64 64;-64 64]);视图(-15150);

现在,我们可以运行simulannealbnd求最小目标函数的解。

rng默认的%的再现性[x, fval exitFlag、输出]= simulannealbnd (ObjectiveFunction startingPoint,磅,乌兰巴托);
终止优化:最佳功能值的变化小于选择。功能公差。
流(“迭代次数为:%d \ n”,output.iterations);
迭代次数是:1095
流(“功能评估的数量为:%d\n”,output.funccount);
功能评价次数:1104次
流('发现的最佳函数值为:%g\n',fval);
得到的最佳函数值为:2.98211

注意,当您运行这个例子时,您的结果可能与上面显示的结果不同,因为模拟退火算法使用随机数来生成点。

添加可视化

simulannealbnd可以通过一个“options”参数接受一个或多个plot函数。该特性对于可视化求解程序在运行时的性能非常有用。使用以下命令选择绘图函数optimoptions.工具箱中包含一组绘图函数可供选择,也可以提供自己的自定义绘图函数。

若要选择多个绘图功能,请设置PlotFcn选择通过optimoptions函数。对于本例,我们选择saplotbestf,绘制每次迭代的最佳函数值,saplottemperature,表示每次迭代各维度的当前温度,saplotf,它显示当前函数值(请记住,当前值不一定是最佳值),并且saplotstopping,它绘制每10次迭代满足的停止标准的百分比。

选择= optimoptions (@simulannealbnd,“PlotFcn”,{@saplotbestf、@saplottemperature @saplotf, @saplotstopping});

运行的能手。

simulannealbnd (ObjectiveFunction startingPoint,磅,乌兰巴托,选项);

终止优化:最佳功能值的变化小于选择。功能公差。

指定温度的选择

模拟退火中使用的温度参数控制整个搜索结果。每个维度的温度用于限制该维度中的搜索范围。工具箱允许您指定初始温度以及在解决方案过程中更新温度的方法。与温度相关的两个选项是InitialTemperatureTemperatureFcn.

指定初始温度

每个维度的默认初始温度设置为100。如果你想让初始温度在不同的维度上不同那么你必须指定一个温度向量。当问题在每个维度上的比例不同时,这可能是必要的。例如,

选择= optimoptions (@simulannealbnd,“InitialTemperature”,50 [300]);

InitialTemperature可设置为向量长度小于变量个数(维数);求解者通过取初始温度矢量的最后一个元素,将矢量扩展到其余维度。这里我们希望初始温度在所有维度上都是相同的所以我们只需要指定一个温度。

选项。InitialTemperature = 100;

指定温度函数

所使用的默认温度函数simulannealbnd被称为temperatureexp.在temperatureexp进度表中,任何给定步骤的温度都是前一步温度的0.95倍。这使得温度一开始下降缓慢,但最终比其他方案更快地降温。如果需要另一种方案,例如Boltzmann调度或“快速”调度退火,则temperatureboltztemperaturefast可以分别使用。要选择快速温度计划,我们可以更新之前创建的选项,进行更改TemperatureFcn直接。

选项。TemperatureFcn = @temperaturefast;

指定再次退火

再退火是退火过程的一部分。在接受了一定数量的新点之后,将温度提升到一个更高的值,希望能够重新开始搜索并移出局部极小值。过早地执行再退火可能无法帮助求解器识别最小值,因此一个相对较高的区间是一个不错的选择。重新退火发生的时间间隔可以使用ReannealInterval选择。在这里,我们将默认的重新退火间隔减少到50,因为函数在许多区域看起来是平坦的,并且求解器可能会很快陷入困境。

选项。ReannealInterval = 50;

现在我们已经设置了新的温度选项,我们再次运行求解器

[x, fval exitFlag、输出]= simulannealbnd (ObjectiveFunction startingPoint,磅,乌兰巴托,选项);
终止优化:最佳功能值的变化小于选择。功能公差。
流(“迭代次数为:%d \ n”,output.iterations);
迭代次数为:1306
流(“功能评估的数量为:%d\n”,output.funccount);
函数计算次数为:1321次
流('发现的最佳函数值为:%g\n',fval);
得到的最佳函数值为:16.4409

复制的结果

simulannealbnd是一个不确定的算法。这意味着在不更改任何设置的情况下多次运行求解程序可能会得到不同的结果。这是因为simulannealbnd利用MATLAB®随机数生成器生成后续点,并在确定是否接受新点时使用。每次生成随机数时,随机数生成器的状态都会发生变化。

看这个,跑了两圈simulannealbnd解算器收益率:

[x, fval] = simulannealbnd (ObjectiveFunction startingPoint,磅,乌兰巴托,选项);
终止优化:最佳功能值的变化小于选择。功能公差。
流('发现的最佳函数值为:%g\n',fval);
找到的最佳函数值为:1.99203

而且,

[x, fval] = simulannealbnd (ObjectiveFunction startingPoint,磅,乌兰巴托,选项);
终止优化:最佳功能值的变化小于选择。功能公差。
流('发现的最佳函数值为:%g\n',fval);
找到的最佳函数值为:10.7632

在前两次运行中simulannealbnd给出了不同的结果。

我们可以重新生成我们的结果,如果我们重置随机数生成器的状态之间运行的求解器使用返回的信息simulannealbnd.simulannealbnd返回随机数生成器当时的状态simulannealbnd在输出参数中调用。此信息可用于重置状态。在这里,我们使用这个输出信息重置运行之间的状态,以便下两次运行的结果相同。

[x, fval exitFlag、输出]= simulannealbnd (ObjectiveFunction startingPoint,磅,乌兰巴托,选项);
终止优化:最佳功能值的变化小于选择。功能公差。
流('发现的最佳函数值为:%g\n',fval);
得到的最佳函数值为:20.1535

我们重置随机数发生器的状态。

strm = RandStream.getGlobalStream;strm。状态= output.rngstate.State;

现在,让我们来运行simulannealbnd一次。

[x, fval] = simulannealbnd (ObjectiveFunction startingPoint,磅,乌兰巴托,选项);
终止优化:最佳功能值的变化小于选择。功能公差。
流('发现的最佳函数值为:%g\n',fval);
得到的最佳函数值为:20.1535

修改停止标准

simulannealbnd使用六个不同的标准来确定何时停止求解程序。simulannealbnd当超过最大迭代次数或函数评估次数时停止;默认情况下,迭代的最大次数设置为Inf,函数计算的最大次数为3000 * numberOfVariables.simulannealbnd跟踪函数值的平均变化MaxStallIterations迭代。如果平均变化量小于函数容差,FunctionTolerance,则算法将停止。当目标函数值达到时,求解器也会停止ObjectiveLimit.最后求解器会在运行后停止运行MaxTime秒。这里我们设置FunctionTolerance1 e-5。

选项。FunctionTolerance = 1 e-5;

运行simulannealbnd解算器。

[x, fval exitFlag、输出]= simulannealbnd (ObjectiveFunction startingPoint,磅,乌兰巴托,选项);
终止优化:最佳功能值的变化小于选择。功能公差。
流(“迭代次数为:%d \ n”,output.iterations);
迭代次数为:1843次
流(“功能评估的数量为:%d\n”,output.funccount);
函数计算次数为:1864次
流('发现的最佳函数值为:%g\n',fval);
得到的最佳函数值为:6.90334