Сначала вам нужно добавить z
в виде двоичной переменной:
z = m.addVars(I, J, vtype=GRB.BINARY, name="z")
Затем вам понадобятся ограничения, чтобы гарантировать, что z[i, j] = 1
тогда и только тогда, когда c[i, j] <= 150
.Один из способов сделать это - использовать ограничения индикатора:
z = 1 -> c <= 150
z = 0 -> c >= 150
Это эквивалентно
c > 150 -> z = 0
c < 150 -> z = 1
Вы можете добавить их следующим образом:
m.addConstrs((z[i, j] == 1) >> (c[i][j] <= 150) for i in I for j in J)
m.addConstrs((z[i, j] == 0) >> (c[i][j] >= 150) for i in I for j in J)
Вы можететакже смоделируйте это непосредственно: если у вас есть верхняя и нижняя границы M
и m
для значения c[i][j] - 150
(то есть, M >= c[i][j] - 150 >= m
для всех i, j
), вы можете использовать следующие ограничения:
M * (1-z) >= c - 150
m * z <= c - 150
Если c > 150
, правые части обоих неравенств будут положительными.Первый затем заставляет 1 - z = 1
и, следовательно, z = 0
.Второе неравенство будет тривиально выполнено.
Если c < 150
, правые части отрицательны.Первое неравенство становится тривиальным, в то время как второе вынуждает z = 1
.
. Для M
будет использоваться максимальная запись в c
, для m
вы можете выбрать -150
, если все c[i][j]
неотрицательно.
Вы добавляете эти ограничения следующим образом:
m.addConstrs( M * (1 - z[i, j]) >= c[i][j] - 150 for i in I for j in J )
m.addConstrs( m * z[i,j] <= c[i][j] - 150 for i in I for j in J )
Обратите внимание, что я пренебрег случаем, когда c = 150
.Это связано с тем, что для чисел с плавающей точкой равенства всегда считаются выполненными только в пределах допусков и, следовательно, нет простого способа отличить строгие и нестрогие неравенства.Вы можете аппроксимировать это эпсилоном, например:
z = 0 -> c >= 150 + epsilon