Re: [simmer-devel] Combining trajectories

79 views
Skip to first unread message
Message has been deleted

Iñaki Ucar

unread,
May 24, 2021, 7:32:12 AM5/24/21
to simmer-devel
Hi,

On Fri, 21 May 2021 at 14:01, Joe Micoud <de-w...@web.de> wrote:
>
> Hello,
>
> i want to combine several trajectories, but the second trajectory shall only start, if the first trajectory is finished after several arrivals.
> As afterwards it is aimed to optimize the resources the rollback () does not work. Hence, I am using the "activate" function. But thus, the second trajectory is activated multiple times. In the following code there are 2 arrivals for the first trajectory and three for the second. But as the second trajectory is activated two times, there are 6 runs for the second trajectory.

What's the exact behaviour you are looking for? I see two
possibilities: (1) the 3 arrivals in delivery2 start as soon as the
first arrival in delivery1 ends that trajectory; (2) delivery2 should
wait for the 2 arrivals en delivery1 to finish. Both cases have a
similar solution: clone/synchronize:

delivery1_process <- trajectory("delivery1_process") %>%
clone(amount_delivery[1]) %>%
... # seize, timeout, release...
synchronize(wait = ...) %>%
activate("delivery2_process")

If wait=FALSE, it's case (1); otherwise, we're in case (2). You can do
the same for delivery2_process in order to activate the following one.

> Besides, the trajectories one and two (delivery_process) are actually the same with different variables. Is it possible to simplify this?

Yes, it is: write a function to build such trajectories with input
parameters name, delivery_operationtime, delivery_sigma and
activate_next. Then,

delivery1_process <- delivery_process(
name = "delivery1_process",
delivery_operationtime = delivery_operationtime[1],
delivery_sigma = delivery_sigma[1],
activate_next = "delivery2_process"
)

etc.

>
> Following a simplified code:
> library(simmer)
>
> amount_delivery=c(2, 3)
> delivery_operationtime=c(10, 10)
> delivery_sigma=c(1, 1)
> unloading_operationtime=c(15, 10)
> unloading_sigma=c(2, 2)
>
> envs=simmer("envs")
> envs
>
> delivery1_process <- trajectory("delivery1_process") %>%
>
> seize("delivery", 1) %>%
> timeout(function() rnorm (1, delivery_operationtime [1], delivery_sigma [1])) %>%
> release("delivery", 1) %>%
> seize("unloading", 1) %>%
> timeout(function() rnorm(1, 5, 2)) %>%
> release("unloading", 1) %>%
>
> activate ("delivery2_process")
>
> delivery2_process <- trajectory("delivery2_process") %>%
>
> seize("delivery", 1) %>%
> timeout(function() rnorm (1, delivery_operationtime [2], delivery_sigma [2])) %>%
> release("delivery", 1) %>%
> seize("unloading", 1) %>%
> timeout(function() rnorm(1, 5, 2)) %>%
> release("unloading", 1) %>%
>
> activate ("packing_process")
>
> packing_process <- trajectory("packing_process") %>%
>
> seize("packing", 1) %>%
> timeout(function() rnorm(1, 6, 3)) %>%
> release("packing", 1)
>
> envs=simmer("envs") %>%
> add_resource("delivery", 1) %>%
> add_resource("unloading", 1) %>%
> add_generator("delivery1_process", delivery1_process, at(rep(0, amount_delivery[1])))%>%
> add_generator("delivery2_process", delivery2_process, when_activated(amount_delivery[2])) %>%
> add_resource("packing",1)%>%
> add_generator("packing_process",packing_process, when_activated())
>
>
> Thanks in advance!
>
>
> --
> You received this message because you are subscribed to the Google Groups "simmer-devel" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to simmer-devel...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/simmer-devel/bd332f2d-a15c-4d67-bbb3-16339e63e809n%40googlegroups.com.



--
Iñaki Úcar

Joe Micoud

unread,
Jun 25, 2021, 6:43:12 AM6/25/21
to simmer-devel

Hi,

I have another question. I worked in interruptions of the simulation according to a distribution. This interruption interrupts the activity2. After a timeout the actual activity can proceed. The interruptions shall not happen after finish of the actual process. Thus, I used the deactivate function. But unfortunately one interruption still occurs frequently after the actual finish of the process. Is there a possibility to prevent this? And actually the interruption distribution shall only start, when activity2 is activated. Is there a way to combin when activated and a distribution?

Additionally, I would like to investigate an inter arrival time for activity2. Activity2 shall start after activation by activity1. Then a total amount of arrivals should be created according to an arrival time and amount of arrivals per inter arrival. For example, total arrivals of 20 with an inter arrival time of 5 time units with 5 arrivals each inter arrival. Hence, there would be 4 inter arrivals. Afterwards the inter arrival time shall be investigated. For example, only 2 inter arrivals of 10 arrivals with an inter arrival time of 10. Is there a possibility to simulate this? 

