预解决CLP的Rglpk和R实现

时间:2019-06-09 17:09:17

标签: r linear-programming

我需要解决一些约束矩阵很大(甚至无法生成约束矩阵)的二进制线性规划问题;所以我想:为什么不制作稀疏约束矩阵?但是,我认识的所有LP解算器(lpSolveRsymphony)似乎都无法处理稀疏约束矩阵。
因此,我找到并安装了Rglpk,它可以通过slam处理稀疏矩阵。
然后,我可以使用带有 sparse 选项的xtabs制作矩阵,将它们转换为slam格式,然后将其提交给求解器。使用Rglpk而不是lpSolve时,性能的提高给我留下了深刻的印象(在某些其他问题上,该性能也比Rsymphony慢)。在Rglpk中,我还可以使用 presolve 选项,lpSolve也有但实际上被忽略了。

但是,现在我有两个疑问。

  1. 当我使用Rglpk解决了一个大问题时,我首先尝试使用presolve=TRUE,并在不到20分钟的时间内完成了操作。
    但是,当我对presolve=FALSE进行同样的尝试时,不仅它在几个小时后还没有完成,而且通过设置verbose=TRUE我可以看到,与“最优”函数相比,目标函数甚至可以达到更好的值。 'presolve=TRUE运行中找到的值。
    问题1:presolve=TRUE不应该只是在没有实际改变问题的情况下就加速流程,而不能通过获得不太理想的解决方案的方式来解决问题?

  2. 在寻找有关Rglpk的更多信息时,我发现this report在这里比较了几个LP解算器。
    该报告似乎认为CLP是最好的开源解决方案。我寻找了R的实现,但是我只能找到clpAPI link,它似乎没有像RglpkRsymphonylpSolve做。看起来它可以处理稀疏矩阵:命令loadMatrixCLP似乎采用行和列索引+非零元素的值;但显然这需要一些工作。然后我仍然不知道如何处理各种低级求解器,选项等。而且我找不到任何有关预求解技术的参考。
    第二季度:有人知道R中CLP的高级实现吗?
    Rsymphony应该很好(COIN-OR等),并且在其参考手册中粗略地提到了稀疏矩阵,但是后来我找不到关于如何将稀疏矩阵传递给求解器的明确解释。 br /> 我咨询了this webpage,但找不到明显达到目标的东西。

有什么想法吗?

谢谢!


编辑:使用RsymphonylpSolveRglpk 解决的问题示例

根据sascha的建议进行进一步搜索后,发现Rsymphony可以处理稀疏矩阵。
所以我尝试了一下,发现它起作用了。但是,lpSolve找到了另外一个解决方案,Rsymphony却没有。

在下面的示例中,初始data.frame t0表示7个对象(由属性“ ID”标识),每个对象都与一个属性“ SC”(每个对象唯一)相关联,数组属性“ FP”。
由于我不知道如何在R中很好地处理数组属性,因此我分别合并了“ SC”和“ FP”属性的初始数据,并使用“ prop_to_handle”属性标记了相应的行。

优化的目标是选择1个SC ==“ A”的对象,2个SC ==“ B”的对象和1个SC ==“ C”的对象,以使唯一FP的数量解决方案已最大化。
我在StackExchange帖子的其他地方讨论了这个主题(计算独特功能)。到目前为止,没有人能为我在这里实现的解决方案提供替代解决方案,其中包括为每个FP功能添加1个二进制变量,然后进行适当的约束以确保没有矛盾。
在这种情况下,有7个ID和12个不同的FP功能,因此需要分配19个二进制变量。

#Initial data
t0 <- structure(list(ID = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 
4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7), prop_to_handle = c("FP", 
"FP", "FP", "SC", "FP", "FP", "FP", "SC", "FP", "FP", "FP", "SC", 
"FP", "FP", "FP", "SC", "FP", "FP", "FP", "SC", "FP", "FP", "FP", 
"SC", "FP", "FP", "FP", "SC"), SC = c(NA, NA, NA, "A", NA, NA, 
NA, "A", NA, NA, NA, "B", NA, NA, NA, "B", NA, NA, NA, "B", NA, 
NA, NA, "C", NA, NA, NA, "C"), N = c(NA, NA, NA, 1, NA, NA, NA, 
1, NA, NA, NA, 2, NA, NA, NA, 2, NA, NA, NA, 2, NA, NA, NA, 1, 
NA, NA, NA, 1), FP = c(100, 200, 300, NA, 100, 400, 600, NA, 
500, 200, 300, NA, 500, 400, 600, NA, 500, 900, 700, NA, 250, 
150, 300, NA, 250, 175, 350, NA)), .Names = c("ID", "prop_to_handle", 
"SC", "N", "FP"), row.names = c(NA, -28L), class = "data.frame")

