使用basinhopping优化时,如何强制系数间最小间距为0.1?
问题描述
我正在使用scipy.optimize.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。如果排序有助于实现该约束,我也可以接受。请问实现该需求的最佳方式是什么?
实现方案
最简洁高效的方式是通过变量替换将约束转化为简单边界约束问题,利用排序简化处理逻辑,具体步骤如下:
1. 变量替换逻辑
假设我们有3个变量x1, x2, x3,先对其排序得到x_sorted[0] ≤ x_sorted[1] ≤ x_sorted[2],此时"两两间距≥0.1"的约束等价于:
x_sorted[1] ≥ x_sorted[0] + 0.1x_sorted[2] ≥ x_sorted[1] + 0.1
我们定义新变量完成约束转化:
y0 = x_sorted[0] y1 = x_sorted[1] - x_sorted[0] - 0.1 y2 = x_sorted[2] - x_sorted[1] - 0.1
此时所有y变量的边界变为:
y0 ∈ [0, 0.8](剩余两个变量至少需要0.2的空间)y1 ≥ 0,y2 ≥ 0y0 + y1 + y2 ≤ 0.8(保证最终变量不超过1的上限)
再通过y变量还原出排序后的x:
x_sorted[0] = y0 x_sorted[1] = y0 + y1 + 0.1 x_sorted[2] = y0 + y1 + y2 + 0.2
2. 修改代码实现
将原目标函数包装为适配新变量的函数,同时调整初始值和边界:
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]: # 还原为排序后的x变量打印 x_sorted = [ xx[0], xx[0] + xx[1] + 0.1, xx[0] + xx[1] + xx[2] + 0.2 ] print([round(x, 2) for x in x_sorted], f) MIN.append(f) return fn # 原x0=(0.4,0.6,0.8)转换为新变量初始值 y0 = (0.4, 0.1, 0.1) # 新变量的边界设置 y_bounds = [ (0, 0.8), (0, 0.7), (0, 0.6) ] # 包装目标函数:输入y变量,还原为x_sorted后计算rosen值 def constrained_rosen(y): x_sorted = [ y[0], y[0] + y[1] + 0.1, y[0] + y[1] + y[2] + 0.2 ] return rosen(x_sorted) minimizer_kwargs = dict(method="L-BFGS-B", bounds=y_bounds) progress_f = [0] c = build_show_bh(progress_f) print("Optimizing using basinhopping with spacing constraint") res = basinhopping( constrained_rosen, y0, minimizer_kwargs=minimizer_kwargs, niter=10, callback=c, disp=True ) # 还原最终结果的x变量 final_y = res.x final_x_sorted = [ final_y[0], final_y[0] + final_y[1] + 0.1, final_y[0] + final_y[1] + final_y[2] + 0.2 ] print(f"Final sorted x with spacing constraint: {[round(x,2) for x in final_x_sorted]}") print(f"external way of keeping track of MINF: {progress_f}")
3. 方案优势
- 避免了复杂的非线性约束处理,直接通过变量替换将约束转化为简单的边界约束,适配
L-BFGS-B这类支持边界的优化器 - 利用排序简化了约束逻辑,不需要处理所有两两变量的组合约束
- 计算效率高,不会因为约束引入额外的计算开销
如果需要保留原变量的顺序,可以在目标函数中加入排序还原的映射,但全局优化中变量顺序通常不影响结果,排序后的处理更简洁。
内容的提问来源于stack exchange,提问作者Simd
相关产品推荐
相关产品推荐

