Эффективный способ добавления переменных и ограничений через Gurobi Python без перечисления всех элементов - PullRequest
0 голосов
/ 22 сентября 2018

Я учусь строить модели оптимизации с помощью Python Gurobi, и у меня возникают некоторые проблемы с поиском питонского способа определения переменных решения и ограничений:

Предполагая, что у меня есть эти наборы:

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)

Но у меня все еще есть проблема с определением моей цели, которая заключается в умножении числа и стоимости и еды, и я ищуболее последовательный, элегантный способ:

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)

Извините за длинные вопросы.Любая помощь от экспертов по оптимизации / питону будет отличной.

1 Ответ

0 голосов
/ 22 сентября 2018

Это может помочь вам использовать структуру tupledict , которую API Gurobi Python должен хранить переменные.У него есть несколько удобных методов, которые позволяют легко суммировать, умножать или нарезать переменные.Ниже приведен полный пример.

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

Надеюсь, это поможет!

...