python - 如何使用 Dual_annealing 设置简单的线性约束?

标签 python scipy mathematical-optimization

我可以设置简单的边界以与双退火一起使用:例如

upper_bound = 20
num_points = 30
bounds = [(0, upper_bound) for i in range(num_points)]
res = dual_annealing(fun, bounds, maxiter=1000)

但我还想约束变量,以便每个 i 的 x_i >= x_{i-1}+0.5 。也就是说,每个变量应至少比前一个变量大 0.5。

你怎么能做到这一点?

如果 scipy 不能做到这一点,是否有其他具有全局优化器的库可以做到这一点?

最佳答案

不知道我的理解是否正确,如有错误,请指正。

问题

根据您的边界规范,我了解到 fun 是 30 个变量的函数 {x_1, x_2, ...,x_i-1, x_i, x_i+1, ..., x_30}。您想要的是强制这些变量遵循关系 x_i >= x_i-1+0.5。正如另一个答案所述,这确实可以通过拉格朗日乘子来实现,但有时方程太复杂。

这是一个非常基本的强力替代方案 - 约束数值优化:

from scipy.optimize import dual_annealing
import numpy as np

# an example objective function
def fun(x: np.ndarray) -> float:
    return np.sum(x)

# let's create a simple wrapper using a callable class that will
# 'watch' that constrains are fulfilled.
# hit and miss attributes are only for convenience
# to see some stats at the end
class Wrapper:

    def __init__(self, fun):
        self.fun = fun
        self.hit = 0
        self.miss = 0

    def __call__(self, x: np.ndarray) -> np.ndarray:
        # check if all differences are higher than 0.5
        # if yes than return the value of objective function
        if np.all(np.diff(x) > 0.5):
            self.hit += 1
            return self.fun(x)
        # if the constraints are not met than return inf. This effectively
        # discourages the optimizer from visiting the points of function where
        # the constrains are not fulfilled
        else:
            self.miss += 1
            return np.inf        

upper_bound = 20
num_points = 30
bounds = [(0, upper_bound) for i in range(num_points)]

wrapped = Wrapper(fun)

# We specify x0 starting point as the optimizer might fail to start otherwise.
# This is because your constraints are quite limiting and it might be hard to
# generate initial state. The optimizer makes 1000 attempts to do so and than
# fails. This avoids that
res = dual_annealing(
    wrapped,
    bounds,
    maxiter=1000,
    x0=np.linspace(0, upper_bound, 30)
)
print(res.x)
print(wrapped.hit, wrapped.miss)

注释

这里有一些缺点需要注意:

  • 我不知道计算强度如何fun,但在如此严格的约束下,这可能会导致资源密集,甚至在 30D 空间中速度非常快。如果运行此命令,您将看到命中/未命中比率约为 5/8
  • 由于计算强度,您可能会遇到收敛问题
  • 您还应该考虑限制的严格程度。也许他们可以放松一点,np.inf 可以用多项式函数的指数代替。这会更好,因为它不会引入现在存在的任何不连续性,尽管模拟退火应该可以使用它们。
  • 由于使用“np.inf”和它引入的不连续性,可能需要使用 dual_annealing(..., no_local_search=True) 关闭本地搜索,因为它使用 BFGS,您可以在那里遇到梯度爆炸。
  • 如果您的函数足够简单,您应该尝试使用拉格朗日乘子在纸上完成此操作,这始终是更好的方法。

关于python - 如何使用 Dual_annealing 设置简单的线性约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75698797/

相关文章:

python - Serverless:上传的文件必须是非空 zip。

python - 我无法在 selenium 中使用 python 请求 session cookie

python - scipy UnivariateSpline 因多值 X 而失败

python - 类型错误 : can't convert expression to float

matlab - MATLAB lsqnonlin 中用户定义的 Jacobean 模式被忽略

python - 处理 python 中的错误

python - 从域名地址中提取名称实体

python - 从 numpy 中的一维数组创建方形 nxn 矩阵的最快方法

python - 使用SciPy的minimum找到图中的最短路径

c++ - 计算词典索引的最有效方法