首页 文章

如何使用LpSolve在R中设置线性编程优化?

提问于
浏览
5

例如,我有这个示例数据:

d=data.frame(x=c(1,1,1,2,2,3,4,4),y=c(5,6,7,8,7,5,6,5),w=c(1,2,3,4,5,6,7,8))

看起来像这样:

x y w
1 1 5 1
2 1 6 2
3 1 7 3
4 2 8 4
5 2 7 5
6 3 5 6
7 4 6 7
8 4 5 8

xy 表示来自 dataxdatay 的索引 . w 表示将 datax[x]datay[y] 进行比较得分 . 我希望从 d 最大化总得分(或 w ),其中 x 的每个值最多匹配一个 y 值,反之亦然 .

结果应如下所示:

x y w
1 2 7 5
2 3 5 6
3 4 6 7

其中所有 w 值的总和最大化,并且每个 x 和每个 y 在结果中仅显示一次 .

如何在 lpSolve::lp 函数中设置此问题?

1 回答

  • 7

    您可以使用lpSolveAPI来解决您的问题 . 鉴于您的约束,您声明的解决方案并不可行 . 所以,让我们一起想要让X和Y在解决方案中不再重复 .

    您将需要8个新的二进制变量 . 每个变量指定 d 中的该行是被拾取(1)还是被丢弃(0) .

    根据OP的请求更新

    是的,lpSolveAPI代码(下面)使它看起来比实际上更复杂 . 这个LP公式(lpSolveAPI的输出)应该让事情更清晰:

    /* Objective function */
    max: +pick_1 +2 pick_2 +3 pick_3 +4 pick_4 +5 pick_5 +6 pick_6 +7 pick_7 +8 pick_8;
    
    /* Constraints */
    OneX_1: +pick_1 +pick_2 +pick_3 <= 1;
    OneX_2: +pick_4 +pick_5 <= 1;
    OneX_4: +pick_7 +pick_8 <= 1;
    OneY_5: +pick_1 +pick_6 +pick_8 <= 1;
    OneY_6: +pick_2 +pick_7 <= 1;
    OneY_7: +pick_3 +pick_5 <= 1;
    
    /* Variable bounds */
    pick_1 <= 1;
    pick_2 <= 1;
    pick_3 <= 1;
    pick_4 <= 1;
    pick_5 <= 1;
    pick_6 <= 1;
    pick_7 <= 1;
    pick_8 <= 1;
    

    说明:第二个约束(OneX_2)仅表示 pick_4pick_5 中只有一个可以为1,因为数据框 d 中的第4行和第5行具有X = 2

    解决方案

    请注意,上面的公式产生了一个在数据框中选择4行的最佳解决方案 d

    > d[c(3,4,6,7),]
      x y w
    3 1 7 3
    4 2 8 4
    6 3 5 6
    7 4 6 7
    

    w的总和是20,这比问题中的解决方案更好 .

    代码

    library(lpSolveAPI)
    d <- data.frame(x=c(1,1,1,2,2,3,4,4),y=c(5,6,7,8,7,5,6,5),w=c(1,2,3,4,5,6,7,8))
    
    ncol <- 8 #you have eight rows that can be picked or dropped from the solution set
    lp_rowpicker <- make.lp(ncol=ncol)
    set.type(lp_rowpicker, columns=1:ncol, type = c("binary"))
    
    obj_vals <- d[, "w"]
    set.objfn(lp_rowpicker, obj_vals) 
    lp.control(lp_rowpicker,sense='max')
    
    #Add constraints to limit X values from repeating
    add.constraint(lp_rowpicker, xt=c(1,1,1), #xt specifies which rows of the LP
                   indices=c(1,2,3), rhs=1, type="<=")
    add.constraint(lp_rowpicker, xt=c(1,1), #xt specifies which rows of the LP
                   indices=c(4,5), rhs=1, type="<=")
    add.constraint(lp_rowpicker, xt=c(1,1), #xt specifies which rows of the LP
                   indices=c(7,8), rhs=1, type="<=") #x's in dataframe rows 7 & 8 are both '4'
    
    #Add constraints to limit Y values from repeating
    add.constraint(lp_rowpicker, xt=c(1,1,1), #xt specifies which rows of the LP
                   indices=c(1,6,8), rhs=1, type="<=") #Y's in df rows 1,6 & 8 are all '5'
    add.constraint(lp_rowpicker, xt=c(1,1), #xt specifies which rows of the LP
                   indices=c(2,7), rhs=1, type="<=") #Y's in dataframe rows 2&7 are both '6'
    add.constraint(lp_rowpicker, xt=c(1,1), #xt specifies which rows of the LP
                   indices=c(3,5), rhs=1, type="<=") #y's in dataframe rows 3&5 are both '7'
    
    solve(lp_rowpicker)
    get.objective(lp_rowpicker) #20
    get.variables(lp_rowpicker)
    #[1] 0 0 1 1 0 1 1 0
    #This tells you that from d you pick rows: 3,4,6 & 7 in your optimal solution.
    
    #If you want to look at the full formulation:
    rownames1 <- paste("OneX", c(1,2,4), sep="_")
    rownames2 <- paste("OneY", c(5,6,7), sep="_")
    colnames<- paste("pick_",c(1:8), sep="")
    dimnames(lp_rowpicker) <- list(c(rownames1, rownames2), colnames)
    print(lp_rowpicker)
    
    #write it to a text file
    write.lp(lp_rowpicker,filename="max_w.lp")
    

    希望这能让您了解如何使用lpSolveAPI来制定您的问题 .

相关问题