scipy.optimize.minimize动态约束生成及求解失效问题排查
问题排查与适配方案
故障原因
- 约束函数使用了非法的布尔逻辑:改造后的
eq_const_1中使用==判断返回True/False布尔值,求和后为离散整数,不符合SLSQP优化器对约束函数连续可导的要求。该函数梯度几乎处处为0,优化器无法找到迭代方向,会直接停在初始值,导致所有约束都未生效。 - 多约束合并逻辑不符合优化器要求:原本的多条约束要求每一对相邻项的比值差严格为0,合并为布尔求和的方式完全改变了约束的数学性质,优化器无法正确解析约束条件。
通用适配实现
动态生成与number_periods匹配的约束列表即可,逻辑和硬编码实现完全一致,同时规避lambda延迟绑定的常见坑:
import numpy as np from scipy.optimize import minimize clear_payments = np.array([90,100,110,120,130,120,110,100,90]) future_value_of_aim = 470 d_r = 0.12 def discoun_coeff(per,d_r): x = np.ones(per+1) k = np.empty(per+1) for i in range(per+1): k[i]=x[i]*(1+d_r)**i return k[::-1] def aim(X): return np.sum(X) def paymets_year(clear_payments, number_periods): payments = clear_payments[:number_periods+1] X = np.ones(number_periods+1) # 初始化约束列表,先加入折现求和等于目标值的约束 constraints = [ {'type':'eq', 'fun': lambda x: np.sum(x*discoun_coeff(number_periods,d_r))-future_value_of_aim} ] # 动态生成相邻项比值相等的约束,用参数默认值捕获当前索引,避免lambda延迟绑定问题 for i in range(number_periods): constraints.append( {'type':'eq', 'fun': lambda x, idx=i: (payments[idx]/x[idx] - payments[idx+1]/x[idx+1])} ) bounds = ((0,70),)*(number_periods+1) res = minimize(aim, X, method='SLSQP', constraints=constraints, bounds=bounds) return res.x # 测试验证 number_periods = 6 p = paymets_year(clear_payments, number_periods) print(p)
运行后输出结果和原硬编码实现完全一致:
[38.34895684 42.60995205 46.87094726 51.13194246 55.39293767 51.13194246 46.87094726]
内容的提问来源于stack exchange,提问作者Anton Dorogov
相关产品推荐
相关产品推荐

