我有兴趣在线性程序中构建基本上是或的语句。目前我在R中使用lpSolveAPI,但我也希望得到有关此类问题的线性编程最佳实践的答案。
以下是使用lpSolveAPI包的一些工作代码:
(vector + 1 2)
(vector + 1 2)
=> #((VECTOR + 1 2) 1 2)
运行此代码并查看结果时,您会看到x6 = 0.9,x7 = -0.1和x8 = -0.2。对此的解释是购买了90%的 b ,并且出售了30%的 b 。
我希望建立一个约束,要求在任何地点出售 a 或 b 时,也不能购买。 (反之亦然)
在这种特殊情况下,我认为最佳解决方案是销售20% a (x3)并购买20% b (x5或x6)。 x =(0,0,-0.2,0,0.2,0,0,0)
换句话说,如果您选择在x1和/或x2中使用非零值,则x3和x4中的值必须为0。同样,如果在x3和/或x4中选择的值不是零,则x1和x2中的值必须为零。
答案 0 :(得分:3)
通常,“所有这些变量都是非负数或非正数”形式的约束要求引入一个二进制变量,指示是否已选择正面或负面情况。
我们来看前四个变量的情况;我们将引入一个二进制变量p1
,指示是否处于非负方案(p1=1
)或非正方案(p1=0
)。现在我们有以下限制:
0 <= x1 <= 1
0 <= x2 <= 1
-0.2 <= x3 <= 0
-0.4 <= x4 <= 0
如果p1=1
,则下限必须至少为0,如果p1=0
则上限必须不超过0.我们可以将约束重写为:
0 <= x1 <= 1 * p1
0 <= x2 <= 1 * p1
-0.2 * (1-p1) <= x3 <= 0
-0.4 * (1-p1) <= x4 <= 0
基本上,我们需要将所有正上限乘以p1
,如果我们处于非负空间则没有影响,如果我们在非负空间则将上限设置为0积极的情况。类似地,我们需要将所有负下界多个(1-p1)
,如果我们处于非正空间则没有影响,如果我们处于非负面情况,则将下限设置为0。
我们同样为第二组变量定义了一个新的二进制变量p2
,并按如下方式更新我们的约束:
0 <= x5 <= 1 * p2
0 <= x6 <= 1 * p2
-0.1 * (1-p2) <= x7 <= 0
-0.2 * (1-p2) <= x8 <= 0
在代码中,这看起来像:
n <- nrow(mat)
LP <- make.lp(0, n+2)
set.objfn(LP, c(-mat[, 'score'], 0, 0))
set.type(LP, n+1, "binary")
set.type(LP, n+2, "binary")
set.bounds(LP, lower = c(mat[, 'lb'], 0, 0))
set.bounds(LP, upper = c(mat[, 'ub'], 1, 1))
for (i in 1:n) {
add.constraint(LP, c(i == (1:n), (mat[i,'a'] == 1) * mat[i,'lb'], (mat[i,'b'] == 1) * mat[i,'lb']), ">=", mat[i,'lb'])
add.constraint(LP, c(i == (1:n), -(mat[i,'a'] == 1) * mat[i,'ub'], -(mat[i,'b'] == 1) * mat[i,'ub']), "<=", 0)
}
add.constraint(LP, c(rep(1, n), 0, 0), "=", 0)
solve(LP)
get.objective(LP)
# [1] -0.058
round(head(get.variables(LP), -2), 3)
# [1] 0.0 0.0 -0.2 -0.4 0.0 0.6 0.0 0.0
找到的最优解,客观值为0.058,实际上优于OP手工找到的解(只有客观值0.03)。