Pulp добавить новое ограничение, где параметры / типы не могут быть одинаковыми? - PullRequest
0 голосов
/ 28 марта 2020

Код ниже позволяет мне оптимизировать прибыль на основе бюджета (max_cost) и разрешенных пиков (max_to_pick). Как мне go добавить новое ограничение, когда я не могу выбрать один и тот же город.

from pulp import *

  # PROBLEM DATA:
  costs = [15, 25, 35, 40, 45, 55]
  profits = [1.7, 2, 2.4, 3.2, 5.6, 6.2]
  # city = ["NYC","SF","LA","SF","NYC","LA"]   NEW CONSTRAINTS
  max_cost = 200
  max_to_pick = 4

  # DECLARE PROBLEM OBJECT:
  prob = LpProblem("Mixed Problem", LpMaximize)

  # VARIABLES
  n = len(costs)
  N = range(n)
  x = LpVariable.dicts('x', N, cat="Binary")

  # OBJECTIVE
  prob += lpSum([profits[i]*x[i] for i in N])

  # CONSTRAINTS
  prob += lpSum([x[i] for i in N]) <= max_to_pick        # Limit number to include
  prob += lpSum([x[i]*costs[i] for i in N]) <= max_cost  # Limit max. cost

  # SOLVE & PRINT RESULTS
  prob.solve()
  print(LpStatus[prob.status])
  print('Profit = ' + str(value(prob.objective)))
  print('Cost = ' + str(sum([x[i].varValue*costs[i] for i in N])))

  for v in prob.variables ():
  print (v.name, "=", v.varValue)

Большое спасибо!

Ответы [ 2 ]

1 голос
/ 31 марта 2020

Возможно, вам будет проще следовать приведенному ниже коду, поскольку он не опирается на индексы и списки индексов.

Ключом к этому подходу является то, что вы можете использовать объект в качестве ключа словаря.

Таким образом, словарь переменных (здесь x) состоит из пар ключ-значение объекта Facility, LPVariable.

from pulp import *

class Facility():

    def __init__(self, cost, profit, city):
        self.cost = cost
        self.profit = profit
        self.city = city

    def __str__(self):
        return f"Facility(city={self.city}, profit={self.profit}, cost={self.cost})" 


# PROBLEM DATA:
max_cost = 200
max_to_pick = 4

costs = [15, 25, 35, 40, 45, 55]
profits = [1.7, 2, 2.4, 3.2, 5.6, 6.2]
cities = ["NYC","SF","LA","SF","NYC","LA"] 

facilities = [Facility(cost, profit, city) for cost, profit, city in
              zip(costs, profits, cities)]


# DECLARE PROBLEM OBJECT:
prob = LpProblem("Mixed Problem", LpMaximize)

# VARIABLES
x = LpVariable.dicts('facility', facilities, cat="Binary")

# OBJECTIVE
prob += lpSum([facility.profit * x[facility] for facility in facilities])

# CONSTRAINTS
# number of facilities
prob += lpSum(x.values()) <= max_to_pick # Limit number to include

# maximum cost
prob += lpSum([facility.cost * x[facility] for facility in facilities]) <= max_cost

# no city more than once
# loop through unique city names
# add a constraint that the sum of matching facilities <= 1
unique_cities = set([facility.city for facility in facilities])
for city in unique_cities:
    prob += lpSum([x[facility] for facility in facilities if facility.city == city]) <= 1

# solve the problem
prob.solve()

# identify the chosen facilities
# object_variable_d swaps keys and values
# so you can find the Facility object from the LpVariable
# all of the LpVariables are unique, so this should work
object_variable_d = {v: k for k, v in x.items()}
chosen_facilities = [object_variable_d[var] 
                     for var in prob.variables() 
                     if var.value() == 1]

# print out results
print(LpStatus[prob.status])
print(f'Profit = {value(prob.objective)}')
print(f'Cost = {sum([facility.cost for facility in chosen_facilities])}')
for facility in chosen_facilities:
    print(facility)
1 голос
/ 29 марта 2020

Предполагая, что вы хотите ограничить варианты, чтобы города в списке city были включены не более одного раза, добавьте следующие ограничения: Он устанавливает ограничение таким образом, чтобы сумма x переменных решения, выделенных для каждого города, была не более 1.

Может быть более pythoni c способ создания индексов списка. Вы можете создать их все в один слой следующим образом, но мне будет сложнее следовать:

list_of_lists_of_indices = [[i for i in N if city[i] == c] for c in set(city)]

from pulp import *
# PROBLEM DATA:
costs = [15, 25, 35, 40, 45, 55]
profits = [1.7, 2, 2.4, 3.2, 5.6, 6.2]
city = ["NYC","SF","LA","SF","NYC","LA"] # NEW CONSTRAINTS

max_cost = 200
max_to_pick = 4
# DECLARE PROBLEM OBJECT:
prob = LpProblem("Mixed Problem", LpMaximize)
# VARIABLES
n = len(costs)
N = range(n)
x = LpVariable.dicts('x', N, cat="Binary")
# OBJECTIVE
prob += lpSum([profits[i]*x[i] for i in N])
# CONSTRAINTS
prob += lpSum([x[i] for i in N]) <= max_to_pick        # Limit number to include
prob += lpSum([x[i]*costs[i] for i in N]) <= max_cost  # Limit max. cost

# NEW CONSTRAINT
for c in set(city):
  index_list = [i for i in N if city[i] == c]
  prob += lpSum([x[i] for i in index_list]) <= 1

# SOLVE & PRINT RESULTS
prob.solve()
print(LpStatus[prob.status])
print('Profit = ' + str(value(prob.objective)))
print('Cost = ' + str(sum([x[i].varValue*costs[i] for i in N])))

for v in prob.variables ():
    print (v.name, "=", v.varValue)
...