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

Pyomo非线性优化中实现目标变量为指定倍数的问题求助

问题背景与目标

已知销售份额与空间份额的关系:
$S=B^b$
$\log(S)=b*\log(B)$ # 这是目标函数#

其中:

  • S=销售份额,即“品类销售额/部门销售额”
  • b=空间隔间份额,即“品类空间隔间数/部门空间隔间数”

目标函数实现代码如下:

model.objective = pyomo.Objective(rule= sum( exp(log( model.space[c] /  model.sapce_sum[c] )  *    model.sales_coeff[c][0]  +   model.sales_intercept[c]
                 )  *      model.sales_sum[c] for c in   model.dept_cat_nbr   ), sense=pyomo.maximize)

通过回归模型得到系数用于销售预测,根据空间隔间数计算销售额。其中:

  • space[c]=品类级空间隔间数
  • model.space_sum[c]=部门级空间隔间数
  • (model.space[c]/model.sapce_sum[c])=空间隔间份额,用于调用预计算的系数
  • model.dept_cat_nbr为类似'90_1400'的索引集合
  • model.space_bay为待优化变量,用于定义各品类的空间分配以优化需求
  • model.multiple为参数,取值为0.5或1,用于控制品类是否占用半格或整格货架

期望输出:

  • 对于半格品类(如'90_1400'),model.space_bay需为2.5、3这类0.5的倍数,而非2.7
  • 对于整格品类(如'95_1200'),model.space_bay需为3、4这类整数,而非3.5、4.7
尝试的两种方法及问题

方法1:取模约束

尝试通过以下约束实现倍数要求:

def abide_space_multiples(model,i):
    return  model.space_bay[i]% model.multiple[i]==0
model.space_multiple_cons = pyomo.Constraint(model.dept_cat_nbr,rule = abide_space_multiples)

其中model.multiple[i]示例:{'95_1200':0.5, '95_4200':0.5,...}

结论:失败,Pyomo不支持%运算符

方法2:整数变量转换

定义整数变量model.space_bay_integer,通过约束使目标变量model.space_bay为其与model.multiple[i]的乘积:

# Define Bays only in integer terms
model.space_bay_integer=pyomo.Var(model.dept_cat_nbr, domain=pyomo.Integers)

## Second Variable(Target Variable)
# Lower and Upper Bound
model.bay_lb=pyomo.Param(model.dept_cat_nbr, initialize={df_sum_wt.loc[i,'dept_catg']: df_sum_wt.loc[i,'min_bay'] for i in range(len(df_sum_wt))})
model.bay_ub=pyomo.Param(model.dept_cat_nbr, initialize={df_sum_wt.loc[i,'dept_catg']: df_sum_wt.loc[i,'max_bay'] for i in range(len(df_sum_wt))})

model.space_bay = pyomo.Var(model.dept_cat_nbr, domain = pyomo.NonNegativeReals, bounds = {i: (model.bay_lb[i],model.bay_ub[i]) for i in model.dept_cat_nbr})

# create space constraint 
def abide_space_multiples(model,i):
    return  model.space_bay[i]==model.space_bay_integer[i]*model.multiple[i]
model.space_multiple_cons = pyomo.Constraint(model.dept_cat_nbr,rule = abide_space_multiples)

结论:失败,使用IPOPT等非线性求解器时,model.space_bay_integer未保持整数域,返回分数值(如'92_1802':4.4099...),导致model.space_bay也不是指定倍数。而线性求解器(如GLPK、CPLEX)不支持含log和exp的非线性目标函数。

可行解决方案

要解决非线性优化场景下的整数/半整数约束问题,核心是使用支持混合整数非线性规划(MINLP)的求解器,同时优化变量定义与目标函数:

1. 更换为MINLP求解器

替换IPOPT为支持非线性目标+整数变量约束的求解器,比如:

  • Bonmin:开源MINLP求解器,适合处理此类问题
  • Couenne:开源全局优化求解器,适配非凸MINLP场景
  • Gurobi/CPLEX:商业求解器,部分版本支持非线性MINLP(需确认版本特性)

以Bonmin为例,Pyomo中调用方式:

from pyomo.environ import SolverFactory
solver = SolverFactory('bonmin')
result = solver.solve(model, tee=True)

2. 优化变量约束定义

保留整数变量转换思路,可拆分变量类型减少浮点数误差:

# 定义整数变量
model.space_bay_int = pyomo.Var(model.dept_cat_nbr, domain=pyomo.Integers)

# 约束逻辑:整格品类直接等于整数变量,半格品类为整数变量*0.5
def space_bay_rule(model, i):
    if model.multiple[i] == 1:
        return model.space_bay[i] == model.space_bay_int[i]
    else:
        return model.space_bay[i] == model.space_bay_int[i] * 0.5
model.space_bay_constraint = pyomo.Constraint(model.dept_cat_nbr, rule=space_bay_rule)

这种拆分更清晰,降低求解器处理浮点数倍数的复杂度。

3. 简化目标函数运算

原目标函数中exp(log(x))可等价替换为x,减少非线性运算层级,提升求解稳定性:

model.objective = pyomo.Objective(
    rule=sum(
        (model.space[c] / model.space_sum[c]) ** model.sales_coeff[c][0] 
        * exp(model.sales_intercept[c]) 
        * model.sales_sum[c] 
        for c in model.dept_cat_nbr
    ), 
    sense=pyomo.maximize
)

注:由$\log(S) = b*\log(B) + intercept$推导得$S = B^b * \exp(intercept)$,此等价转换能减少嵌套运算,降低求解难度。

内容的提问来源于stack exchange,提问作者stat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 15:35:23