Pulp 在 options/types 不能相同的地方添加新约束?

Pulp add new constraint where options/types cannot be the same?

下面的代码允许我根据允许的预算 (max_cost) 和选择 (max_to_pick) 优化利润。如何在无法选择同一个城市的情况下添加新约束。

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)

非常感谢!

假设您要限制选择,使列表 city 中的城市最多包含一次,然后按如下方式添加约束即可。它设置了一个约束,使得分配给每个城市的 x 个决策变量的总和最多为 1。

可能有更 pythonic 的方法来创建列表索引。您可以按如下方式在一行中创建所有这些,但我发现它更难遵循:

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)

您可能会发现下面的代码更容易理解,因为它不依赖于索引和索引列表。

此方法的关键在于您可以将对象用作字典键。

因此变量字典(此处为 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)