Добавить бинарную переменную размером n в Gurobi - PullRequest
0 голосов
/ 20 октября 2018

Я пытаюсь реализовать модель оптимизации местоположения объекта в Gurobi (интерфейс Python).У меня есть некоторые трудности с переводом модели.Математическая модель показана ниже:

enter image description here

где dloc, floc - координаты (x, y) спроса (клиента) и объекта (склада)) места.Величины dloc - это константы (то есть 50), а не floc, которые являются переменными решения: они рассчитываются решателем.кроме того, координаты x, y являются числами с плавающей точкой от 0 до 100.

Одна из ключевых проблем заключается в том, что я не знаю, как добавить переменную объекта, число которой может быть любым от 0 до n.

мои коды на данный момент:

from gurobipy import *
import numpy as np
import math


def distance(a, b):
    dx = a[0] - b[0]
    dy = a[1] - b[1]
    return math.sqrt(dx ** 2 + dy ** 2)

customer = np.random.uniform(0,100,[50,2])
print(customer)

m = Model()

n = m.addVar(lb=0.0, ub=GRB.INFINITY,vtype=GRB.INTEGER) #number of candidate facilities

facility={}
for j in range(n):
    facility[j] = m.addVar(vtype=GRB.BINARY, name="facility%d" % j) #certainly this is not correct, as an error is reported as 'Var' object cannot be interpreted as an integer

floc = ? 

Итак, я попробовал другой способ, вручную установив фиксированное число объектов-кандидатов в качестве временного обходного пути:

from gurobipy import *
import numpy as np
import math

customer = np.random.uniform(0,100,[50,2])
print(customer)

m = Model()

###Variable
dc={}
x={}
y={}
assign={}

for j in range(10):
    dc[j] = m.addVar(lb=0,ub=1,vtype=GRB.BINARY, name="DC%d" % j)
    x[j]= m.addVar(lb=0, ub=100, vtype=GRB.CONTINUOUS, name="x%d")
    y[j] = m.addVar(lb=0, ub=100, vtype=GRB.CONTINUOUS, name="y%d")
for i in range(len(customer)):

    for j in range(len(dc)):
        assign[(i,j)] = m.addVar(lb=0,ub=1,vtype=GRB.BINARY, name="Cu%d from DC%d" % (i,j))

###Constraint
for i in range(len(customer)):
    for j in range(len(dc)):
        m.addConstr(((customer[i][0] - x[j])*(customer[i][0] - x[j]) +\
                              (customer[i][1] - y[j])*(customer[i][1] - y[j])) <= 40*40 + 100*100*(1-assign[(i,j)]))

for i in range(len(customer)):
    m.addConstr(quicksum(assign[(i,j)] for j in range(len(dc))) == 1)

for i in range(len(customer)):
    for j in range(len(dc)):
        m.addConstr(assign[(i, j)] <= dc[j])

n=0
for j in dc:
    n=n+dc[j]

m.setObjective(n,GRB.MINIMIZE)

m.optimize()

print('\nOptimal Solution is: %g' % m.objVal)
for v in m.getVars():
    print('%s %g' % (v.varName, v.x))

Anyoneмог бы продемонстрировать перевод модели в Gurobi, был бы большим подспорьем.

1 Ответ

0 голосов
/ 21 октября 2018

Я не вижу проблем в вашем определении для n.Тем не менее я переписал ваш код, чтобы сделать его менее подробным и легким для понимания.Сначала мы создаем данные наборы и константы:

from gurobipy import Model, GRB, quicksum
import numpy as np

m = Model()

demo_coords = np.random.uniform(0, 100, size=(50, 2)) # Just for demonstration

# Sets and Constants
demand = [f"i{k}" for k in range(1, 51)]
facilities = [ f"facility{k}" for k in range(1, 11) ]
dloc = {fac : demo_coords[i] for i, fac in enumerate(demand)}
maxdist = 40
M = 10e6

Обратите внимание, что dloc - это словарь, такой, что dloc[i] даст вам координаты для точки спроса i.Тогда dloc[i][0] - это координата x, а dloc[i][1] - координата y.

Теперь мы можем создать переменные и сохранить их в gurobi tubledict :

# Variables
floc = m.addVars(facilities, 2, name="floc")
isopen = m.addVars(facilities, vtype=GRB.BINARY, name="isopen")
assign = m.addVars(demand, facilities, vtype=GRB.BINARY, name="assign")
n = m.addVar(vtype=GRB.INTEGER, name="n")
m.update()

Используя m.addConstrs () , ограничения можно записать в виде

# Constraints
m.addConstrs(((dloc[i][0] - floc[j, 0]) * (dloc[i][0] - floc[j, 0]) \
    + (dloc[i][1] - floc[j, 1])*(dloc[i][1] - floc[j, 1]) \
    <= maxdist**2 + M * (1 - assign[i, j]) \
    for i in demand for j in facilities), name="distance")

m.addConstrs((quicksum(assign[i, j] for j in facilities) == 1\
              for i in demand), name="assignDemand")

m.addConstrs((assign[i, j] <= isopen[j] for i in demand for j in facilities),\
name="closed")

m.addConstr(n == quicksum(isopen[j] for j in facilities), name="numFacilities")

# zip is needed to iterate over all pairs of consecutive facilites
m.addConstrs((isopen[j] >= isopen[jp1] \
    for j, jp1 in zip(facilities, facilities[1:])), name="order")

Обратите внимание, что, хотя записать floc[j, 0] в ограничении для ограничения не проблемарасстояние, вы не можете написать dloc[i, 0], так как dloc - это словарь Python, а floc - это tupledict.

Установка целевой функции и вызов m.optimize()

# Objective
m.setObjective(n, sense=GRB.MINIMIZE)

m.optimize()

if m.status == GRB.OPTIMAL:
    print(f"Optimal Solution is: {m.objVal}")
    print("--------------")
    for var in m.getVars():
        print(var.varName, var.X)

дает мне оптимальное решение n = 3.

...