从预定义集中为 scipy.optimize 选择变量

Choosing variables for scipy.optimize from a pre-defined set

我正在尝试使用 scipy.optimize 最小化具有三个输入变量的函数,其中两个是有界的,并且必须从一组值中选择一个。为了确保第三个变量是从一组预定义的值中选择的,我引入了以下约束:

from scipy.optimize import rosin, shgo
import numpy as np

# Set from which the third variable to be optimized can hold 
Z = np.array([-1, -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 1]) 

def Reson_Test(x):   # arbitrary objective function
     print (x)
     return rosen(x)**2 - np.sin(x[0]) 

def Cond_1(x):
     if x[2] in Z:
          return 1
     else:
          return -1

bounds = [(-512,512),]*3 
conds = ({'type': 'ineq' , 'fun' : Cond_1})


result = shgo(Rosen_Test, bounds, constraints=conds)
print (result)

但是,当查看 Rosen_Test 的打印结果时,很明显条件没有被强制执行 - 也许条件定义不正确?

我想知道是否有人有任何想法来确保可以从集合中选择第三个变量。

注意:选择使用 shgo 方法是为了引入和更改约束。另外,如果满足这个条件,我愿意使用其他优化包

不平等约束不是那样起作用的。

docs中所述,它们被定义为

g(x) <= 0

你需要像这样写 g(x) 作品。在您的情况下并非如此。您只是 return 为一个维度设置一个标量。您需要 return 一个具有三个维度的向量,形状为 (3,).

在您的情况下,您可以尝试改用等式约束,因为这样可以稍微好一点。但我仍然不确定它是否会起作用,因为这些优化器不会那样工作。 整个事情可能会给优化器留下一个相当颠簸和不连续的 objective 函数。您可以阅读 混合整数非线性规划 (MINLP),也许开始 here.

还有一个原因导致您的方法无法按预期工作 由于优化器使用浮点数,因此在优化和猜测新解决方案时,它可能永远不会在您的数组中找到数字。

这说明了问题:

import numpy as np

Z = np.array([-1, -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 1])

print(0.7999999 in Z) # False, this is what the optimizer will find
print(0.8 in Z) # True, this is what you want

也许您应该尝试以允许对 Z.

的整个范围使用不等式约束的方式来定义您的问题

但让我们看看它如何工作。

等式约束定义为

h(x) == 0

所以你可以使用

def Cond_1(x):
    if x[2] in Z:
        return numpy.zeros_like(x)
    else:
        return numpy.ones_like(x) * 1.0 # maybe multiply with some scalar?

想法是 return 一个数组 [0.0, 0.0, 0.0] 如果找到数字则满足等式约束。 else return [1.0, 1.0, 1.0] 表示不满足。

注意事项

1.) 您可能需要将其调整为 return 一个类似于 [0.0, 0.0, 1.0] 的数组,以向优化器显示您对哪个维度不满意,这样优化器就可以通过仅调整一个维度来做出更好的猜测。

2.) 您可能需要 return 大于 1.0 的值来声明不满足的等式约束。这取决于实施。优化器 可能 认为 1.0 很好,因为它接近 0.0。所以也许你必须尝试一些东西 [0.0, 0.0, 999.0].

这解决了尺寸问题。但是仍然找不到任何数字对上面提到的浮点数做的事情。

但我们可以尝试像这样破解它

import numpy as np

Z = np.array([-1, -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 1])

def Cond_1(x):

    # how close you want to get to the numbers in your array
    tolerance = 0.001 
    delta = np.abs(x[2] - Z)
    print(delta)
    print(np.min(delta) < tolerance)

    if np.min(delta) < tolerance:

        return np.zeros_like(x)

    else:

        # maybe you have to multiply this with some scalar
        # I have no clue how it is implemented
        # we need a value stating to the optimizer "NOT THIS ONE!!!"
        return np.ones_like(x) * 1.0


sol = np.array([0.5123, 0.234, 0.2])
print(Cond_1(sol)) # True

sol = np.array([0.5123, 0.234, 0.202])
print(Cond_1(sol)) # False

是一些关于优化的建议。为确保它以可靠的方式工作,请尝试以不同的初始值开始优化。如果与边界一起使用,全局优化算法可能没有初始值。优化器以某种方式离散化 space.

您可以做些什么来检查优化的可靠性并获得更好的整体结果:

  • 优化整个区域[-512, 512](对于所有三个维度)

  • 尝试其中的 1/2:[-512, 0][0, 512](8 个子优化,每个维度 2 个)

  • 尝试其中的 1/3:[-512, -171][-171, 170][170, 512](27 个子优化,每个维度 3 个)

  • 现在比较收敛的结果,看完整的全局优化是否找到相同的结果

  • 如果全局优化器没有找到"real"最小值而是次优化:

    • 你的objective函数在整个域上太难了
    • 尝试不同的全局优化器
    • 调整参数(可能是等式约束的 999)
    • 我经常将子优化用作正常过程的一部分,而不仅仅是为了测试。特别是对于黑盒问题。

另请参阅这些答案: