scipy 跳盆有界优化

gorkyyrv  于 2022-11-10  发布在  其他
关注(0)|答案(1)|浏览(191)

我不明白如何将界限融入到scipy的跳盆程序中。
我根据scipy的教程编写了下面的脚本,用来测试一维边界上的盆地跳跃。

from scipy.optimize import basinhopping
import matplotlib.pyplot as plt

class MyBounds:
    def __init__(self, xmax, xmin ):
        self.xmax = np.array(xmax)
        self.xmin = np.array(xmin)
    def __call__(self,**kwargs):
        x = kwargs["x_new"]
        tmax = bool(np.all(x <= self.xmax))
        tmin = bool(np.all(x >= self.xmin))
        return tmax and tmin

my_bounds = MyBounds([-4], [2])

func = lambda x: np.cos(14.5 * x - 0.3) + (x + 0.2) * x
x0=[1.]

minimizer_kwargs = {"method": "BFGS"}
ret = basinhopping(func, x0, minimizer_kwargs=minimizer_kwargs,
                   niter=2000, accept_test=my_bounds)
print("global minimum: x = %.4f, f(x) = %.4f" % (ret.x, ret.fun))

bounds = np.linspace(-5, 5, 100)
vals = [func(x) for x in bounds]

plt.plot(bounds, vals)

如果没有accept_test = my_bounds,则输出为global minimum: x = -0.1951, f(x) = -1.0009。如果包含这一行,则输出为global minimum: x = 1.0926, f(x) = 0.4259。这没有意义--0.1951包含在[-4,2]中,所以应用边界时,它不应该是输出吗?
此外,将边界更改为[4,0]会输出global minimum: x = 1.0926, f(x) = 0.4259。这甚至不在边界内。
在scipy里处理这个问题的正确方法是什么?

3htmauhk

3htmauhk1#

Basinhopping调用大都会Hasting以迭代方式生成步骤建议。这是随机的,在优化器的罩下发生。然而,这很可能是您的答案隐藏的地方。您可以使用函数揭示建议的序列(以及它们是否被接受)

def debug(x, f, accepted):
    print("f(x)={}, \tIs accepted: {}".format(round(f, 3), int(accepted)))

以及修改该线

ret = basinhopping(func, x0, minimizer_kwargs=minimizer_kwargs,
                   niter=2000, accept_test=my_bounds, callback=debug)

在您的程式码中。
这将打印迭代过程中每个步骤的状态。您将能够看到哪些步骤未被接受(使优化程序远离您期望的最小值)。
然而,x = -0.1951在区间[-4, 2]内,x = 1.0926[0, 4]也是如此,不幸的是,myBounds.__init__(self, xmax, xmin)的参数顺序与直觉相反,先列出大的,后列出小的。

相关问题