从预定义集中为 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)
- 我经常将子优化用作正常过程的一部分,而不仅仅是为了测试。特别是对于黑盒问题。
另请参阅这些答案:
我正在尝试使用 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
您可以做些什么来检查优化的可靠性并获得更好的整体结果:
优化整个区域
[-512, 512]
(对于所有三个维度)尝试其中的 1/2:
[-512, 0]
和[0, 512]
(8 个子优化,每个维度 2 个)尝试其中的 1/3:
[-512, -171]
、[-171, 170]
、[170, 512]
(27 个子优化,每个维度 3 个)现在比较收敛的结果,看完整的全局优化是否找到相同的结果
如果全局优化器没有找到"real"最小值而是次优化:
- 你的objective函数在整个域上太难了
- 尝试不同的全局优化器
- 调整参数(可能是等式约束的 999)
- 我经常将子优化用作正常过程的一部分,而不仅仅是为了测试。特别是对于黑盒问题。
另请参阅这些答案: