繁体   English   中英

如何使用Python库PuLP在线性编程中执行均等配给

[英]How to perform equal rationing in Linear Programming using Python library PuLP

我将在以下示例的帮助下解释我的问题。

在这个问题中,我有4个播放器,其中有数量显示的数量和价格显示的价格。 我也有估计数量作为估计。 目标是通过四个玩家使用可用数量来实现估计数量。 而且选择政策是,价格较低的玩家将被优先考虑供应数量。

price = [140, 50, 80, 60]

quantity = [100, 150, 200, 400]

estimate = 400

因此,对于这个问题,每个玩家提供的数量是

supply = [0, 150, 0, 250]

这只是一个简单的示例,数组的实际大小不止于此。 我正在使用Python的PuLP库来解决此线性编程问题。

但是问题是,当所有价格均等时,它会根据指数给出答案,这意味着index0的玩家将首先提供,然后index1的玩家将以此类推。 但是,我的实际要求是在相等定价的情况下将估计数量平均分配给所有参与者。 看例子

price = [60, 60, 60, 60]

quantity = [100, 150, 200, 400]

estimate = 400

输出是

supply = [100 , 150, 150, 0]

我的要求是

supply = [100, 100, 100, 100]

那么,我的问题是,如何解决等额配给问题?

两个想法:

LP

向目标引入一个加权惩罚成分,即供应变量的所有成对差(绝对值!)之和。

优点:

  • 可以表述为LP

缺点:

  • 此惩罚的权重取决于问题,需要调整!
  • 对的数量呈指数增长(与#supplies有关)
    • 导致辅助变量和约束
    • 给定一个快速公式,求解器将开始努力解决N >> 100 (例如,对于N=150 ,求解时间为10秒;取决于bigM
  • 需要重新定义绝对值( lpsolve docs
    • 需要在纸浆中手动完成

SOCP

将加权惩罚成分引入目标,即供应变量的欧几里得范数。

优点:

  • 无变量/约束的指数增长

缺点:

  • 此惩罚的权重取决于问题,需要调整!
  • 不再是线性的:需要SOCP求解器(功能较弱)
  • 需要规范制定(但是如果可以访问SOCP求解器,这很自然)

我没有使用太多的纸浆,将在概念上显示这两种方法(BIGM不调整;慢制剂)使用cvxpy ,它会自动为我们提供了ABS规范功能(重新配制)。

import numpy as np
import cvxpy as cvx
from itertools import combinations
np.set_printoptions(suppress=True, precision=6)

# price = np.array([140, 50, 80, 60])
# quantity = np.array([100, 150, 200, 400])

price = np.array([60, 60, 60, 60])
quantity = np.array([100, 150, 200, 400])

estimate = 400

# LP approach
def solve_lp(penalty=True):
    bigM = 1e-3

    N = len(price)
    pairs = list(combinations(range(N), 2))

    x = cvx.Variable(N)
    constraints = [x >= 0,
                   cvx.sum_entries(x) >= estimate,
                   x <= quantity]
    obj_costs = price * x
    obj_penalty = sum([cvx.abs(x[a] - x[b]) for (a,b) in pairs])
    objective = obj_costs + bigM * float(penalty) * obj_penalty

    problem = cvx.Problem(cvx.Minimize(objective), constraints)
    problem.solve(solver='CBC')  # Warning: solver not shipped by default
                                 #          same solver as shipped by pulp
                                 #          = Clp/Cbc
    print(problem.status)
    print(problem.value)
    print(x.value.T)

# QP approach
def solve_socp(penalty=True):
    bigM = 1e-3

    N = len(price)
    est_avg = estimate / N

    x = cvx.Variable(N)
    constraints = [x >= 0,
                   cvx.sum_entries(x) >= estimate,
                   x <= quantity]
    obj_costs = price * x
    obj_penalty = cvx.norm(x - est_avg)
    objective = obj_costs + bigM * float(penalty) * obj_penalty

    problem = cvx.Problem(cvx.Minimize(objective), constraints)
    problem.solve(solver='ECOS')
    print(problem.status)
    print(problem.value)
    print(x.value.T)

print('LP a')
solve_lp(penalty=False)
print('LP b')
solve_lp(penalty=True)
print('SOCP a')
solve_socp(penalty=False)
print('SOCP b')
solve_socp(penalty=True)

输出量

LP a
optimal
24000.0
[[100. 100. 200.   0.]]
LP b
optimal
24000.0
[[100. 100. 100. 100.]]
SOCP a
optimal
24000.000032013406
[[ 44.92762   69.401923  93.878797 191.791661]]
SOCP b
optimal
24000.000001071123
[[ 99.999423  99.999973  99.999959 100.000645]]

备注:SOCP通过内点法求解,该方法近似求解(理论上:与所需精度一样)。 因此,值不完全是100。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM