Search code examples
rsystemsimulationinventory

Immediate Inventory Restock in R Simmer


I am fairly new to both the Simmer library and R in general, so I was hoping someone could help me with this issue.

The examples in the Simmer documentation show a restock monitor that checks inventory on set intervals, but I want a restock to occur immediately after a customer retrieves some amount of inventory. I've tried creating a restock generator with an indefinite start time and using set_source("Restock", at(now(env)) to reschedule the restock to occur at the current sim time, but this doesn't seem to work. Any suggestions?

# Inv. properties
INV_CAP      <- 100
INV_TRIG     <- 30
INV_LEVEL    <- INV_CAP

# Environment rates
SERVE_RATE   <- 1/10
RESTOCK_RATE <- 1/10

env <- simmer()

restock <- trajectory() %>%
  # Restock only beneath INV_TRIG threshold
  branch(function() INV_LEVEL <= INV_TRIG,
    continue = TRUE,
      trajectory() %>%
        log_("Begin restock") %>%
        timeout(function() rexp(1, RESTOCK_RATE)) %>%
        log_(function(){
          INV_LEVEL <<- INV_CAP
          paste("Restock finished")
        }))

serve <- trajectory() %>%
  log_("Begin serving") %>%
  timeout(function() rexp(1, SERVE_RATE)) %>%
  # Decrease inv. level and cust. demand
  set_attribute("demand", function() {
    amount <- min(INV_LEVEL, get_attribute(env, "demand"))
    INV_LEVEL <<- INV_LEVEL - amount
    return(-amount)
  }, mod = "+")

customer <- trajectory() %>%
  set_attribute("demand", function() sample(DEMAND_MIN:DEMAND_MAX, 1)) %>%
  log_("Entering queue") %>%
  seize("Server") %>%
  join(serve) %>%
  release("Server") %>%
  log_("Finished")

env %>%
  add_resource("Server", capacity = SERVER_CAP, queue_size = QUEUE_CAP) %>%
  add_generator("Customer", customer, function() rexp(1, CUST_RATE), mon = 2) %>%
  run(until = 500)

Solution

  • To set a "Restock" source, you need to define an inactive "Restock" generator in the first place. And given that it is inactive, you need to activate it after setting the new source. I'll give you a small example:

    library(simmer)
    
    env <- simmer()
    
    restock <- trajectory() %>%
      log_("restock")
    
    serve <- trajectory() %>%
      log_("serve") %>%
      set_source("Restock", at(0)) %>%
      activate("Restock")
    
    env %>%
      add_generator("Customer", serve, at(1, 2, 3)) %>%
      add_generator("Restock", restock, at(-1)) %>%
      run()
    

    EDIT: if you define the following convenience function (I think I'll add it to simmer for the next release):

    when_activated <- function(n=1) {
      first <- TRUE
      function() {
        if (first) {
          first <<- FALSE
          return(-1)
        }
        c(rep(0, n), -1)
      }
    }
    

    Then,

    library(simmer)
    
    env <- simmer()
    
    restock <- trajectory() %>%
      log_("restock")
    
    serve <- trajectory() %>%
      log_("serve") %>%
      activate("Restock")
    
    env %>%
      add_generator("Customer", serve, at(1, 2, 3)) %>%
      add_generator("Restock", restock, when_activated()) %>%
      run()
    

    and that's it.