Pyomo AbstractModel搭配Python字典改写膳食问题遇错求助
Pyomo抽象模型字典对接膳食规划问题解决方案
修改要点
- 修正营养字段名称错误:将原合并的
Carbo Protein拆分为两个独立字段Carbo、Protein,使营养名称列表长度与营养需求矩阵、食物营养矩阵维度对齐 - 重构数据字典结构:按照Pyomo抽象模型字典数据规范,拆分集合、参数的赋值逻辑,将嵌套在集合中的参数(成本
c、体积V、营养下限Nmin、营养上限Nmax)单独提取为独立的Param字段 - 修正无效值:将营养上限的
None替换为正无穷inf,匹配Param的默认值规则,避免类型报错
可运行完整代码
from __future__ import division import pyomo.environ as pyo from pyomo.opt import SolverFactory from math import inf food_keys = ['Cheeseburger', 'Ham Sandwich', 'Hamburger', 'Fish Sandwich', 'Chicken Sandwich', 'Fries', 'Sausage Biscuit', 'Lowfat Milk', 'Orange Juice'] cost_vol_keys = ['c', 'V'] cost_vol = [[1.84, 4.0], [2.19, 7.5], [1.84, 3.5], [1.44, 5.0], [2.29, 7.3], [.77, 2.6], [1.29, 4.1], [.60, 8.0], [.72, 12.0]] F = {food_keys[i]: {cost_vol_keys[j]: cost_vol[i][j] for j in range(len(cost_vol_keys))} for i in range(len(food_keys))} # 修正营养字段,拆分Carbo和Protein为两个独立字段 nutrition_keys = ['Cal', 'Carbo', 'Protein', 'VitA', 'VitC', 'Calc', 'Iron'] nutrition_req_keys = ['Nmin', 'Nmax'] nutrition_req = [ [2000, None], [ 350, 375], [ 55, None], [ 100, None], [ 100, None], [ 100, None], [ 100, None] ] N = {nutrition_keys[i]: {nutrition_req_keys[j]: nutrition_req[i][j] for j in range(len(nutrition_req_keys))} for i in range(len(nutrition_keys))} Vmax = 75.0 nutrition = [ [510, 34, 28, 15, 6, 30, 20], [370, 35, 24, 15, 10, 20, 20], [500, 42, 25, 6, 2, 25, 20], [370, 38, 14, 2, 0, 15, 10], [400, 42, 31, 8, 15, 15, 8], [220, 26, 3, 0, 15, 0, 2], [345, 27, 15, 4, 0, 20, 15], [110, 12, 9, 10, 4, 30, 0], [ 80, 20, 1, 2, 120, 2, 2] ] a = {(food_keys[i], nutrition_keys[j]): nutrition[i][j] for j in range(len(nutrition_keys)) for i in range(len(food_keys))} # 拆分参数为Pyomo要求的独立字典格式 c_dict = {f: F[f]['c'] for f in food_keys} v_dict = {f: F[f]['V'] for f in food_keys} nmin_dict = {n: N[n]['Nmin'] for n in nutrition_keys} nmax_dict = {n: N[n]['Nmax'] if N[n]['Nmax'] is not None else inf for n in nutrition_keys} # 重构符合规范的data字典 data = {None: { 'F': {None: food_keys}, 'N': {None: nutrition_keys}, 'c': c_dict, 'V': v_dict, 'Nmin': nmin_dict, 'Nmax': nmax_dict, 'a': a, 'Vmax': {None: Vmax}, }} model = pyo.AbstractModel() # 求解器配置:若无Gurobi可替换为cbc/glpk,删除Gurobi专属的opt.options配置即可 solver = 'gurobi' solver_io = 'python' stream_solver = False keepfiles = False opt = SolverFactory(solver, solver_io = solver_io) opt.options['outlev'] = 1 opt.options['solnsens'] = 1 opt.options['bestbound'] = 1 # 模型定义部分无需修改 model.F = pyo.Set() model.N = pyo.Set() model.c = pyo.Param(model.F, within = pyo.PositiveReals) model.a = pyo.Param(model.F, model.N, within = pyo.NonNegativeReals) model.Nmin = pyo.Param(model.N, within = pyo.NonNegativeReals, default = 0.0) model.Nmax = pyo.Param(model.N, within = pyo.NonNegativeReals, default = inf) model.V = pyo.Param(model.F, within = pyo.PositiveReals) model.Vmax = pyo.Param(within = pyo.PositiveReals) model.x = pyo.Var(model.F, within = pyo.NonNegativeIntegers) def cost_rule(model): return sum(model.c[i] * model.x[i] for i in model.F) model.cost = pyo.Objective(rule = cost_rule) def nutrient_rule(model, j): value = sum(model.a[i, j] * model.x[i] for i in model.F) return pyo.inequality(model.Nmin[j], value, model.Nmax[j]) model.nutrient_limit = pyo.Constraint(model.N, rule = nutrient_rule) def volume_rule(model): return sum(model.V[i] * model.x[i] for i in model.F) <= model.Vmax model.volume = pyo.Constraint(rule = volume_rule) model_instance = model.create_instance(data) model_instance.pprint() results = opt.solve(model_instance, keepfiles = keepfiles, tee = stream_solver) # 输出求解结果 print("\n最优解:") for f in model_instance.F: if pyo.value(model_instance.x[f]) > 1e-6: print(f"{f}: {pyo.value(model_instance.x[f])} 份") print(f"最低总成本:{round(pyo.value(model_instance.cost), 2)} 元")
内容的提问来源于stack exchange,提问作者baxbear
相关产品推荐
相关产品推荐

