通过 Gurobi Python 添加变量和约束的有效方法,无需枚举所有元素

Efficient way to add variables and constraints through Gurobi Python without enumerating through all elements

我正在学习通过 Gurobi python 构建优化模型,但我在寻找 pythonic 定义决策变量和约束的方法时遇到了一些问题:

假设我有这些集合:

time={morning, afternoon, evening};
interval={early,late};
food={burger, banana, apple, orange};

我的决策变量是二元吃[时间、间隔、食物]。但是,我只有一组已定义的可能选项,如下所示,无法枚举我的集合中的所有元素:

time      interval  food  number  value
morning   early   banana   2      500
morning   early   apple    3      600
afternoon early   burger   1      800
evening    late   orane    2      400

所以我的吃变量只能是以下:

eat[morning,early,banana]
eat[morning,early,apple]
eat[afternoon,early,burger]
eat[evening,late,orange]

我做不到:

eat = m.addVars(time, interval, food, name = "Eat", vtype=GRB.BINARY)

我可以这样做:

eat = {}
for row in input.to_dict('records'):
         key = (row['time'], row['interval'],row['food'])
         eat[key] =  m.addVar(name = "Eat", vtype=GRB.BINARY)

但我仍然无法定义我的 objective,它是乘以数字和价值,然后吃,我正在寻找一种更一致、更优雅的方式:

obj = quicksum(number[i,j,k]*value[i, j, k] * eat[i, j, k] for i in time 
for j in interval for k in food)

以上将列举所有错误的地方,我试过这样的事情:

obj = quicksum(number[key]*value[key] * eat[key] \
                 for key in eat)

这将它限制为仅在字典中定义的组合,但是当我必须像下面这样分隔字典的元素时,我正在为约束而苦苦挣扎:

m.addConstrs(quicksum(eat[i,j,k] for k in food)==1 for i in time for j in interval)

或类似

m.addConstrs(quicksum(eat[morning,j,banana] ==1) for j in interval)

抱歉,问题很长。 optimization/python 专家的任何帮助都会很棒。

它可能会帮助您利用 Gurobi Python API 必须存储变量的 tupledict 结构。它有一些方便的方法,可以让您轻松地对变量求和、乘法或切片。我在下面提供了一个完整的例子。

from gurobipy import GRB, Model
import numpy as np

tuples = [('morning', 'early', 'banana'),('morning', 'early', 'apple'), 
('afternoon', 'early', 'burger'), ('evening', 'late', 'orane')]

numbers, values = [2, 3, 1, 2], [500, 600, 800, 400]

m = Model('SO52451928')

eat = m.addVars(tuples, name='eat', vtype=GRB.BINARY)

coeffs = np.array(numbers) * np.array(values) # Can be made with regular lists as well
coeffs = dict(zip(tuples, coeffs))

obj = eat.prod(coeffs)
m.setObjective(obj)

# This structure holds the unique combinations of (time, interval) that 
# appear in the data. They are necessary, because they form the set over which
# our constraints are defined
time_intervals = set(zip(*zip(*tuples)[:2]))

constrs = m.addConstrs((
    eat.sum(i, j, '*') == 1 for i, j in time_intervals), name='one_food')

m.write(m.ModelName+'.lp')
m.optimize()

if m.SolCount > 0:
    print(zip(m.getAttr(
    'VarName', m.getVars()), m.getAttr('x', m.getVars())))

希望对您有所帮助!