Thanks

library(simmer)
library(parallel)

amount=2
amount_2=20

activity1_<-trajectory("activity1_")%>%
        
        clone(amount)%>%               
        seize("operation1", 1) %>%
        log_("operation1")%>%
        timeout(10)%>%
        release("operation1", 1) %>%
         log_("operation1 finish")%>%
  
        synchronize(wait=TRUE)%>%
        activate ("activity2_")

activity2_<-trajectory ("activity2_")%>%
                       
        clone(amount_2)%>%
  
        seize("operation2", 1) %>%
        log_("operation2")%>%
        timeout(5)%>%
        release("operation2", 1) %>%
        log_("operation2 finish")%>%  
        deactivate("interruption_")%>%
        
        synchronize(wait=TRUE)%>%
        activate ("activity3_")
           
activity3_<- trajectory("activity3_") %>%
  
  seize("operation3", 1) %>%
  log_("operation3")%>%
  timeout(20)%>%
  release("operation3", 1) %>%
  log_("operation3 finish")
  
interruption_ <- trajectory("interruption_") %>%
  
    log_("interruption_" ) %>%
    seize("operation2", 1) %>%
    timeout(5) %>%
    log_("interruption_fin") %>%
    release("operation2", 1)
  
envs <- mclapply(1:3, function(i) {
  simmer("Site") %>%
    
    add_generator("activity1_", activity1_, at(rep(0,1))) %>%
    add_generator("activity2_", activity2_, when_activated(1)) %>%
    add_generator("activity3_", activity3_, when_activated(1)) %>%
    add_generator("interruption_", interruption_,
                  function() rnorm (1,80, 20), priority = 1)%>%
    
    add_resource("operation1", 1, Inf, preemptive = TRUE) %>%
    add_resource("operation2", 1, Inf, preemptive = TRUE) %>%
    add_resource("operation3", 1, Inf, preemptive = TRUE) %>%
    
    run() 
})

Iñaki Ucar

unread,
Jun 25, 2021, 10:10:56 AM6/25/21
to simmer-devel
On Fri, 25 Jun 2021 at 12:43, Joe Micoud <de-w...@web.de> wrote:
>
> Hi,
>
> I have another question. I worked in interruptions of the simulation according to a distribution. This interruption interrupts the activity2. After a timeout the actual activity can proceed. The interruptions shall not happen after finish of the actual process. Thus, I used the deactivate function. But unfortunately one interruption still occurs frequently after the actual finish of the process.

Yes, this is indeed a quirk in deactivate(). What happens is that the
generator is deactivated, but the arrival that was scheduled the last
time it was executed is still there. And that's kind of annoying, and
certainly unexpected from the user perspective. I'll open an issue to
track and solve this in a future release.

> Is there a possibility to prevent this?

Now, as a workaround, you could set a global with value equal to 0 and
change it to 1 when you deactivate your source. Then, in your
interruption trajectory, put something like leave(function()
get_global(env, "my_var")).

> And actually the interruption distribution shall only start, when activity2 is activated. Is there a way to combine when activated and a distribution?

Currently, when_activated() does not support a function, but it should
be rather easy to adapt to that end. See the source code here:
https://github.com/r-simmer/simmer/blob/master/R/generators.R#L190.
I'll open an issue to make that helper accept a function too in a
future release.

> Additionally, I would like to investigate an inter arrival time for activity2. Activity2 shall start after activation by activity1. Then a total amount of arrivals should be created according to an arrival time and amount of arrivals per inter arrival. For example, total arrivals of 20 with an inter arrival time of 5 time units with 5 arrivals each inter arrival. Hence, there would be 4 inter arrivals. Afterwards the inter arrival time shall be investigated. For example, only 2 inter arrivals of 10 arrivals with an inter arrival time of 10. Is there a possibility to simulate this?

To generate batches of arrivals, your interarrival function just need
to return zeroes. For instance, 5 simultaneous arrivals at 3 time
units from now would be returning c(3, 0, 0, 0, 0). Not sure if this
answers your question though.

--
Iñaki Úcar

Iñaki Ucar

unread,
Jun 25, 2021, 10:17:23 AM6/25/21
to simmer-devel
For reference, here are the two issues:

https://github.com/r-simmer/simmer/issues/249
https://github.com/r-simmer/simmer/issues/250
--
Iñaki Úcar

Joe Micoud

unread,
Jun 28, 2021, 12:13:27 PM6/28/21
to simmer-devel

Thanks for the quick help. The source code is very helpful. With a change in the when_activated code it is possible to simulate arrivals according to a distribution after activation.

I worked in a source for interruption, but somehow it is NA, although it is defined. Thus, it is not working as expected.  Why is this?

