我要解决的问题与本文中的问题基本相同:
https://stats.stackexchange.com/questions/339935/python-library-for-combinatorial-optimization
并且我当前的实现确实使用了基于遗传算法的优化器。
但是,我想将其作为二进制线性编程问题解决(至少尝试,即使它看起来很“ NP-hard”)。
我的问题是如何以最佳方式制定LP,因为我不确定我做对了吗。
以下是我正在处理的内容的简化版本,但是它准确显示了问题所在。
我们通过组合处理,使m * n个对象(在本例中为6个),其中包含m(3)个类型为'R1'的对象(例如{A,B,C})和n(2)个类型为'R2的对象'(例如{X,Y})。
对6个对象{AX,AY,BX,BY,CX,CY}进行评估,每个对象都按此顺序获得得分D,在这种情况下为{0.8,0.7,0.5,0.9,0.4,0.0}。
CL <- cbind(expand.grid(R2=LETTERS[24:25],R1=LETTERS[1:3],stringsAsFactors = FALSE),D=c(0.8,0.7,0.5,0.9,0.4,0.0))
现在我们要选择2个 distinct R1和1个R2,以使D的总和最大。
在此示例中,答案为R1 = {A,B},R2 = {Y}。
但是,不能得出这样的结论,例如,平均R最高的2个R1和R2。
它适用于R1,但不适用于R2:
aggregate(D~R1,CL,mean)
# R1 D
#1 A 0.75
#2 B 0.70
#3 C 0.20
aggregate(D~R2,CL,mean)
# R2 D
#1 X 0.5666667
#2 Y 0.5333333
我知道如何将其表达为线性规划问题;只是我不确定我的公式是否有效,因为基本上会导致m n + m + n变量和2 (m + n)+2约束的问题。
主要困难在于,我需要以某种方式计算选择的不同R1和R2的数量,除了下面将要说明的以外,我不知道有其他方法可以做到(并且在我的另一篇文章{{3}中也有介绍}。
这就是我要做的:
CL["Entry"] <- seq_len(dim(CL)[[1]])
R1.mat <- table(CL$R1,CL$Entry)
R2.mat <- table(CL$R2,CL$Entry)
N_R1 <- dim(R1.mat)[[1]]
N_R2 <- dim(R2.mat)[[1]]
N_Entry <- dim(CL)[[1]]
constr.mat <- NULL
dir <- NULL
rhs <- NULL
constr.mat <- rbind(constr.mat,cbind(R1.mat,-diag(table(CL$R1)),matrix(0,N_R1,N_R2)))
dir <- c(dir,rep("<=",N_R1))
rhs <- c(rhs,rep(0,N_R1))
constr.mat <- rbind(constr.mat,cbind(R2.mat,matrix(0,N_R2,N_R1),-diag(table(CL$R2))))
dir <- c(dir,rep("<=",N_R2))
rhs <- c(rhs,rep(0,N_R2))
constr.mat <- rbind(constr.mat,constr.mat)
dir <- c(dir,rep(">=",N_R1+N_R2))
rhs <- c(rhs,1-table(CL$R1),1-table(CL$R2))
constr.mat <- rbind(constr.mat,c(rep(0,N_Entry),rep(1,N_R1),rep(0,N_R2)))
dir <- c(dir,"==")
rhs <- c(rhs,2)
constr.mat <- rbind(constr.mat,c(rep(0,N_Entry),rep(0,N_R1),rep(1,N_R2)))
dir <- c(dir,"==")
rhs <- c(rhs,1)
obj <- c(aggregate(D~Entry,CL,c)[["D"]],rep(0,N_R1+N_R2))
例如lpSolve
可以解决的问题:
sol <- lp("max", obj, constr.mat, dir, rhs, all.bin = TRUE,num.bin.solns = 1, use.rw=FALSE, transpose.constr=TRUE)
sol$solution
#[1] 0 1 0 1 0 0 1 1 0 0 1
显示已选择产品{AY,BY},对应于R1 = {A,B}和R2 = {Y}:
CL[as.logical(sol$solution[1:N_Entry]),]
# R2 R1 D Entry
#2 Y A 0.7 2
#4 Y B 0.9 4
我发现在大问题上lpSolve
被卡住了很长时间; Rsymphony
似乎表现更好。
但是,我的主要问题是:制定LP的这种方式有效吗?我应该采取其他方式吗?
谢谢!
编辑
同时,针对一个有点相关的问题,我here指出,如果将一组“成本”(在此示例中为负)添加到“目标”的目标向量上,则只有一组约束可能就足够了。不同的R1和R2'变量。
所以这里,而不是:
obj <- c(aggregate(D~Entry,CL,c)[["D"]],rep(0,N_R1+N_R2))
我会做的:
obj <- c(aggregate(D~Entry,CL,c)[["D"]],rep(-1,N_R1+N_R2))
这将使 m + n 约束变得不必要。
即使对于较小的 m,n 来说,仍然仍然是一个巨大的问题,因此,如果有人可以建议如何做得更好...
我看过lp.transport
,但这仅限于2个维度(例如,仅R1和R2,而不是R1,R2,R3),而且我认为您不能限制不同对象的数量这类求解器中的每个类别。