问题描述
我正在尝试在 lpsolveAPI 中制定货架优化整数编程算法,并希望添加一个约束,从而使每个选定货架 (S) 上的每种产品的数量相同:
我的困难是访问和使用总和作为约束(特别是 Xij)
我可以重新编写使其线性而不会有太多问题(请原谅伪代码):
sum(X_ij)*F_ij - sum(F_ij) = 0
此操作可能会影响 X 本身的选择,因此我需要它是动态的(否则我只能在求解后更改值)如何访问这些值,或将 F 值编码为相等?
>线性程序通过一系列约束创建了一个二元解决方案,将产品放在货架上(目前可能放在一个或两个货架上),有四个货架。然后是第二组,它允许那些货架上的许多产品不是零,受产品宽度与货架长度的限制,所有货架上的产品数量给定最大(大多数为 8 个,虽然这有点武断),最大限度地提高产品利润。所有这些都按预期工作。但是,我希望添加一个约束,使两个或多个货架上的产品数量相同,即一个货架上有四个,另一个货架上有四个。鉴于使用的货架数量可以是 1 或 2,我不能简单地划分这些值。此外,由于哪些货架被占用是由约束决定的,我不能简单地使用 P1S1 = P1S2(除非我可以选择被占用的货架,但我没有这样做)
这是我尝试做的一个最小的例子(请原谅我第一次这样做的不雅代码)数据集是here:
library(lpSolveAPI)
shelves <- data.frame(Sl_i = c(151,200,180,218),Sh_i = c(30,30,36))
datatable <- read.csv("~/Desktop/sales/datatable.txt",sep="")
S = 4 # number of shelves
P = 40 # number of products
Shelf_choice <-
make.lp(0,nrow(mydata) * 2) # create the lp object with decision variables == longitude of data.frame
#### SET OBJECTIVE FUNCTION ####
#### Set controls for the model ####
lp.control(Shelf_choice,sense = "max",timeout = 10,presolve = "none") ## timeout prevents getting stuck
set.objfn(Shelf_choice,c(rep(rep(0,nrow(
mydata
)),1),mydata$Pu_j)) # maximize profit (Pu_j)
set.type(Shelf_choice,1:nrow(mydata),"binary") # present on shelf or not
set.type(Shelf_choice,1:nrow(mydata) + nrow(mydata),"integer") # number of product j on shelf
### Assure that each product appears on minimum number of shelves (1 in this case)
Add_productShelf_constraint <- function (prod_index) {
cargo_cols <-
(0:(S - 1)) * P + prod_index # # index of products by column (eg. 1,41,81,121)
add.constraint(
Shelf_choice,rep(1,S),# repeat value the same number of times as shelves
indices = cargo_cols,type = ">=",rhs = mydata$smin_j[prod_index]
) # value of minimum number of shelves
}
lapply(1:P,Add_productShelf_constraint) # list apply this for every product
### Assure that product appears no more than the number of shelves permitted (2 in this case)
Add_productShelfMAX_constraint <- function (prod_index) {
cargo_cols <-
(0:(S - 1)) * P + prod_index # index of products by column (eg. 1,type = "<=",rhs = mydata$smax_j[prod_index]
) # value of minimum number of shelves
}
lapply(1:P,Add_productShelfMAX_constraint) # list apply this for every product
### Third Constraint: Products too tall for a shelf are excluded
Add_height_constraint <-
function (prod_index) {
# this needs to be improved
add.constraint(Shelf_choice,1,indices = prod_index,type = "=",rhs = 0)
}
lapply(which(mydata$height == 0),Add_height_constraint) # Here we select the colums which have 0 (don't fit),and set the value to 0
## Products are on consecutive shelves - this currently only works for two shelves
Add_nextshelf_constraint <- function (prod_index) {
mat1 <- combn(1:S,2)[,which(combn(1:S,2)[2,] - combn(1:S,2)[1,] != 1)]
cargo_cols <- (0:(S - 1)) * P + prod_index
result <- matrix(cargo_cols[mat1],nrow = 2)
for (i in 1:ncol(result)) {
add.constraint(
Shelf_choice,c(1,indices = result[,i],rhs = 1
)
}
}
lapply(1:P,Add_nextshelf_constraint)
### Product facings only appear on selected shelves (where Xij = 1)
Add_FF_constraint1 <- function (prod_index) {
Y01col <- prod_index
print(Y01col)
FF_col <- prod_index + nrow(mydata)
add.constraint(
Shelf_choice,-100),indices = c(FF_col,Y01col),rhs = 0
)
}
lapply(1:nrow(mydata),Add_FF_constraint1) #
Add_FF_constraint2 <- function (prod_index) {
Y01col <- prod_index
FF_col <- prod_index + nrow(mydata)
add.constraint(
Shelf_choice,-1),Add_FF_constraint2) #
#### Sum of product widths on shelves does not exceed shelf length
Add_FijShelflength_constraint <- function (shelf_index) {
shelf_cols_mydata <- ((1:(P)) + (shelf_index - 1) * P)
FF_shelf_cols <- ((1:(P)) + (shelf_index - 1) * P) + nrow(mydata)
add.constraint(
Shelf_choice,c(mydata$Pw_j[shelf_cols_mydata]),# width of each product
indices = c(FF_shelf_cols),# indices of products per shelf in Fij Matrix
rhs = shelves$Sl_i[shelf_index]
) # length of each shelf
}
lapply(1:S,Add_FijShelflength_constraint) # list apply this by shelf index
## add minimum number of total facings
Add_min_facings_constraint <- function (prod_index) {
FjSi_cols <-
(0:(S - 1)) * P + prod_index + nrow(mydata) # index of the products by column in out table
add.constraint(
Shelf_choice,# repeat value the same number of times as shelves
indices = FjSi_cols,# index of products by column (eg. 1,121)
type = ">=",rhs = mydata$Fmin_j[prod_index]
) # value of minimum number of products
}
lapply(1:P,Add_min_facings_constraint) # list apply this for every product
## add maximum number of facings
Add_max_facings_constraint <- function (prod_index) {
FjSi_cols <-
(0:(S - 1)) * P + prod_index + nrow(mydata)
add.constraint(
Shelf_choice,121)
type = "<=",rhs = mydata$Fmax_j[prod_index]
) # value of maximum number of products
}
lapply(1:P,Add_max_facings_constraint) # list apply this for every product
solve(Shelf_choice)
get.objective(Shelf_choice) # gives the total value of the facings
### Tabulates the results ####
test <- matrix(get.variables(Shelf_choice),ncol = S * 2,byrow = F)
rownames(test) <- paste0("Product",1:40)
colnames(test) <- c(rep(paste0("Shelf",1:4),2))
test[,5:8] # shows the product placements (uneven products between shelves)
#
结果:
产品 | 货架 1 | 货架 2 | 货架 3 | 货架 4 |
---|---|---|---|---|
P1 | 0 | 0 | 0 | 2 |
- | - | - | - | - |
P11 | 1 | 7 | 0 | 0 |
P16 | 2 | 2 | 0 | 0 |
例如,我需要产品 11 在每个货架上有相同数量的产品(每个货架 4 个)
我试图创建一个约束,例如:
Sum_Xshelf_constraint <- function (prod_index) {
binary_sum <-
sum(get.variables(Shelf_choice)[(0:(S - 1)) * P + prod_index])
total_Fij <-
sum(get.variables(Shelf_choice)[(0:(S - 1)) * P + prod_index + nrow(df)])
total_cols <-
(0:(S - 1)) * P + prod_index + nrow(df) # index of the products in Fij
for (i in 1:length(total_cols)) {
add.constraint(
Shelf_choice,c(binary_sum),indices = c(total_cols[i]),rhs = total_Fij
) # value of minimum number which is Fmin_j
}
}
### At least one product on a shelf
lapply(1:P,Sum_Xshelf_constraint)
任何想法如何实现这一目标?提前致谢。
解决方法
如果你的决策变量是 PiSj(#ith Product on jth Shelf),那么一系列链式方程就可以工作:
P1S1 = P1S2
P1S2 = P1S3
P1S3 = P1S4
这种简单有时可以显着提高性能。
,我必须在这里回答我自己的问题:
这是不可能的。
仔细阅读,似乎这个特定约束是二次的... (http://lpsolve.sourceforge.net/5.5/)
"假设 xj 必须取一个整数值 i:
yj / y0 = i
或
yj = i * y0
不幸的是,这个约束不能被 lpsolve 处理,因为它是二次的。”
完成后,我将使用二次解法编辑此答案。我想我最好现在发布这个,这样其他人就不会花太多精力去尝试解决它。
谢谢!