I would like to optimize the interarrival time automatically for a certain amount of arrivals. In the actual simulation there is a high amount of arrivals. Therefore, by doing this manual is cumbersome. Is there a way to compare different interarrival times like in the simmer.optim example. But each interarrival is containing different amount of arrivals. For example, there is a total amount of 12 arrivals. Hence, there could be a daily delivery of 2 arrivals 6 days or a delivery of 6 arrivals every 3 days.

amount=2
amount_2=3


when_activated2 <- function(n, m, s) {
  first <- TRUE
  function() {
    if (first) {
      first <<- FALSE
      return(-1)
    }
    c(rnorm(n,m,s), -1)
  }
}

envs<-simmer()

activity1_<-trajectory("activity1_")%>%
  
  clone(amount)%>%               
  log_("operation1")%>%
  seize("operation1", 1) %>%
  timeout(10)%>%
  release("operation1", 1) %>%
  log_("operation1 finish")%>%
  
  synchronize(wait=TRUE)%>%
  activate ("activity2_")%>%
  activate ("interruption_")
  
activity2_<-trajectory ("activity2_")%>%
  
  set_global("my_var", 0)%>%
  log_(function() paste(get_global(envs, "my_var"))) %>%
  
  clone(amount_2)%>%
  
  log_("operation2")%>%
  seize("operation2", 1) %>%
  timeout(5)%>%
  release("operation2", 1) %>%
  log_("operation2 finish")%>%  

  synchronize(wait=TRUE)%>%
  activate ("activity3_")

activity3_<- trajectory("activity3_") %>%
  
  batch(2)%>%
  set_global("my_var", 1)%>%
  seize("operation3", 1) %>%
  log_("operation3")%>%
  timeout(20)%>%
  release("operation3", 1) %>%
  log_("operation3 finish")

interruption_ <- trajectory("interruption_") %>%
  
  leave(function()get_global(envs,"my_var")>0.5)%>%
  log_("interruption_" ) %>%
  seize("operation2", 1) %>%
  timeout(5) %>%
  log_("interruption_fin") %>%
  release("operation2", 1)

envs <- mclapply(1:2, function(i) {
  simmer("Site") %>%
    
    add_generator("activity1_", activity1_, at(rep(0,1))) %>%
    add_generator("activity2_", activity2_, when_activated2(2,20,2)) %>%
    add_generator("activity3_", activity3_, when_activated(1)) %>%
    add_generator("interruption_", interruption_, when_activated2(1,20,5),
                  priority = 1)%>%
    
    add_resource("operation1", 1, Inf, preemptive = TRUE) %>%
    add_resource("operation2", 1, Inf, preemptive = TRUE) %>%
    add_resource("operation3", 1, Inf, preemptive = TRUE) %>%
    
    run() 
})

Iñaki Ucar

unread,
Jun 29, 2021, 6:48:55 AM6/29/21
to simmer-devel
On Mon, 28 Jun 2021 at 18:13, Joe Micoud <de-w...@web.de> wrote:

Thanks for the quick help. The source code is very helpful. With a change in the when_activated code it is possible to simulate arrivals according to a distribution after activation.

I worked in a source for interruption, but somehow it is NA, although it is defined. Thus, it is not working as expected.  Why is this?

See the following thread about parallelization: https://github.com/r-simmer/simmer/discussions/244
 

I would like to optimize the interarrival time automatically for a certain amount of arrivals. In the actual simulation there is a high amount of arrivals. Therefore, by doing this manual is cumbersome. Is there a way to compare different interarrival times like in the simmer.optim example. But each interarrival is containing different amount of arrivals. For example, there is a total amount of 12 arrivals. Hence, there could be a daily delivery of 2 arrivals 6 days or a delivery of 6 arrivals every 3 days.

So what is exactly your optimization objective?

--
Iñaki Úcar

Joe Micoud

unread,
Jun 29, 2021, 11:25:16 AM6/29/21
to simmer-devel

Great, the hint using simulate function works well.

I would like to minimise total duration under possible ranges for resources and interarrival times. Thus, optimisation of allocation of resources, capacity rates and interarrival time. And in the end consideration/minimisation of budget as well.

Iñaki Ucar

unread,
Jul 1, 2021, 7:13:42 AM7/1/21
to simmer-devel
On Tue, 29 Jun 2021 at 17:25, Joe Micoud <de-w...@web.de> wrote:

Great, the hint using simulate function works well.

I would like to minimise total duration under possible ranges for resources and interarrival times. Thus, optimisation of allocation of resources, capacity rates and interarrival time. And in the end consideration/minimisation of budget as well.

simmer.optim is still experimental, but I believe it should work for you. Take a look at the example in the README. You can parametrize your variables (resources, interarrival times...) with .opt(), define your objective (total duration, or e.g. total duration * budget) and a set of constraints (e.g. for the budget), then apply different optimizers.

--
Iñaki Úcar
Reply all
Reply to author
Forward
0 new messages