Python PuLP 在 Text/Categorical 字段上设置约束

Python PuLP Set Constraint on Text/Categorical Field

我正在使用 PuLP 解决贷款优化问题的最小化问题。下面的代码输出具有当前约束(资本要求和最大提取金额)的正确贷款组合。

from pulp import *

class Loan():

def __init__(self, id, interest_rate, drawdown_amount, lender, min_drawdown, max_drawdown):
    self.id = id
    self.interest_rate = interest_rate
    self.drawdown_amount = drawdown_amount
    self.lender = lender
    self.min_drawdown = min_drawdown
    self.max_drawdown = max_drawdown

def __str__(self):
    return f"loan(id={self.id}, lender={self.lender}, drawdown_amount={self.drawdown_amount}, interest_rate={self.interest_rate}, min_drawdown={self.min_drawdown}, max_drawdown={self.max_drawdown})" 


# PROBLEM DATA:
    
capital_requirement = 1200000

ids = ["WF_1", "BA_1", "BA_2", "JP_1"] 
interest_rates = [0.05, 0.03, 0.02, 0.04]
drawdown_amounts = [1,1,1,1,1]
lenders = ["Wells Fargo", "Bank of America" , "Bank of America", "JPMorgan"] 
min_drawdowns = [75000, 100000, 300000, 80000]
max_drawdowns = [500000, 500000, 500000, 500000]

loans = [Loan(id, interest_rate, drawdown_amount, lender, min_drawdown, max_drawdown ) for id, interest_rate, drawdown_amount, lender, min_drawdown, max_drawdown in
              zip(ids, interest_rates, drawdown_amounts, lenders, min_drawdowns, max_drawdowns)]


# DECLARE PROBLEM OBJECT
prob = LpProblem("Loan Optimiser", LpMinimize)

# VARIABLES
loanVars = LpVariable.dicts('loans', loans, 0)

# OBJECTIVE
prob += lpSum([loan.interest_rate * loanVars[loan] for loan in loans])

# CONSTRAINTS
# Amount of money to borrow:
prob += lpSum([loan.drawdown_amount * loanVars[loan] for loan in loans]) == capital_requirement 

# If a loan is included, it must be below the maximum drawdown amount of that loan:
for loan in loans:
    prob += loanVars[loan] <= loan.max_drawdown * loanVars_selected[loan]

资本要求为 1.2m 的示例输出:

---------The optimal loans to use for borrowing € 1200000.0 are----------

0000.0 of JP_1

0000.0 of BA_1

0000.0 of BA_2

Total Interest Cost = 000.00 Total Interest Rate = 2.75 %

我想添加一个约束,以便贷方只能在输出中出现一次,在上面的示例中,这将从输出中删除 BA_1 并添加 WF_1.

我为此约束编写的代码如下,但未正确应用逻辑:

unique_lenders = set([loan.lender for loan in loans])
print(unique_lenders)
for lender in unique_lenders:
   prob += lpSum([loanVars[loan] for loan in loans if loan.lender == lender]) >= 1

提前致谢。

编辑:

我使用二进制变量 loanVars_selected 和以下基于 Erwins 答案的代码得到了约束:

for lender in unique_lenders:
prob += lpSum(loanVars_selected[loan] for loan in loans if loan.lender == lender) <= 1 

我认为您希望每笔贷款都有一个二元变量。然后添加:

  loanVars[loan] <= b[loan]*maxLoan[loan]

  for each lender L:
         sum(for all loans issued by L,b[loan]) <= 1  

(为了清楚起见,我使用了伪代码)