使用SIMER包(或替代方案)调度资源时使用路由逻辑 [英] Use routing logic when dispatching resources with simmer package (or an alternative)

查看:11
本文介绍了使用SIMER包(或替代方案)调度资源时使用路由逻辑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法将(定制的)路由引擎与simmer包一起用于离散事件模拟?(或其他包)


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

对于我的代码的某些部分,我了解如何将其切换为simmer。但到目前为止,我还想不出如何将路由逻辑与资源调度结合使用。


示例:下面的最小示例显示了我需要的功能类型(并且不知道如何使用SIMMER构建)。

生成一些数据events(作业)和resources

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
)
路由逻辑简化版:根据eventresources的位置计算路径。(对于该示例,仅指向介于0和1之间的一维空间,在真实示例中,OSRM算法的定制版本与历史数据一起..)

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

模拟的两个版本。sim只获取第一个可用的资源,而不考虑waytimesim_nearest为所有空闲资源计算waytimes,并将其调度到最近的资源。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

是否可以使用SIMER(或其他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)
如您所见,我已经将events数据框直接连接到轨迹(您不再需要resourceworktime;前者将存储为res_id属性,而后者将由simmer自动监控并使用get_mon_arrivals()检索))。我们指定t是Time列,另一个position将作为属性添加到每个事件,如我前面所说。

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

这篇关于使用SIMER包(或替代方案)调度资源时使用路由逻辑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