在python中将整数编程转换为二进制

时间:2016-09-01 21:53:01

标签: python binary integer linear-programming

Excel Image

请参阅上图以了解我对问题的解释。

from scipy.optimize import linprog

a = [-800,-1200,-800]

b = [[200,100,400],[200,200,400],[200,300,200]]

c = [600,600,600]

result = linprog(a,b,c)
print(result)

我写的代码就在上面。我感兴趣的输出中的数字是fun : -2400.0< - 这是当前的结果。这不是我想要的。

这是问题,也是我要找的。

图中有两张桌子。 RHS上的表是整数部分,LHS表是二进制部分。我想要的答案是fun : -2800.0,它是LHS表中第4列的一部分。

让我告诉你我是如何确定答案的。 首先,正如您所看到的,对于LHS表中的所有三个分配,都会编写0和1和1的所有可能组合。我必须从第4列LHS中找到满足RHS表中所有条件的最佳数字。例如:从顶部开始;从LHS和RHS表中取得的数字。 1表示选择分配,0表示不选择。因此第一行有1 1 1意味着选择所有分配。现在,我们添加第0,1和第2天的所有数字,我们可以看到它们都超过600.添加200 * 1 + 100 * 1 + 400 * 1 = 700,大于600.同样的事情一天因此,2801不是我们想要的数字。接下来,我们选择2800,它确实满足每个添加数字< = 600的总条件,因为assignment1为0,所以200 * 0 + 100 * 1 + 400 * 1 = 500,小于600,同样的事情其余两天。

我只是不明白如何将每一件事放在python中并获得-2800而不是-2400的结果。

linprog必须有一个简单的方法。

我在LHS表的第4个中获得数字的方式是使用RHS表中的绿色突出显示的数字,这些数字也在LHS表的最后一行。 我做了=((B5 + $ B $ 13)+(C5 * $ C $ 13)+(D5 * $ D $ 13))获得2801,依此类推其余的。

如果不使用linprog,我无法想到比以下代码更好的内容:

B = [800,1200,800]
A = [[200,100,400],[200,200,400],[200,300,200]]

for num in A[0],A[1],A[2]:
    t0 = num[0]*1 + num[1]*1 + num[2]*1
    t1 = num[0]*0 + num[1]*1 + num[2]*1
    print(t0)

1 个答案:

答案 0 :(得分:1)

首先:你的问题非常严厉(你对linprog的使用并不常见; Variable A通常是2d-one。)

通常我对这些问题犹豫不决(=非常不完整),但我认为我现在遇到了问题。

你的问题/表述有什么大问题?

  • 你没告诉我们,左边桌子的第四列来自哪里!这些值是固定的(独立于剩余的表格),还是以某种方式相关?
  • 在检查了这些值后,我理解,这些值本身(让我们称之为z)是以下形式的决策变量的线性函数:
    • z = 1*x0 + 1200*x1 + 800*x2 + 800
    • 您的问题没有解释,这里很重要!

如何处理问题?

正确的方法:忽略800&的恒定偏移。以后正确的目标

以下代码(我以常用方式使用变量名称)忽略偏移量(常量偏移量不会改变有关决策变量的结果)。因此,您希望稍后将偏移量添加到您获得的解决方案/或忽略返回的目标,并通过上面的公式自行计算!

from scipy.optimize import linprog
import numpy as np

a_ub = [[200, 100, 400], [200, 200, 300], [400, 400, 200]]
b_ub = [600, 600, 600]
c = [-1, -1200, -800]

result = linprog(c,a_ub,b_ub, bounds=(0,1))
print('*** result: (negated, offset of 800 missing) ***\n')
print(result)

结果:

*** result: (negated, offset of 800 missing) ***

     fun: -2000.0
 message: 'Optimization terminated successfully.'
     nit: 3
   slack: array([ 100.,  100.,    0.,    1.,    0.,    0.])
  status: 0
 success: True
       x: array([ 0.,  1.,  1.])

在否定目标后,只需添加偏移量即可获得所需的2800结果!

愚蠢的方法:添加一些固定的变量来描述偏移量

""" Alternative formulation
    We introduce a 4th variable W, which is set to 1 and introduce the offset
    into the objective
"""
from scipy.optimize import linprog
import numpy as np

