如何在scipy优化过程中拒绝超出约束范围的局部最小值
关于scipy trust-constr方法约束校验的解决方案
scipy.optimize.minimize 使用trust-constr方法求解后返回的OptimizeResult对象,本身就内置了约束校验相关的属性,不需要额外修改迭代逻辑,你只要在局部优化结束后对返回结果做校验,就能筛选出符合约束的局部最小值。
核心校验属性
trust-constr返回的结果包含两个可直接用于约束判断的属性:
status:求解器结束状态码,仅当status == 0时代表求解正常结束,且最终结果满足所有预设约束constr_violation:当前结果的约束违反总量,所有约束都满足时该值为0,数值越高代表违反约束的程度越高
结合basinhopping的实现方式
你可以自定义局部优化的包装函数,在每次调用trust-constr完成后先做约束校验,符合要求就返回当前结果,不符合就返回上一轮的可行局部最小值,不需要拒绝整个basinhopping步骤:
from scipy.optimize import basinhopping, minimize # 替换为你自己的目标函数、约束、边界定义 def objective(x): return x[0]**2 + x[1]**2 constraints = [{"type": "eq", "fun": lambda x: x[0] + x[1] - 1}] bounds = [(-2, 2), (-2, 2)] last_feasible_res = None def filtered_local_min(x): global last_feasible_res # 调用trust-constr求解局部最小值 res = minimize( objective, x, method="trust-constr", bounds=bounds, constraints=constraints ) # 校验约束(加1e-6阈值避免浮点误差影响) if res.status == 0 and res.constr_violation < 1e-6: last_feasible_res = res return res # 不符合约束时返回上一个可行解 if last_feasible_res is not None: return last_feasible_res # 首次求解就无可行解时,将目标函数设为极大值避免basinhopping采纳 res.fun = 1e10 return res # basinhopping调用时指定自定义的局部优化器 result = basinhopping( objective, x0=[0, 0], local_minimizer=filtered_local_min )
可选细粒度控制
如果需要在迭代过程中提前拦截不符合约束的迭代点,可以给minimize传入callback回调函数,每一步迭代都会触发回调,你可以在回调中校验当前迭代点的约束满足情况,不符合要求就返回True提前终止本次局部优化,减少无效计算。
内容的提问来源于stack exchange,提问作者Antoto
相关产品推荐
相关产品推荐