#Installing and loading packages
if (length(find.package(package="Rsymphony",quiet=TRUE))==0) install.packages("Rsymphony")
if (length(find.package(package="slam",quiet=TRUE))==0) install.packages("slam")
if (length(find.package(package="lpSolve",quiet=TRUE))==0) install.packages("lpSolve")
if (length(find.package(package="Rglpk",quiet=TRUE))==0) install.packages("Rglpk")
if (length(find.package(package="slam",quiet=TRUE))==0) install.packages("slam")
require(Rsymphony)
require(slam)
require(lpSolve)
require(Rglpk)

#making sure SC is not a factor
t0["SC"] <- as.character(t0$SC)

#separating the SC and FP handling
t0_FP <- t0[t0$prop_to_handle=="FP",]
t0_SC <- t0[t0$prop_to_handle=="SC",]

#sparse constraint matrix for SC
SC.ID.mat <- xtabs(~SC+ID,t0_SC,sparse=T)

#sparse constraint matrix for FP
FP.ID.mat <- xtabs(~FP+ID,t0_FP,sparse=T)

NIDs_vs_FP <- table(t0_FP[["FP"]]) 

N.FP <- length(NIDs_vs_FP)
N.ID <- length(dimnames(SC.ID.mat)[[2]])
N.SC <- length(dimnames(SC.ID.mat)[[1]])

N.ID.SC <- as.vector(xtabs(N~SC,t0_SC[!duplicated(t0_SC$SC),]))

NIDs_vs_SC <- table(t0_SC[["SC"]])
N.ID.SC[(unname(NIDs_vs_SC - N.ID.SC) < 0)] <- NIDs_vs_SC[(unname(NIDs_vs_SC - N.ID.SC) < 0)]

#converting the sparse matrices from xtabs to the format accepted by Rglpk
FP.ID.mat <- as.simple_triplet_matrix(FP.ID.mat)
SC.ID.mat <- as.simple_triplet_matrix(SC.ID.mat)

#putting together the overall constraint matrix
cm <- rbind(cbind(FP.ID.mat,-simple_triplet_diag_matrix(NIDs_vs_FP)),cbind(FP.ID.mat,-simple_triplet_diag_matrix(NIDs_vs_FP)),cbind(SC.ID.mat,simple_triplet_zero_matrix(N.SC,N.FP)))

#making a non-sparse overall constraint matrix for lpSolve
cm2 <- as.matrix(cm)

#directions and rhs of the constraints
cdir <- c(rep("<=",N.FP),rep(">=",N.FP),rep("==",N.SC))
crhs <- unname(c(rep(0,N.FP),1-NIDs_vs_FP,N.ID.SC))

#objective vector, assigning -1 to each FP feature
cobj <- c(rep(0,N.ID),rep(-1,N.FP))

#solution using Rsymphony
sol.Rsymphony <- Rsymphony_solve_LP (cobj, cm, cdir, crhs, types = "B", max = FALSE, verbosity=0, first_feasible = FALSE)$solution

#solution using lpSolve
sol.lpSolve <- lp("min", cobj, cm2, cdir, crhs, all.bin=TRUE, num.bin.solns = 2,  use.rw = FALSE, transpose.constraints = TRUE)$solution

#solution using Rglpk
sol.Rglpk <- Rglpk_solve_LP (cobj, cm, cdir, crhs, types = "B", max = FALSE, control=list(verbose=TRUE,presolve=FALSE))$solution

#comparison of the solutions
sol.Rsymphony
#[1] 1 0 0 1 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1
sol.lpSolve
#[1] 1 0 0 1 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1
sol.Rglpk
#[1] 0 1 1 0 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1

RsymphonyRglpk都找到一个解决方案,每种情况下都不同。 lpSolve找到两个解决方案。

不幸的是,我无法在实际问题上使用lpSolve,因为它太大了,所以不仅实际求解会花费很长时间,而且甚至无法创建初始矩阵。我可以尝试使用'dense.const'选项...

欢迎任何评论或建议。

0 个答案:

没有答案