使用 Simmer 构建特定模型

Using Simmer to build a specific model

我有实际事件的数据,我需要模拟如果有不同的资源可能会发生什么。下一阶段将构建一个 "proper" 模拟,其中事件和时间的创建更加随机。我的问题是我无法弄清楚如何确保为特定的 activity 分配实际生活中的开始时间、优先级和超时。

library(simmer)
set.seed(654)
env <- simmer()
workerCount <- 2

actualData <- data.frame(arrTime = c(1:10,1:5), 
priority = 1:3, duration = rnorm(15, 50, 5))

activityTraj <- trajectory() %>%
seize('worker') %>%
timeout(5) %>%
release('worker')

env %>%
add_resource('worker', workerCount, Inf, preemptive = TRUE) %>%
add_generator('worker', activityTraj, at(actualData$arrTime), 
mon = 2, priority = 2)

env %>% run(50)

我在上面需要做的是让生成器中的优先级从数据帧中读取(当前硬编码为 2),轨迹中的超时(当前硬编码为 5)也从数据框。我看不出如何确保指定 activity 的优先级和时间的行也将用于指定持续时间(或 "timeout")。

首先,您必须确保您的actualData帧按arrTime:

排序
actualData <- data.frame(arrTime = c(1:10,1:5), 
                         priority = 1:3, 
                         duration = rnorm(15, 50, 5)) %>%
  dplyr::arrange(arrTime)

然后,让我们构建一个辅助函数来使用您的 actualData:

的列
consume <- function(x, prio=FALSE) {
  i <- 0
  function() {
    i <<- i + 1
    if (prio) c(x[[i]], x[[i]], FALSE)
    else x[[i]]
  }
}

可以按如下方式应用于您的轨迹:

activityTraj <- trajectory() %>%
  set_prioritization(consume(actualData$priority, TRUE)) %>%
  set_attribute("duration", consume(actualData$duration)) %>%
  seize('worker') %>%
  timeout(function(attr) attr["duration"]) %>%
  release('worker')

因为您的到达时间已排序。最后,让我们运行模拟一下:

env %>%
  add_resource('worker', workerCount, Inf, preemptive = TRUE) %>%
  add_generator('worker_', activityTraj, at(actualData$arrTime)) %>%
  run()

并检查实际持续时间是否正常:

activity_time <- get_mon_arrivals(env) %>%
  tidyr::separate(name, c("prefix", "n"), convert=TRUE) %>%
  dplyr::arrange(n) %>%
  dplyr::pull(activity_time)

all(activity_time == actualData$duration)
#> TRUE

更新:自simmer v3.8.0以来,新的数据源add_dataframe大大简化了这种模式:

library(simmer)

workerCount <- 2
actualData <- data.frame(
  time = c(1:10,1:5), priority = 1:3, service = rnorm(15, 50, 5)) %>%
  dplyr::arrange(time)

activityTraj <- trajectory() %>%
  seize('worker') %>%
  timeout_from_attribute("service") %>%
  release('worker')

env <- simmer() %>%
  add_resource('worker', workerCount, Inf, preemptive = TRUE) %>%
  add_dataframe('worker_', activityTraj, actualData, time="absolute") %>%
  run()

activity_time <- get_mon_arrivals(env) %>%
  tidyr::separate(name, c("prefix", "n"), convert=TRUE) %>%
  dplyr::arrange(n) %>%
  dplyr::pull(activity_time)

all(activity_time == actualData$duration)
#> TRUE