我有一个房间列表,房间的最大平方英尺,程序,程序的最大平方英尺,以及房间与预期程序使用的匹配程度(match #)的值。在帮助下,我已经能够最大限度地利用每个房间的一个项目。然而,我想把这个分析更进一步,允许在同一个房间里有多个程序,或者如果它有最高的匹配值,只要倍数仍然符合平方英尺的要求,就可以在同一个房间里有多个程序。此外,我想告诉lpSolve整体,我只想在整个建筑中设置"x"个办公室,"y"个工作室等。以下是我到目前为止的数据和代码:
program.size <- c(120,320,300,800,500,1000,500,1000,1500,400,1500,2000)
room.size <- c(1414,682,1484,2938,1985,1493,427,1958,708,581,1485,652,727,2556,1634,187,2174,205,1070,2165,1680,1449,1441,2289,986,298,590,2925)
(obj.vals <- matrix(c(3,4,2,8,3,7,4,8,6,4,7,7,
3,4,2,8,3,7,4,8,6,4,7,7,
4,5,3,7,4,6,5,7,5,3,6,6,
2,3,1,7,2,6,3,7,7,5,6,6,
4,5,3,7,4,6,5,7,5,3,6,6,
3,6,4,8,5,7,4,8,7,7,7,7,
3,4,2,8,3,7,4,8,6,4,7,7,
4,5,3,7,4,6,5,7,5,3,6,6,
6,7,5,7,6,6,7,7,5,3,6,6,
6,7,5,7,6,6,7,7,5,3,6,6,
5,6,6,6,5,7,8,6,4,2,5,5,
6,7,5,7,6,6,7,7,5,3,6,6,
6,7,5,7,6,6,7,7,5,3,6,6,
3,4,4,8,3,9,6,8,6,4,7,7,
3,4,2,6,3,5,4,6,6,4,5,5,
4,5,3,5,4,4,5,5,5,3,4,4,
5,6,4,8,5,7,6,8,6,4,7,7,
5,6,4,8,5,7,6,8,6,4,7,7,
4,5,5,7,4,8,7,7,5,3,6,6,
5,6,4,8,5,7,6,8,6,4,7,7,
3,4,2,6,3,5,4,6,6,4,5,5,
5,6,4,8,5,7,6,8,6,4,7,7,
5,6,4,8,5,7,6,8,6,4,7,7,
5,4,4,6,5,5,6,6,6,6,7,5,
6,5,5,5,6,4,5,5,5,7,6,4,
4,5,3,7,4,6,5,7,7,5,6,6,
6,5,5,5,6,4,5,5,5,7,6,4,
3,4,4,6,3,7,6,6,6,4,5,5), nrow=12))
rownames(obj.vals) <- c("Enclosed Offices", "Open Office", "Reception / Greeter", "Studio / Classroom",
"Conference / Meeting Room", "Gallery", "Public / Lobby / Waiting",
"Collaborative Space", "Mechanical / Support", "Storage / Archives",
"Fabrication", "Performance")
(obj.adj <- obj.vals * outer(program.size, room.size, "<="))
nr <- nrow(obj.adj)
nc <- ncol(obj.adj)
library(lpSolve)
obj <- as.vector(obj.adj)
con <- t(1*sapply(1:nc, function(x) rep(1:nc == x, each=nr)))
dir <- rep("<=", nc)
rhs <- rep(1, nc)
mod <- lp("max", obj, con, dir, rhs, all.bin=TRUE)
final <- matrix(mod$solution, nrow=nr)
所以现在我的问题是,我如何让求解器最大限度地利用平方英尺,并在每个房间(列)内匹配#,并允许多个相同的程序或程序组合来实现这一点?我知道我必须解除"mod"中的"<= 1"限制,但我不知道如何让它在每个房间找到最适合的,然后最终,整体。
对于room[,1]的解决方案应该是:
$optimum
33
并且它将尝试在房间内容纳11个封闭办公室,这比1个协作空间(8个匹配)和1个存储/档案(4个匹配)的最佳匹配度高得多,总共12个匹配。
这就引出了我的下一个问题关于限制我的解矩阵中某些程序的总数。我想它应该包括一些
as.numeric(data$EnclosedOffices "<=" 5)
但我也不知道如何限制它。这些数字对于所有程序都是不同的。
感谢所有的帮助,如果有任何澄清,请随时要求。
更新:约束
- 最大化每个房间的匹配# (obj.vals)。最大化程序。每个房间的面积。大小广场的脚。要做到这一点,要么多次使用相同的程序(5 x封闭式办公室)或组合方案(1协作空间和1)性能。
- 限制和/或强制返回的程序数量解决方案。只要不超过我为所有房间提供的程序的最大数量,这些程序可以在房间之间分开。(在所有28列中,仅可选择5个封闭办公室,8个工作室/教室,1个制造等。
如果您使用R包lpSolveAPI
(lpSolve的包装器),那么它会变得更容易一些。首先,看一下数学公式(一个整数程序),然后我向您展示解决问题的代码。
制定
设X_r_p
为取正整数值的决策变量
X_r_p
=分配给r
房间的p
类程序数(在所有你的问题将有28*12=336个决策变量)
最大匹配分数
Max sum(r) sum(p) C_r_p * X_r_p
#这里C_r_p是将p分配给房间r的分数
,
房间面积限制约束
Sum(p) Max_area_p * X_r_p <= Room Size (r) for each room r
(我们将有28个这样的约束)
限制程序数约束
Sum(r) X_r_p <= Max_allowable(p) for each program p
(我们将有12个这样的约束)
X_r_p >= 0, Integer
这就是整个公式。336列40行
在R中的实现
这是一个在R中的实现,使用lpSolveAPI
。注意:由于OP没有提供max_allowed的程序,所以我为max_programs.
生成了自己的数据
program.size <- c(120,320,300,800,500,1000,500,1000,1500,400,1500,2000)
room.size <- c(1414,682,1484,2938,1985,1493,427,1958,708,581,1485,652,727,2556,1634,187,2174,205,1070,2165,1680,1449,1441,2289,986,298,590,2925)
(obj.vals <- matrix(c(3,4,2,8,3,7,4,8,6,4,7,7,3,4,2,8,3,7,4,8,6,4,7,7,
4,5,3,7,4,6,5,7,5,3,6,6,2,3,1,7,2,6,3,7,7,5,6,6, 4,5,3,7,4,6,5,7,5,3,6,6,
3,6,4,8,5,7,4,8,7,7,7,7,3,4,2,8,3,7,4,8,6,4,7,7, 4,5,3,7,4,6,5,7,5,3,6,6,
6,7,5,7,6,6,7,7,5,3,6,6,6,7,5,7,6,6,7,7,5,3,6,6, 5,6,6,6,5,7,8,6,4,2,5,5,
6,7,5,7,6,6,7,7,5,3,6,6, 6,7,5,7,6,6,7,7,5,3,6,6, 3,4,4,8,3,9,6,8,6,4,7,7,
3,4,2,6,3,5,4,6,6,4,5,5, 4,5,3,5,4,4,5,5,5,3,4,4, 5,6,4,8,5,7,6,8,6,4,7,7,
5,6,4,8,5,7,6,8,6,4,7,7, 4,5,5,7,4,8,7,7,5,3,6,6, 5,6,4,8,5,7,6,8,6,4,7,7,
3,4,2,6,3,5,4,6,6,4,5,5, 5,6,4,8,5,7,6,8,6,4,7,7, 5,6,4,8,5,7,6,8,6,4,7,7,
5,4,4,6,5,5,6,6,6,6,7,5, 6,5,5,5,6,4,5,5,5,7,6,4, 4,5,3,7,4,6,5,7,7,5,6,6,
6,5,5,5,6,4,5,5,5,7,6,4, 3,4,4,6,3,7,6,6,6,4,5,5), nrow=12))
rownames(obj.vals) <- c("Enclosed Offices", "Open Office", "Reception / Greeter", "Studio / Classroom",
"Conference / Meeting Room", "Gallery", "Public / Lobby / Waiting",
"Collaborative Space", "Mechanical / Support", "Storage / Archives",
"Fabrication", "Performance")
对于这12个项目中的每一个,让我们设置一个可以分配给所有房间的最大重复次数。请注意,这是我添加的东西,因为这个数据不是由op提供的(限制他们被分配到太多的房间)。
max_programs <- c(1,2,3,1,5,2,3,4,1,3,1,2)
library(lpSolveAPI)
nrooms <- 28
nprgs <- 12
ncol = nrooms*nprgs
lp_matching <- make.lp(ncol=ncol)
#we want integer assignments
set.type(lp_matching, columns=1:ncol, type = c("integer"))
# sum r,p Crp * Xrp
set.objfn(lp_matching, obj.vals) #28 rooms * 12 programs
lp.control(lp_matching,sense='max')
#' Set Max Programs constraints
#' No more than max number of programs over all the rooms
#' X1p + x2p + x3p ... + x28p <= max(p) for each p
Add_Max_program_constraint <- function (prog_index) {
prog_cols <- (0:(nrooms-1))*nprgs + prog_index
add.constraint(lp_matching, rep(1,nrooms), indices=prog_cols, rhs=max_programs[prog_index])
}
#Add a max_number constraint for each program
lapply(1:nprgs, Add_Max_program_constraint)
#' Sum of all the programs assigned to each room, over all programs
#' area_1 * Xr1+ area 2* Xr2+ ... + area12* Xr12 <= room.size[r] for each room
Add_room_size_constraint <- function (room_index) {
room_cols <- (room_index-1)*nprgs + (1:nprgs) #relevant columns for a given room
add.constraint(lp_matching, xt=program.size, indices=room_cols, rhs=room.size[room_index])
}
#Add a max_number constraint for each program
lapply(1:nrooms, Add_room_size_constraint)
解决方法:
> solve(lp_matching)
> get.objective(lp_matching)
[1] 195
get.variables(lp_matching) # to see which programs went to which rooms
> print(lp_matching)
Model name:
a linear program with 336 decision variables and 40 constraints
您也可以将IP模型写入文件以检查它:
#Give identifiable column and row names
rp<- t(outer(1:nrooms, 1:nprgs, paste, sep="_"))
rp_vec <- paste(abc, sep="")
colnames<- paste("x_",rp_vec, sep="")
# RowNames
rownames1 <- paste("MaxProg", 1:nprgs, sep="_")
rownames2 <- paste("Room", 1:nrooms, "AreaLimit", sep="_")
dimnames(lp_matching) <- list(c(rownames1, rownames2), colnames)
write.lp(lp_matching,filename="room_matching.lp")
希望对你有帮助。
基于后续问题的更新
跟进问题1:修改代码以确保每个房间至少有一个程序
添加以下约束集:
X_r_p >= 1 for all r
注意:由于这是一个最大化问题,因此最优解决方案应该默认遵守此约束。换句话说,如果可以,它总是会将程序分配给任何房间,并假设分配的分数为正。
跟进问题2:另一个问题是,我是否可以要求它总共有28个以上的程序?例如,如果我想要28个封闭式办公室,它们几乎都可以放在一个2938平方英尺的房间里。如果max设置为28,我怎么让R去找其他的程序呢?
为了达到这个目标,你可以做一些不同的事情。完全不存在所有程序的和<= 28约束。(如果你在上面的解决方案中注意到,我的约束条件略有不同。)
约束:
Sum(r) X_r_p <= Max_allowable(p) for each program p
仅限制程序类型的Max。总数没有限制。此外,您不必为每种类型的程序都编写这样的约束。只有当你想要限制它的出现时,才写这个约束。
为了推广这一点,您可以为每种类型的程序的总数设置下界和上界。这将使您可以很好地控制分配。
min_allowable(p) <= sum(over r) X_r_p <= max_allowable(p) for any program type p