You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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.1
  • x_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 ≥ 0
  • y0 + 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 15:44:54