运维开发网
广告位招商联系QQ:123077622
 
广告位招商联系QQ:123077622

使用simmer包(或替代方案)调度资源时使用路由逻辑

运维开发网 https://www.qedev.com 2020-06-17 19:33 出处:网络 作者:运维开发网整理
有没有办法将(定制的)路由引擎与simmer包一起用于离散事件模拟? (或另类包裹) 上下文:我正在使用R运行dicrete-event simulations(DES).现在我所有的模拟都是在没有使用为DES设计的R包的情况下构建的.由于我的代码越来越大(性能越来越差),我正在考虑切换到为DES设计的R软件包之一. 对于我的代码的某些部分,我看到我如何将其切换为慢煮.但到目前为止,我无法弄清楚如
有没有办法将(定制的)路由引擎与simmer包一起用于离散事件模拟? (或另类包裹)

上下文:我正在使用R运行dicrete-event simulations(DES).现在我所有的模拟都是在没有使用为DES设计的R包的情况下构建的.由于我的代码越来越大(性能越来越差),我正在考虑切换到为DES设计的R软件包之一.

对于我的代码的某些部分,我看到我如何将其切换为慢煮.但到目前为止,我无法弄清楚如何将路由逻辑与资源调度结合使用.

示例:以下最小示例显示了我需要的功能(并且无法弄清楚如何使用simmer构建).

生成一些数据,事件(作业)和资源

set.seed(1)

events <- data.frame(
  id = 1:3L,
  t = sort(trunc(rexp(3) * 100)),
  position = runif(3),
  resource = NA,
  worktime = NA
)

resources <- data.frame(
  id = 1:2L,
  position = c(0.2, 0.8),
  t_free = 0
)

路由逻辑的简化版本:根据事件和资源的位置计算路由. (对于该示例,仅指向0和1之间的1-D空间,在实际示例中,OSRM算法的定制版本与历史数据一起…)

waytime <- function(events, resources, i) {
  trunc(abs(events$position[i] - resources$position[resources$id == events$resource[i]]) * 100)
}

两个版本的模拟. sim只需要第一个可用的资源而不考虑方式时间. sim_nearest计算所有空闲资源的方式时间并调度到最近的资源. sim_nearest是我在实际例子中想要的,不知道如何使用simmer构建.

sim <- function(events, resources) {
  for (i in 1:nrow(events)) {
    # Default dispatching: Use the first free vehicle
    events$resource[i] <- resources$id[resources$t_free <= events$t[i]][1]
    # Simulate event
    events$worktime[i] <- waytime(events, resources, i)
    resources$t_free[events$resource[i]] <- events$t[i] + events$worktime[i]
  }
  return(list(events = events, resources = resources))
}

sim_use_nearest <- function(events, resources) {
  for (i in 1:nrow(events)) {
    # Dispatching by position: Use the nearest free resource
    ids_free <- resources$id[resources$t_free <= events$t[i]]
    events$resource[i] <- resources$id[which.min(abs(resources$position[ids_free] - events$position[i]))]
    # Simulate event
    events$worktime[i] <- waytime(events, resources, i)
    resources$t_free[events$resource[i]] <- events$t[i] + events$worktime[i]
  }
  return(list(events = events, resources = resources))
}

模拟两种选择:

res <- sim(events, resources)
res_use_nearest <- sim_use_nearest(events, resources)

看到差异:

res$events
# id   t  position resource worktime
#  1  14 0.9082078        1       70
#  2  75 0.2016819        2       59
#  3 118 0.8983897        1       69
res$resources
# id position t_free
#  1      0.2    187
#  2      0.8    134
res_use_nearest$events
# id   t  position resource worktime
#  1  14 0.9082078        2       10
#  2  75 0.2016819        1        0
#  3 118 0.8983897        2        9
res_use_nearest$resources
# id position t_free
#  1      0.2     75
#  2      0.8    127

是否可以使用simmer(或其他R DES包)生成相同的结果?

Samy的方法很好,但我会略微不同(请注意,这没有经过测试,因为我没有编写必要的routing_logic函数):

library(simmer)

env <- simmer()

t <- trajectory() %>%
  seize("available_resources") %>%
  set_attribute(c("res_id", "delay"), routing_logic) %>%
  select(function() paste0("res_", get_attribute(env, "res_id"))) %>%
  seize_selected() %>%
  timeout_from_attribute("delay") %>%
  release_selected() %>%
  release("available_resources")

请注意,“available_resources”(必须是容量等于您拥有的资源数量的资源)就像一个令牌.一旦被占用,这意味着有一些资源可用.否则,事件只是坐在那里等待.

routing_logic()必须是基于某个策略(例如,第一个可用或最近)选择“res_id”的函数,计算延迟并返回两个值,这些值作为属性存储.在该函数中,您可以使用get_capacity()来了解每个资源的状态,而无需设置t_free.您还可以检索该事件的position属性,该属性将自动设置如下:

set.seed(1)

events <- data.frame(
  t = sort(trunc(rexp(3) * 100)),
  position = runif(3)
)

resources <- data.frame(
  id = 1:2L,
  position = c(0.2, 0.8)
)

env %>% 
  add_dataframe("event_", t, events, mon=2, col_time="t", time="absolute") %>%
  add_resource("available_resources", capacity=nrow(resources))

for (id in resources$id) env %>%
  add_resource(paste0("res_", id), capacity=1, queue_size=0)

如您所见,我已将事件数据框直接连接到轨迹(您不再需要资源和工作时间;前者将存储为res_id属性,后者将由simmer自动监视并使用get_mon_arrivals()).我们指定t是时间列,另一个位置将作为属性添加到每个事件中,正如我之前所说的那样.

通过此设置,您只需重新定义routing_logic()即可实现不同的策略和不同的结果.

扫码领视频副本.gif

0

精彩评论

暂无评论...
验证码 换一张
取 消