英文:
Best way to enforce a distance between coefficients
问题
我正在使用 basinhopping 进行全局优化。我的简单代码如下:
from scipy.optimize import basinhopping, rosen
def build_show_bh(MIN=None):
if MIN is None:
MIN = [0]
def fn(xx, f, accept):
if f < MIN[-1]:
print([round(x, 2) for x in xx], f)
MIN.append(f)
return fn
x0 = (0.4, 0.6, 0.8)
bounds = [(0,1)]*3
minimizer_kwargs = dict(method="L-BFGS-B", bounds=bounds)
progress_f = [0]
c = build_show_bh(progress_f)
print("Optimizing using basinhopping")
res = basinhopping(
rosen,
x0,
minimizer_kwargs=minimizer_kwargs,
niter=10,
callback=c,
disp=True
)
print(f"external way of keeping track of MINF: {progress_f}")
我想要添加一个约束,即每个系数必须与其他系数相差至少0.1。如果这有助于的话,我愿意让它们按顺序排列。最佳的方法是什么?
英文:
I am using basinhopping to perform a global optimization. My simple code is:
from scipy.optimize import basinhopping, rosen
def build_show_bh(MIN=None):
if MIN is None:
MIN = [0]
def fn(xx, f, accept):
if f < MIN[-1]:
print([round(x, 2) for x in xx], f)
MIN.append(f)
return fn
x0 = (0.4, 0.6, 0.8)
bounds = [(0,1)]*3
minimizer_kwargs = dict(method="L-BFGS-B", bounds=bounds)
progress_f = [0]
c = build_show_bh(progress_f)
print("Optimizing using basinhopping")
res = basinhopping(
rosen,
x0,
minimizer_kwargs=minimizer_kwargs,
niter=10,
callback=c,
disp=True
)
print(f"external way of keeping track of MINF: {progress_f}")
I would like to add a constraint that each of the coefficients must be at last 0.1 from both the other coefficients. I am happy for them to be in sorted order if that helps. What is the best way of doing that?
答案1
得分: 2
以下是翻译好的代码部分:
# 我会通过创建一个关于连续值之间差异的约束来解决这个问题。
def constraint(x, use_epsilon=True):
difference_between_coeffs = np.diff(x)
epsilon = 1e-6 # 使用此值使约束稍微保守一些
min_difference = 0.1 + (epsilon if use_epsilon else 0)
difference_metric = difference_between_coeffs - min_difference
difference_metric_capped = np.minimum(0, difference_metric)
return np.sum(difference_metric_capped)
# 注意:此约束还要求系数按排序顺序排列。
# 写这个程序时,我遇到的问题是,有时SLSQP会给我一些稍微违反约束的点,我通过要求点之间稍微远一些来解决了这个问题。我发现`epsilon = 1e-6`足以解决这个问题。
# 然后,您必须告诉最小化器使用此约束:
constraints = [
{"type": "eq", "fun": constraint}
]
minimizer_kwargs = dict(method="SLSQP", bounds=bounds, constraints=constraints)
# 注意:我将方法从L-BFGS-B切换到SLSQP,因为BFGS不支持约束。您还可以使用trust-constr - 这是唯一支持约束和边界的其他方法。
# 接下来,我遇到的问题是,有时候basinhopping选择了一个违反约束的点,这导致了最小化的失败,然后认为basinhopping选择的点是正确的。我通过为basinhopping使用接受测试来解决了这个问题。这样,如果点违反了约束,就不会接受这些点。
def accept(x_new, **kwargs):
return constraint(x_new) == 0
res = basinhopping(
# ...
accept_test=accept,
)
# 完整代码:
from scipy.optimize import basinhopping, rosen
import numpy as np
def build_show_bh(MIN=None):
if MIN is None:
MIN = [0]
def fn(xx, f, accept):
if f < MIN[-1]:
print([round(x, 2) for x in xx], f)
MIN.append(f)
return fn
def constraint(x, use_epsilon=True):
difference_between_coeffs = np.diff(x)
epsilon = 1e-6 # 使用此值使约束稍微保守一些
min_difference = 0.1 + (epsilon if use_epsilon else 0)
difference_metric = difference_between_coeffs - min_difference
difference_metric_capped = np.minimum(0, difference_metric)
return np.sum(difference_metric_capped)
def accept(x_new, **kwargs):
return constraint(x_new) == 0
constraints = [
{"type": "eq", "fun": constraint}
]
x0 = (0.4, 0.6, 0.8)
bounds = [(0, 1)] * 3
minimizer_kwargs = dict(method="SLSQP", bounds=bounds, constraints=constraints)
progress_f = [100]
c = build_show_bh(progress_f)
print("Optimizing using basinhopping")
res = basinhopping(
rosen,
x0,
minimizer_kwargs=minimizer_kwargs,
accept_test=accept,
niter=10,
callback=c,
disp=True
)
print(f"external way of keeping track of MINF: {progress_f}")
希望这有助于您理解代码。
英文:
I would solve this problem by creating a constraint on the difference between successive values.
def constraint(x, use_epsilon=True):
difference_between_coeffs = np.diff(x)
epsilon = 1e-6 # Use this to make constraint slightly more conservative
min_difference = 0.1 + (epsilon if use_epsilon else 0)
difference_metric = difference_between_coeffs - min_difference
difference_metric_capped = np.minimum(0, difference_metric)
return np.sum(difference_metric_capped)
(Note: this constraint also requires the coefficients to be in sorted order.)
While writing this program, I had the problem that sometimes SLSQP would give me points which slightly violated the constraint, which I solved by requiring points to be slightly further apart. I found that an epsilon = 1e-6
was sufficient to fix this.
You then have to tell the minimizer to use this constraint:
constraints = [
{"type": "eq", "fun": constraint}
]
minimizer_kwargs = dict(method="SLSQP", bounds=bounds, constraints=constraints)
Note: I switched the method from L-BFGS-B to SLSQP, as BFGS does not support constraints. You can use trust-constr as well - this is the only other method which supports both constraints and bounds.
Next, I had the problem that sometimes basinhopping picked a point which violated the constraint, which caused minimization to fail, which then considers the point picked by basinhopping to be correct. I fixed this by using an acceptance test for basinhopping. This avoid accepting points if they fail the constraint.
def accept(x_new, **kwargs):
return constraint(x_new) == 0
res = basinhopping(
...
accept_test=accept,
)
Full code:
from scipy.optimize import basinhopping, rosen
import numpy as np
def build_show_bh(MIN=None):
if MIN is None:
MIN = [0]
def fn(xx, f, accept):
if f < MIN[-1]:
print([round(x, 2) for x in xx], f)
MIN.append(f)
return fn
def constraint(x, use_epsilon=True):
difference_between_coeffs = np.diff(x)
epsilon = 1e-6 # Use this to make constraint slightly more conservative
min_difference = 0.1 + (epsilon if use_epsilon else 0)
difference_metric = difference_between_coeffs - min_difference
difference_metric_capped = np.minimum(0, difference_metric)
return np.sum(difference_metric_capped)
def accept(x_new, **kwargs):
return constraint(x_new) == 0
constraints = [
{"type": "eq", "fun": constraint}
]
x0 = (0.4, 0.6, 0.8)
bounds = [(0,1)]*3
minimizer_kwargs = dict(method="SLSQP", bounds=bounds, constraints=constraints)
progress_f = [100]
c = build_show_bh(progress_f)
print("Optimizing using basinhopping")
res = basinhopping(
rosen,
x0,
minimizer_kwargs=minimizer_kwargs,
accept_test=accept,
niter=10,
callback=c,
disp=True
)
print(f"external way of keeping track of MINF: {progress_f}")
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论