Pyomo AbstractModel 和 Python 字典

Pyomo AbstractModel and Python Dictionaries

我是 Pyomo 的新手,我从一些小例子开始,通过理解和测试它们。现在我想使用 Python 字典重写一个更复杂的示例我想重写的示例来自 Pyomo Gallery:

https://nbviewer.jupyter.org/github/Pyomo/PyomoGallery/blob/master/diet/DietProblem.ipynb

作为如何使用 Python 词典与 pyomo 的示例,我采用了以下内容:

https://pyomo.readthedocs.io/en/stable/working_abstractmodels/data/raw_dicts.html

自从我开始的两天以来,我一直在围绕移动索引盘旋字典,并希望我的重新实现能够工作,但我只是不知道正确的方法是什么。为什么当前的方法不起作用。有时我改变了一些关于字典结构的东西并收到了不同的错误消息,然后我继续下一个并且(解决它,或者只是改变它)并且旧的再次弹出。

我只是提供我目前的状态,非常感谢您的帮助。一个可行的解决方案可能会帮助我理解如何使用 Python 字典对数据建模。

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))}

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))}

data = {None: {
    'F': {None: F}, 
    'N': {None: N}, 
    'a': a,
    'Vmax': {None: Vmax},
    }}

model = pyo.AbstractModel()

solver          = 'gurobi'
solver_io       = 'python'
stream_solver   = False     # True prints solver output to screen
keepfiles       = False     # True prints intermediate file names (.nl,.sol,...)

opt = SolverFactory(solver, solver_io = solver_io)
opt.options['outlev'] = 1 # tell gurobi to be verbose with output
opt.options['solnsens'] = 1
opt.options['bestbound'] = 1

# Foods
model.F = pyo.Set()
# Nutrients
model.N = pyo.Set()

# Cost of each food
model.c    = pyo.Param(model.F, within = pyo.PositiveReals)
# Amount of nutrient in each food
model.a    = pyo.Param(model.F, model.N, within = pyo.NonNegativeReals)
# Lower and upper bound on each nutrient
model.Nmin = pyo.Param(model.N, within = pyo.NonNegativeReals, default = 0.0)
model.Nmax = pyo.Param(model.N, within = pyo.NonNegativeReals, default = inf)
# Volume per serving of food
model.V    = pyo.Param(model.F, within = pyo.PositiveReals)
# Maximum volume of food consumed
model.Vmax = pyo.Param(within = pyo.PositiveReals)

# Number of servings consumed of each food
model.x = pyo.Var(model.F, within = pyo.NonNegativeIntegers)

# Minimize the cost of food that is consumed
def cost_rule(model):
    return sum(model.c[i] * model.x[i] for i in model.F)
model.cost = pyo.Objective(rule = cost_rule)

# Limit nutrient consumption for each nutrient
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)

# Limit the volume of food consumed
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)

你 运行 遇到了问题,因为你要求 pyomo 阅读你的字典 就好像 它们是一个 .dat 文件,就像你引用的例子一样。它不能那样做。它可以读取具有由同一键集索引的多个项目的多列 .dat 文件,但(据我所知)不能从 python 字典中执行相同的操作。所以你有几个选择...

  1. 分解你的字典,并有 个人 的成本,价值等。这应该是一个微不足道的修复,然后更新你的 data型号。

  2. 只需像您引用的示例那样将您的数据填充到一个单独的 .dat 文件中,就可以了

  3. 换档 ConcreteModel() 并忘记保持模型和数据分离。 Python 非常擅长整理文件和数据表,所以我几乎总是选择让 python 整理,然后根据创建的词典制作 ConcreteModel()。在不更改任何词典的情况下,您可以这样做:

model = pyo.ConcreteModel('chow time')
# Foods
model.F = pyo.Set(initialize=F.keys())
# Nutrients
model.N = pyo.Set(initialize=N.keys())

# Cost of each food
model.c    = pyo.Param(model.F, within = pyo.PositiveReals, initialize = {k:v['c'] for k,v in F.items()})
# Volume per serving of food
model.V    = pyo.Param(model.F, within = pyo.PositiveReals, initialize = {k:v['V'] for k,v in F.items()})