a_ub = [[200, 100, 400, 0], [200, 200, 300, 0], [400, 400, 200, 0]]  # no upper bound for W 
b_ub = [600, 600, 600]
c = [-1, -1200, -800, -800]  # W*800 added to objective
a_eq = [[0, 0, 0, 1]]  # W=1 fixed
b_eq = [1]             # ""  ""
result = linprog(c,a_ub,b_ub, a_eq, b_eq, bounds=(0,1))
print('*** alternative result (negated, including offset): ***\n')
print(result)

结果:

*** alternative result (negated, including offset): ***

     fun: -2800.0
 message: 'Optimization terminated successfully.'
     nit: 4
   slack: array([ 100.,  100.,    0.,    1.,    0.,    0.,    0.])
  status: 0
 success: True
       x: array([ 0.,  1.,  1.,  1.])

但这一般会起作用吗?

线性编程方法通常不起作用。正如评论中提到的那样,单模矩阵意味着LP求解器保证了最优的整数解。但是如果没有关于你的数据的一些规则,一般不会给出这种单模块性的特征!

查看以下示例代码,该代码生成随机实例并比较LP求解器的结果。和一个MIP求解器。第一个随机实例失败了,因为LP解是连续的!

当然你可以坚持使用MIP解算器,但是:

  • MIP问题一般很难
  • numpy / scipy中没有MIP解算器

代码:

from scipy.optimize import linprog
import numpy as np
from cylp.cy import CyCbcModel, CyClpSimplex
from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray

np.random.seed(1)

def solve_lp(a_ub, b_ub, c):
    result = linprog(c,a_ub,b_ub, bounds=(0,1))
    print(result)
    return result.fun

def solve_mip(a_ub, b_ub, c):
    a_ub, b_ub, c = np.matrix(a_ub), np.array(b_ub), np.array(c)
    n = b_ub.shape[0]

    model = CyLPModel()
    x = model.addVariable('x', n, isInt=True)

    model += a_ub*x <= b_ub
    for i in range(n):
        model += 0 <= x[i] <= 1

    c = CyLPArray(c)
    model.objective = c*x
    s = CyClpSimplex(model)
    cbcModel = s.getCbcModel()
    cbcModel.branchAndBound()
    print('sol: ', cbcModel.primalVariableSolution['x'])
    print('obj: ', cbcModel.objectiveValue)
    return cbcModel.objectiveValue

def solve_random_until_unequal():
    while True:
        a_ub = np.random.randint(0, 1000, size=(3,3))
        b_ub = np.random.randint(0, 1000, size=3)
        c = [-1, -1200, -800]

        lp_obj = solve_lp(a_ub, b_ub, c)
        mip_obj = solve_mip(a_ub, b_ub, c)
        print('A_ub: ', a_ub)
        print('b_ub: ', b_ub)
        assert np.isclose(lp_obj, mip_obj)

solve_random_until_unequal()

输出:

fun: -225.29335071707953
message: 'Optimization terminated successfully.'
nit: 1
slack: array([  9.15880052e+02,   0.00000000e+00,   7.90482399e+00,
    1.00000000e+00,   8.12255541e-01,   1.00000000e+00])
status: 0
success: True
  x: array([ 0.        ,  0.18774446,  0.        ])
Clp0000I Optimal - objective value 0
Clp0000I Optimal - objective value 0
Node 0 depth 0 unsatisfied 0 sum 0 obj 0 guess 0 branching on -1
Clp0000I Optimal - objective value 0
Cbc0004I Integer solution of -0 found after 0 iterations and 0 nodes (0.00 seconds)
Cbc0001I Search completed - best objective -0, took 0 iterations and 0 nodes (0.00 seconds)
Cbc0035I Maximum depth 0, 0 variables fixed on reduced cost
Clp0000I Optimal - objective value 0
Clp0000I Optimal - objective value 0
('sol: ', array([ 0.,  0.,  0.]))
('obj: ', -0.0)
('A_ub: ', array([[ 37, 235, 908],
  [ 72, 767, 905],
  [715, 645, 847]]))
('b_ub: ', array([960, 144, 129]))
Traceback (most recent call last):
File "so_linprog_v3.py", line 45, in <module>
solve_random_until_unequal()
File "so_linprog_v3.py", line 43, in solve_random_until_unequal
assert np.isclose(lp_obj, mip_obj)
AssertionError