【发布时间】:2018-01-10 00:08:48
【问题描述】:
我有很多工作需要在特定的时间间隔内完成。然而,我们每天做这项工作的资源有限。因此,我正在尝试优化开始时间日期(开始时间日期只能向前移动而不是向后移动),以便每天使用的资源与我们的预算更不相似。
这些函数用在下面的例子中::
# Function to shift/rotate a vector
shifter <- function(x, n = 1) {
if (n == 0) x else c(tail(x, -n), head(x, n))
}
# Getting a range of dates
get_date_range <- function(current_date = Sys.Date(), next_planned_date = Sys.Date() + 5)
{
seq.Date(as.Date(current_date), as.Date(next_planned_date), "days")
}
假设一个玩具示例数据集 :: 这里任务 P1 从 14 日开始,而 P2 从 15 日开始。值为零表示当天没有为该任务完成任何工作。
# EXAMPLE TOY DATASET
datain = data.frame(dated = c("2018-12-14", "2018-12-15", "2018-12-16", "2018-12-17"),
P1 = c(1,2,0,3), P2 = c(0,4,0,6)) %>%
mutate(dated = as.character(dated))
#The amount of resources that can be used in a day
max_work = 4
# We will use all the possible combination of start dates to
# search for the best one
possible_start_dates <- do.call(expand.grid, date_range_of_all)
# Utilisation stores the capacity used during each
# combination of start dates
# We will use the minimum of thse utilisation
utilisation <- NULL # utilisation difference; absolute value
utilisation_act <- NULL # actual utilisation including negative utilisation
# copy of data for making changes
ndatain <- datain
# Move data across possible start dates and
# calculate the possible utilisation in each movements
for(i in 1:nrow(possible_start_dates)) # for every combination
{
for(j in 1:ncol(possible_start_dates)) # for every plan
{
# Number of days that are different
days_diff = difftime(oriz_start_date[["Plan_Start_Date"]][j],
possible_start_dates[i,j], tz = "UTC", units = "days" ) %>% as.numeric()
# Move the start dates
ndatain[, (j+1)] <- shifter(datain[, (j+1)], days_diff)
}
if(is.null(utilisation)) # first iteration
{
# calculate the utilisation
utilisation = c(i, abs(max_work - rowSums(ndatain %>% select(-dated))))
utilisation_act <- c(i, max_work - rowSums(ndatain %>% select(-dated)))
}else{ # everything except first iteration
utilisation = rbind(utilisation, c(i,abs(max_work - rowSums(ndatain %>% select(-dated)))))
utilisation_act <- rbind(utilisation_act, c(i, max_work - rowSums(ndatain %>% select(-dated))))
}
}
# convert matrix to dataframe
row.names(utilisation) <- paste0("Row", 1:nrow(utilisation))
utilisation <- as.data.frame(utilisation)
row.names(utilisation_act) <- paste0("Row", 1:nrow(utilisation_act))
utilisation_act <- as.data.frame(utilisation_act)
# Total utilisation
tot_util = rowSums(utilisation[-1])
# replace negative utilisation with zero
utilisation_act[utilisation_act < 0] <- 0
tot_util_act = rowSums(utilisation_act[-1])
# Index of all possible start dates producing minimum utilization changes
indx_min_all = which(min(tot_util) == tot_util)
indx_min_all_act = which(min(tot_util_act) == tot_util_act)
# The minimum possible dates that are minimum of actual utilisation
candidate_dates <- possible_start_dates[intersect(indx_min_all, indx_min_all_act), ]
# Now check which of them are closest to the current starting dates; so that the movement is not much
time_diff <- c()
for(i in 1:nrow(candidate_dates))
{
# we will add this value in inner loop so here we
timediff_indv <- 0
for(j in 1:ncol(candidate_dates))
{
diff_days <- difftime(oriz_start_date[["Plan_Start_Date"]][j],
candidate_dates[i,j], tz = "UTC", units = "days" ) %>% as.numeric()
# print(oriz_start_date[["Plan_Start_Date"]][j])
# print(candidate_dates[i,j])
#
# print(diff_days)
timediff_indv <- timediff_indv + diff_days
}
time_diff <- c(time_diff, timediff_indv)
}
# Alternatives
fin_dates <- candidate_dates[min(time_diff) == time_diff, ]
上面的代码运行良好并产生了预期的输出;但是它不能很好地扩展。我有非常大的数据集(两年的工作以及间隔重复的数千个不同的任务)并且搜索所有可能的组合不是一个可行的选择。有没有办法可以将此问题表述为标准优化问题并使用Rglpk 或Rcplex 或更好的解决方案。感谢您的意见。
【问题讨论】:
-
对我来说似乎是knapsack problem。您可能会在 R(包)或 C++ 中找到一些已经实现的算法。
-
我将从更精确的问题描述开始。然后建立一个数学模型。从中您可以着手实现并做一些性能技巧(例如滚动水平以使用更小的时间窗口)。
-
“我有一堆工作需要在特定的时间间隔内执行”。这是什么意思?每个任务都是三重?或者可能是?还是别的什么?
-
@sprinkus 我假设 OP 的意思是如果任务
P2是c(0,4,0,6),那么执行P2作为c(4,0,6,0)是允许的,因为它会及时移回并保持其特定的间隔,但是c(4,6,0,0)不是,因为间隔不相等。也许OP可以确认?
标签: r algorithm mathematical-optimization schedule resource-scheduling