Simmer in R: Modelling changes in server capacity based on queue length and durationcolumn sum based on row lengthStoring Frequency Count of Simulation Function Output in RFilter row names based on string lengthSimmer R package: Modeling 2 Patients Arriving with Constant Inter-Arrival TimeQ: Model a Function based on EquationsChanging length of lines in a legend.wav file length/duration without reading in the fileVariable Lengths Differ Error on Predictive modelExtract change duration in RHow to define starting state of queueing model in r simmer?
What is the most common end of life issue for a car?
Finding minimum time for vehicle to reach to its destination
Did the IBM PC use the 8088's NMI line?
How do campaign rallies gain candidates votes?
Decreasing star size
How to deal with a player who makes bad characters and kills them?
Leaf-Spine network without routing
Does the Intel 8086 CPU have user mode and kernel mode?
Request for a Latin phrase as motto "God is highest/supreme"
Vertical tennis ball into fancy new enumerate
Use cases for M-0 & C-0?
How acidic does a mixture have to be for milk to curdle?
Why is drive/partition number still used?
Does academia have a lazy work culture?
Is it legal to use cash pulled from a credit card to pay the monthly payment on that credit card?
What is this spacecraft tethered to another spacecraft in LEO (vintage)
Why isn't there any 9.5 digit multimeter or higher?
Twelve past eleven at the police station
Does a Rogue's Evasion work for spells?
Converting 8V AC to 8V DC - bridge rectifier gets very hot while idling
How to die in Goat Simulator
Is there a reason why I should not use the HaveIBeenPwned API to warn users about exposed passwords?
Interrupt pin type on the 6502
How to apply the changes to my `.zshrc` file after edit?
Simmer in R: Modelling changes in server capacity based on queue length and duration
column sum based on row lengthStoring Frequency Count of Simulation Function Output in RFilter row names based on string lengthSimmer R package: Modeling 2 Patients Arriving with Constant Inter-Arrival TimeQ: Model a Function based on EquationsChanging length of lines in a legend.wav file length/duration without reading in the fileVariable Lengths Differ Error on Predictive modelExtract change duration in RHow to define starting state of queueing model in r simmer?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
I am attempting to model a system as follows:
Arrivals generate according to a predefined schedule and have known processing times supplied by a dataframe. There is a single server with a capacity equal to min_daemons at the beginning of the simulation. Simple so far, but the nxt part gets tricky: this capacity can vary on the interval [min_daemons , max_daemons] throughout the simulation according to the following algorithm:
If at any time during the simulation, the queue length reaches or exceeds the value of incr_count, and remains at or above this level for incr_delay, then an additional unit of capacity is added to the main server. This can happen at any time, provided that the capacity at no time exceeds max_daemons.
The reverse is also true. If at any time, the queue length is less than decr_count, and remains at or below this level for decr_delay, a unit of capacity is removed, potentially down to a level of min_daemons.
I created a trajectory for all arrivals that branches off when the conditions for changing server capacity above are met. The problem with this is that the changes in capacity are always tied to an arrival event. What I really want is a process independent of the arrival trajectory that monitors the queue length at all times and makes appropriate capacity changes.
I considered alternatively accomplishing this with some sort of dummy arrival process, say at every second of the simulation, but I wasn't sure if I could prevent the dummy arrivals from competing with the true arrivals for server capacity.
#instantiate simulation environment
env <- simmer("queues") %>% add_resource("daemon",1) %>% add_global("incr_start",99999) %>% add_global("decr_start",99999)
run <- trajectory() %>%
branch(option = function() if (get_queue_count(env,"daemon") >= incr_count) 1
else if (get_queue_count(env,"daemon") <= decr_count) 2
else 3
,
continue = c(T, T, T)
,
trajectory("increment?")
%>% branch(option = function() if (now(env) - get_global(env,"incr_start") >= incr_delay
& get_capacity(env,"daemon") < max_daemons) 1
else if (get_global(env,"incr_start")==99999) 2
else 3
,
continue = c(T, T, T)
,
trajectory("increment")
%>% log_(function () paste("Queue size is: ",get_queue_count(env,"daemon")))
%>% log_(function ()
paste("Queue has exceeded count for ",now(env)-get_global(env,"incr_start")," seconds."))
%>% set_capacity(resource = "daemon", value = 1, mod="+")
,
trajectory("update incr start")
%>% set_global("incr_start",now(env))
%>% log_("Queue count is now above increment count. Starting increment timer.")
,
trajectory("do nothing")
%>% log_("Did not meet increment criteria. Doing nothing.")
)
,
trajectory("decrement?")
%>% branch(option = function() if (now(env) - get_global(env,"decr_start") >= decr_delay
& get_capacity(env,"daemon") > min_daemons) 1
else if (get_global(env,"decr_start")==99999) 2
else 3
,
continue = c(T, T, T)
,
trajectory("decrement")
%>% log_(function () paste("Queue size is: ",get_queue_count(env,"daemon")))
%>% log_(function ()
paste("Queue has been less than count for ",now(env)-get_global(env,"incr_start")," seconds."))
%>% set_capacity(resource = "daemon", value = -1, mod="+")
,
trajectory("update decr start")
%>% set_global("decr_start",now(env))
%>% log_("Queue count is now below decrement count. Starting decrement timer.")
,
trajectory("do nothing")
%>% log_("Did not meet decrement criteria. Doing nothing.")
)
,
trajectory("reset_timer")
%>% log_("Did not meet criteria to increment or decrement. Resetting timers.")
%>% set_global("decr_start", values = 99999)
%>% set_global("decr_start", values = 99999)
) %>%
seize("daemon") %>%
log_("Now running") %>%
log_(function () paste(get_queue_count(env,"daemon")," runs in the queue.")) %>%
timeout_from_attribute("service") %>%
release("daemon") %>%
log_("Run complete")
env %>%
add_dataframe("run", run, arr,time="absolute") %>%
run(200)
I need to do some more debugging to verify that the simulation is working as I intended, but I fully understand that this model is wrong. I can hope that the design doesn't compromise it's validity too much, but I also want to get feedback on how I could design something that's truer to real life.
r event-simulation
add a comment |
I am attempting to model a system as follows:
Arrivals generate according to a predefined schedule and have known processing times supplied by a dataframe. There is a single server with a capacity equal to min_daemons at the beginning of the simulation. Simple so far, but the nxt part gets tricky: this capacity can vary on the interval [min_daemons , max_daemons] throughout the simulation according to the following algorithm:
If at any time during the simulation, the queue length reaches or exceeds the value of incr_count, and remains at or above this level for incr_delay, then an additional unit of capacity is added to the main server. This can happen at any time, provided that the capacity at no time exceeds max_daemons.
The reverse is also true. If at any time, the queue length is less than decr_count, and remains at or below this level for decr_delay, a unit of capacity is removed, potentially down to a level of min_daemons.
I created a trajectory for all arrivals that branches off when the conditions for changing server capacity above are met. The problem with this is that the changes in capacity are always tied to an arrival event. What I really want is a process independent of the arrival trajectory that monitors the queue length at all times and makes appropriate capacity changes.
I considered alternatively accomplishing this with some sort of dummy arrival process, say at every second of the simulation, but I wasn't sure if I could prevent the dummy arrivals from competing with the true arrivals for server capacity.
#instantiate simulation environment
env <- simmer("queues") %>% add_resource("daemon",1) %>% add_global("incr_start",99999) %>% add_global("decr_start",99999)
run <- trajectory() %>%
branch(option = function() if (get_queue_count(env,"daemon") >= incr_count) 1
else if (get_queue_count(env,"daemon") <= decr_count) 2
else 3
,
continue = c(T, T, T)
,
trajectory("increment?")
%>% branch(option = function() if (now(env) - get_global(env,"incr_start") >= incr_delay
& get_capacity(env,"daemon") < max_daemons) 1
else if (get_global(env,"incr_start")==99999) 2
else 3
,
continue = c(T, T, T)
,
trajectory("increment")
%>% log_(function () paste("Queue size is: ",get_queue_count(env,"daemon")))
%>% log_(function ()
paste("Queue has exceeded count for ",now(env)-get_global(env,"incr_start")," seconds."))
%>% set_capacity(resource = "daemon", value = 1, mod="+")
,
trajectory("update incr start")
%>% set_global("incr_start",now(env))
%>% log_("Queue count is now above increment count. Starting increment timer.")
,
trajectory("do nothing")
%>% log_("Did not meet increment criteria. Doing nothing.")
)
,
trajectory("decrement?")
%>% branch(option = function() if (now(env) - get_global(env,"decr_start") >= decr_delay
& get_capacity(env,"daemon") > min_daemons) 1
else if (get_global(env,"decr_start")==99999) 2
else 3
,
continue = c(T, T, T)
,
trajectory("decrement")
%>% log_(function () paste("Queue size is: ",get_queue_count(env,"daemon")))
%>% log_(function ()
paste("Queue has been less than count for ",now(env)-get_global(env,"incr_start")," seconds."))
%>% set_capacity(resource = "daemon", value = -1, mod="+")
,
trajectory("update decr start")
%>% set_global("decr_start",now(env))
%>% log_("Queue count is now below decrement count. Starting decrement timer.")
,
trajectory("do nothing")
%>% log_("Did not meet decrement criteria. Doing nothing.")
)
,
trajectory("reset_timer")
%>% log_("Did not meet criteria to increment or decrement. Resetting timers.")
%>% set_global("decr_start", values = 99999)
%>% set_global("decr_start", values = 99999)
) %>%
seize("daemon") %>%
log_("Now running") %>%
log_(function () paste(get_queue_count(env,"daemon")," runs in the queue.")) %>%
timeout_from_attribute("service") %>%
release("daemon") %>%
log_("Run complete")
env %>%
add_dataframe("run", run, arr,time="absolute") %>%
run(200)
I need to do some more debugging to verify that the simulation is working as I intended, but I fully understand that this model is wrong. I can hope that the design doesn't compromise it's validity too much, but I also want to get feedback on how I could design something that's truer to real life.
r event-simulation
1
What is the question? Where is your model going wrong? How do you know it is wrong?
– Corey Levinson
Mar 26 at 19:13
Paragraphs 5 and 6 are the question. My code executes without error, but the model is not correct, and I can't figure out how to implement it correctly with the standard simmer tools. The true system is constantly checking for times when the queue exceeds a range of lengths for a certain amount of time, at which point it adjusts the capacity of the server. My model is only capable of making this adjustment when there is a new arrival.
– Jack Rossi
Mar 26 at 19:55
add a comment |
I am attempting to model a system as follows:
Arrivals generate according to a predefined schedule and have known processing times supplied by a dataframe. There is a single server with a capacity equal to min_daemons at the beginning of the simulation. Simple so far, but the nxt part gets tricky: this capacity can vary on the interval [min_daemons , max_daemons] throughout the simulation according to the following algorithm:
If at any time during the simulation, the queue length reaches or exceeds the value of incr_count, and remains at or above this level for incr_delay, then an additional unit of capacity is added to the main server. This can happen at any time, provided that the capacity at no time exceeds max_daemons.
The reverse is also true. If at any time, the queue length is less than decr_count, and remains at or below this level for decr_delay, a unit of capacity is removed, potentially down to a level of min_daemons.
I created a trajectory for all arrivals that branches off when the conditions for changing server capacity above are met. The problem with this is that the changes in capacity are always tied to an arrival event. What I really want is a process independent of the arrival trajectory that monitors the queue length at all times and makes appropriate capacity changes.
I considered alternatively accomplishing this with some sort of dummy arrival process, say at every second of the simulation, but I wasn't sure if I could prevent the dummy arrivals from competing with the true arrivals for server capacity.
#instantiate simulation environment
env <- simmer("queues") %>% add_resource("daemon",1) %>% add_global("incr_start",99999) %>% add_global("decr_start",99999)
run <- trajectory() %>%
branch(option = function() if (get_queue_count(env,"daemon") >= incr_count) 1
else if (get_queue_count(env,"daemon") <= decr_count) 2
else 3
,
continue = c(T, T, T)
,
trajectory("increment?")
%>% branch(option = function() if (now(env) - get_global(env,"incr_start") >= incr_delay
& get_capacity(env,"daemon") < max_daemons) 1
else if (get_global(env,"incr_start")==99999) 2
else 3
,
continue = c(T, T, T)
,
trajectory("increment")
%>% log_(function () paste("Queue size is: ",get_queue_count(env,"daemon")))
%>% log_(function ()
paste("Queue has exceeded count for ",now(env)-get_global(env,"incr_start")," seconds."))
%>% set_capacity(resource = "daemon", value = 1, mod="+")
,
trajectory("update incr start")
%>% set_global("incr_start",now(env))
%>% log_("Queue count is now above increment count. Starting increment timer.")
,
trajectory("do nothing")
%>% log_("Did not meet increment criteria. Doing nothing.")
)
,
trajectory("decrement?")
%>% branch(option = function() if (now(env) - get_global(env,"decr_start") >= decr_delay
& get_capacity(env,"daemon") > min_daemons) 1
else if (get_global(env,"decr_start")==99999) 2
else 3
,
continue = c(T, T, T)
,
trajectory("decrement")
%>% log_(function () paste("Queue size is: ",get_queue_count(env,"daemon")))
%>% log_(function ()
paste("Queue has been less than count for ",now(env)-get_global(env,"incr_start")," seconds."))
%>% set_capacity(resource = "daemon", value = -1, mod="+")
,
trajectory("update decr start")
%>% set_global("decr_start",now(env))
%>% log_("Queue count is now below decrement count. Starting decrement timer.")
,
trajectory("do nothing")
%>% log_("Did not meet decrement criteria. Doing nothing.")
)
,
trajectory("reset_timer")
%>% log_("Did not meet criteria to increment or decrement. Resetting timers.")
%>% set_global("decr_start", values = 99999)
%>% set_global("decr_start", values = 99999)
) %>%
seize("daemon") %>%
log_("Now running") %>%
log_(function () paste(get_queue_count(env,"daemon")," runs in the queue.")) %>%
timeout_from_attribute("service") %>%
release("daemon") %>%
log_("Run complete")
env %>%
add_dataframe("run", run, arr,time="absolute") %>%
run(200)
I need to do some more debugging to verify that the simulation is working as I intended, but I fully understand that this model is wrong. I can hope that the design doesn't compromise it's validity too much, but I also want to get feedback on how I could design something that's truer to real life.
r event-simulation
I am attempting to model a system as follows:
Arrivals generate according to a predefined schedule and have known processing times supplied by a dataframe. There is a single server with a capacity equal to min_daemons at the beginning of the simulation. Simple so far, but the nxt part gets tricky: this capacity can vary on the interval [min_daemons , max_daemons] throughout the simulation according to the following algorithm:
If at any time during the simulation, the queue length reaches or exceeds the value of incr_count, and remains at or above this level for incr_delay, then an additional unit of capacity is added to the main server. This can happen at any time, provided that the capacity at no time exceeds max_daemons.
The reverse is also true. If at any time, the queue length is less than decr_count, and remains at or below this level for decr_delay, a unit of capacity is removed, potentially down to a level of min_daemons.
I created a trajectory for all arrivals that branches off when the conditions for changing server capacity above are met. The problem with this is that the changes in capacity are always tied to an arrival event. What I really want is a process independent of the arrival trajectory that monitors the queue length at all times and makes appropriate capacity changes.
I considered alternatively accomplishing this with some sort of dummy arrival process, say at every second of the simulation, but I wasn't sure if I could prevent the dummy arrivals from competing with the true arrivals for server capacity.
#instantiate simulation environment
env <- simmer("queues") %>% add_resource("daemon",1) %>% add_global("incr_start",99999) %>% add_global("decr_start",99999)
run <- trajectory() %>%
branch(option = function() if (get_queue_count(env,"daemon") >= incr_count) 1
else if (get_queue_count(env,"daemon") <= decr_count) 2
else 3
,
continue = c(T, T, T)
,
trajectory("increment?")
%>% branch(option = function() if (now(env) - get_global(env,"incr_start") >= incr_delay
& get_capacity(env,"daemon") < max_daemons) 1
else if (get_global(env,"incr_start")==99999) 2
else 3
,
continue = c(T, T, T)
,
trajectory("increment")
%>% log_(function () paste("Queue size is: ",get_queue_count(env,"daemon")))
%>% log_(function ()
paste("Queue has exceeded count for ",now(env)-get_global(env,"incr_start")," seconds."))
%>% set_capacity(resource = "daemon", value = 1, mod="+")
,
trajectory("update incr start")
%>% set_global("incr_start",now(env))
%>% log_("Queue count is now above increment count. Starting increment timer.")
,
trajectory("do nothing")
%>% log_("Did not meet increment criteria. Doing nothing.")
)
,
trajectory("decrement?")
%>% branch(option = function() if (now(env) - get_global(env,"decr_start") >= decr_delay
& get_capacity(env,"daemon") > min_daemons) 1
else if (get_global(env,"decr_start")==99999) 2
else 3
,
continue = c(T, T, T)
,
trajectory("decrement")
%>% log_(function () paste("Queue size is: ",get_queue_count(env,"daemon")))
%>% log_(function ()
paste("Queue has been less than count for ",now(env)-get_global(env,"incr_start")," seconds."))
%>% set_capacity(resource = "daemon", value = -1, mod="+")
,
trajectory("update decr start")
%>% set_global("decr_start",now(env))
%>% log_("Queue count is now below decrement count. Starting decrement timer.")
,
trajectory("do nothing")
%>% log_("Did not meet decrement criteria. Doing nothing.")
)
,
trajectory("reset_timer")
%>% log_("Did not meet criteria to increment or decrement. Resetting timers.")
%>% set_global("decr_start", values = 99999)
%>% set_global("decr_start", values = 99999)
) %>%
seize("daemon") %>%
log_("Now running") %>%
log_(function () paste(get_queue_count(env,"daemon")," runs in the queue.")) %>%
timeout_from_attribute("service") %>%
release("daemon") %>%
log_("Run complete")
env %>%
add_dataframe("run", run, arr,time="absolute") %>%
run(200)
I need to do some more debugging to verify that the simulation is working as I intended, but I fully understand that this model is wrong. I can hope that the design doesn't compromise it's validity too much, but I also want to get feedback on how I could design something that's truer to real life.
r event-simulation
r event-simulation
asked Mar 26 at 18:50
Jack RossiJack Rossi
1
1
1
What is the question? Where is your model going wrong? How do you know it is wrong?
– Corey Levinson
Mar 26 at 19:13
Paragraphs 5 and 6 are the question. My code executes without error, but the model is not correct, and I can't figure out how to implement it correctly with the standard simmer tools. The true system is constantly checking for times when the queue exceeds a range of lengths for a certain amount of time, at which point it adjusts the capacity of the server. My model is only capable of making this adjustment when there is a new arrival.
– Jack Rossi
Mar 26 at 19:55
add a comment |
1
What is the question? Where is your model going wrong? How do you know it is wrong?
– Corey Levinson
Mar 26 at 19:13
Paragraphs 5 and 6 are the question. My code executes without error, but the model is not correct, and I can't figure out how to implement it correctly with the standard simmer tools. The true system is constantly checking for times when the queue exceeds a range of lengths for a certain amount of time, at which point it adjusts the capacity of the server. My model is only capable of making this adjustment when there is a new arrival.
– Jack Rossi
Mar 26 at 19:55
1
1
What is the question? Where is your model going wrong? How do you know it is wrong?
– Corey Levinson
Mar 26 at 19:13
What is the question? Where is your model going wrong? How do you know it is wrong?
– Corey Levinson
Mar 26 at 19:13
Paragraphs 5 and 6 are the question. My code executes without error, but the model is not correct, and I can't figure out how to implement it correctly with the standard simmer tools. The true system is constantly checking for times when the queue exceeds a range of lengths for a certain amount of time, at which point it adjusts the capacity of the server. My model is only capable of making this adjustment when there is a new arrival.
– Jack Rossi
Mar 26 at 19:55
Paragraphs 5 and 6 are the question. My code executes without error, but the model is not correct, and I can't figure out how to implement it correctly with the standard simmer tools. The true system is constantly checking for times when the queue exceeds a range of lengths for a certain amount of time, at which point it adjusts the capacity of the server. My model is only capable of making this adjustment when there is a new arrival.
– Jack Rossi
Mar 26 at 19:55
add a comment |
1 Answer
1
active
oldest
votes
Checking the status at regular intervals defeats the entire purpose of having discrete events. We have here an asynchronous process, so the proper way to model this is by using signals.
We need to ask ourselves: when could the queue...
increase? When an arrival hits the
seize()activity. So before trying to seize the resource, we need to check the number of enqueued arrivals and act accordingly:- If it's equal to
decr_count, a signal must be sent to cancel any attempt to decrease the server's capacity. - If it's equal to
incr_count - 1, a signal must be sent to request an increase of the server's capacity. - Do nothing otherwise.
- If it's equal to
decrease? When an arrival is served (i.e., continues to the next activity following
seize(). So after seizing the resource, we also need to check the number of enqueued arrivals:- If it's equal to
incr_count - 1, a signal must be sent to cancel any attempt to increase the server's capacity. - If it's equal to
decr_count, a signal must be sent to request a decrease of the server's capacity. - Do nothing otherwise.
- If it's equal to
The procedure for checking the number of enqueued arrivals and deciding what kind of signal is needed, if any, can be bundled in a reusable function (let's call it check_queue) as follows:
library(simmer)
env <- simmer()
check_queue <- function(.trj, resource, mod, lim_queue, lim_server)
.trj %>% branch(
function()
if (get_queue_count(env, resource) == lim_queue[1])
return(1)
if (get_queue_count(env, resource) == lim_queue[2] &&
get_capacity(env, resource) != lim_server)
return(2)
0 # pass
,
continue = c(TRUE, TRUE),
trajectory() %>% send(paste("cancel", mod[1])),
trajectory() %>% send(mod[2])
)
main <- trajectory() %>%
check_queue("resource", c("-", "+"), c(decr_count, incr_count-1), max_daemons) %>%
seize("resource") %>%
check_queue("resource", c("+", "-"), c(incr_count-1, decr_count), min_daemons) %>%
timeout_from_attribute("service") %>%
release("resource")
In this way, the main trajectory is quite simple. Then, we need a couple of processes to receive such signals and increase/decrease the capacity after some delay:
change_capacity <- function(resource, mod, delay, limit)
trajectory() %>%
untrap(paste("cancel", mod)) %>%
trap(mod) %>%
wait() %>%
# signal received
untrap(mod) %>%
trap(paste("cancel", mod),
handler = trajectory() %>%
# cancelled! start from the beginning
rollback(Inf)) %>%
timeout(delay) %>%
set_capacity(resource, as.numeric(paste0(mod, 1)), mod="+") %>%
# do we need to keep changing the capacity?
rollback(2, check=function() get_capacity(env, resource) != limit) %>%
# start from the beginning
rollback(Inf)
incr_capacity <- change_capacity("resource", "+", incr_delay, max_daemons)
decr_capacity <- change_capacity("resource", "-", decr_delay, min_daemons)
Finally, we add the resource, our processes and the data to the simulation environment:
env %>%
add_resource("resource", min_daemons) %>%
add_generator("incr", incr_capacity, at(0)) %>%
add_generator("decr", decr_capacity, at(0)) %>%
add_dataframe("arrival", main, data)
Please note that I didn't check this code. It may require some adjustments, but the general idea is there.
Thanks so much for this! I found your explanation to be extremely helpful, and you code to be remarkably functional. The only thing I had to change was the check function in the rollback, so that it again checks that the queue is greater than increment count or less than decrement count.
– Jack Rossi
May 9 at 15:45
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55364348%2fsimmer-in-r-modelling-changes-in-server-capacity-based-on-queue-length-and-dura%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Checking the status at regular intervals defeats the entire purpose of having discrete events. We have here an asynchronous process, so the proper way to model this is by using signals.
We need to ask ourselves: when could the queue...
increase? When an arrival hits the
seize()activity. So before trying to seize the resource, we need to check the number of enqueued arrivals and act accordingly:- If it's equal to
decr_count, a signal must be sent to cancel any attempt to decrease the server's capacity. - If it's equal to
incr_count - 1, a signal must be sent to request an increase of the server's capacity. - Do nothing otherwise.
- If it's equal to
decrease? When an arrival is served (i.e., continues to the next activity following
seize(). So after seizing the resource, we also need to check the number of enqueued arrivals:- If it's equal to
incr_count - 1, a signal must be sent to cancel any attempt to increase the server's capacity. - If it's equal to
decr_count, a signal must be sent to request a decrease of the server's capacity. - Do nothing otherwise.
- If it's equal to
The procedure for checking the number of enqueued arrivals and deciding what kind of signal is needed, if any, can be bundled in a reusable function (let's call it check_queue) as follows:
library(simmer)
env <- simmer()
check_queue <- function(.trj, resource, mod, lim_queue, lim_server)
.trj %>% branch(
function()
if (get_queue_count(env, resource) == lim_queue[1])
return(1)
if (get_queue_count(env, resource) == lim_queue[2] &&
get_capacity(env, resource) != lim_server)
return(2)
0 # pass
,
continue = c(TRUE, TRUE),
trajectory() %>% send(paste("cancel", mod[1])),
trajectory() %>% send(mod[2])
)
main <- trajectory() %>%
check_queue("resource", c("-", "+"), c(decr_count, incr_count-1), max_daemons) %>%
seize("resource") %>%
check_queue("resource", c("+", "-"), c(incr_count-1, decr_count), min_daemons) %>%
timeout_from_attribute("service") %>%
release("resource")
In this way, the main trajectory is quite simple. Then, we need a couple of processes to receive such signals and increase/decrease the capacity after some delay:
change_capacity <- function(resource, mod, delay, limit)
trajectory() %>%
untrap(paste("cancel", mod)) %>%
trap(mod) %>%
wait() %>%
# signal received
untrap(mod) %>%
trap(paste("cancel", mod),
handler = trajectory() %>%
# cancelled! start from the beginning
rollback(Inf)) %>%
timeout(delay) %>%
set_capacity(resource, as.numeric(paste0(mod, 1)), mod="+") %>%
# do we need to keep changing the capacity?
rollback(2, check=function() get_capacity(env, resource) != limit) %>%
# start from the beginning
rollback(Inf)
incr_capacity <- change_capacity("resource", "+", incr_delay, max_daemons)
decr_capacity <- change_capacity("resource", "-", decr_delay, min_daemons)
Finally, we add the resource, our processes and the data to the simulation environment:
env %>%
add_resource("resource", min_daemons) %>%
add_generator("incr", incr_capacity, at(0)) %>%
add_generator("decr", decr_capacity, at(0)) %>%
add_dataframe("arrival", main, data)
Please note that I didn't check this code. It may require some adjustments, but the general idea is there.
Thanks so much for this! I found your explanation to be extremely helpful, and you code to be remarkably functional. The only thing I had to change was the check function in the rollback, so that it again checks that the queue is greater than increment count or less than decrement count.
– Jack Rossi
May 9 at 15:45
add a comment |
Checking the status at regular intervals defeats the entire purpose of having discrete events. We have here an asynchronous process, so the proper way to model this is by using signals.
We need to ask ourselves: when could the queue...
increase? When an arrival hits the
seize()activity. So before trying to seize the resource, we need to check the number of enqueued arrivals and act accordingly:- If it's equal to
decr_count, a signal must be sent to cancel any attempt to decrease the server's capacity. - If it's equal to
incr_count - 1, a signal must be sent to request an increase of the server's capacity. - Do nothing otherwise.
- If it's equal to
decrease? When an arrival is served (i.e., continues to the next activity following
seize(). So after seizing the resource, we also need to check the number of enqueued arrivals:- If it's equal to
incr_count - 1, a signal must be sent to cancel any attempt to increase the server's capacity. - If it's equal to
decr_count, a signal must be sent to request a decrease of the server's capacity. - Do nothing otherwise.
- If it's equal to
The procedure for checking the number of enqueued arrivals and deciding what kind of signal is needed, if any, can be bundled in a reusable function (let's call it check_queue) as follows:
library(simmer)
env <- simmer()
check_queue <- function(.trj, resource, mod, lim_queue, lim_server)
.trj %>% branch(
function()
if (get_queue_count(env, resource) == lim_queue[1])
return(1)
if (get_queue_count(env, resource) == lim_queue[2] &&
get_capacity(env, resource) != lim_server)
return(2)
0 # pass
,
continue = c(TRUE, TRUE),
trajectory() %>% send(paste("cancel", mod[1])),
trajectory() %>% send(mod[2])
)
main <- trajectory() %>%
check_queue("resource", c("-", "+"), c(decr_count, incr_count-1), max_daemons) %>%
seize("resource") %>%
check_queue("resource", c("+", "-"), c(incr_count-1, decr_count), min_daemons) %>%
timeout_from_attribute("service") %>%
release("resource")
In this way, the main trajectory is quite simple. Then, we need a couple of processes to receive such signals and increase/decrease the capacity after some delay:
change_capacity <- function(resource, mod, delay, limit)
trajectory() %>%
untrap(paste("cancel", mod)) %>%
trap(mod) %>%
wait() %>%
# signal received
untrap(mod) %>%
trap(paste("cancel", mod),
handler = trajectory() %>%
# cancelled! start from the beginning
rollback(Inf)) %>%
timeout(delay) %>%
set_capacity(resource, as.numeric(paste0(mod, 1)), mod="+") %>%
# do we need to keep changing the capacity?
rollback(2, check=function() get_capacity(env, resource) != limit) %>%
# start from the beginning
rollback(Inf)
incr_capacity <- change_capacity("resource", "+", incr_delay, max_daemons)
decr_capacity <- change_capacity("resource", "-", decr_delay, min_daemons)
Finally, we add the resource, our processes and the data to the simulation environment:
env %>%
add_resource("resource", min_daemons) %>%
add_generator("incr", incr_capacity, at(0)) %>%
add_generator("decr", decr_capacity, at(0)) %>%
add_dataframe("arrival", main, data)
Please note that I didn't check this code. It may require some adjustments, but the general idea is there.
Thanks so much for this! I found your explanation to be extremely helpful, and you code to be remarkably functional. The only thing I had to change was the check function in the rollback, so that it again checks that the queue is greater than increment count or less than decrement count.
– Jack Rossi
May 9 at 15:45
add a comment |
Checking the status at regular intervals defeats the entire purpose of having discrete events. We have here an asynchronous process, so the proper way to model this is by using signals.
We need to ask ourselves: when could the queue...
increase? When an arrival hits the
seize()activity. So before trying to seize the resource, we need to check the number of enqueued arrivals and act accordingly:- If it's equal to
decr_count, a signal must be sent to cancel any attempt to decrease the server's capacity. - If it's equal to
incr_count - 1, a signal must be sent to request an increase of the server's capacity. - Do nothing otherwise.
- If it's equal to
decrease? When an arrival is served (i.e., continues to the next activity following
seize(). So after seizing the resource, we also need to check the number of enqueued arrivals:- If it's equal to
incr_count - 1, a signal must be sent to cancel any attempt to increase the server's capacity. - If it's equal to
decr_count, a signal must be sent to request a decrease of the server's capacity. - Do nothing otherwise.
- If it's equal to
The procedure for checking the number of enqueued arrivals and deciding what kind of signal is needed, if any, can be bundled in a reusable function (let's call it check_queue) as follows:
library(simmer)
env <- simmer()
check_queue <- function(.trj, resource, mod, lim_queue, lim_server)
.trj %>% branch(
function()
if (get_queue_count(env, resource) == lim_queue[1])
return(1)
if (get_queue_count(env, resource) == lim_queue[2] &&
get_capacity(env, resource) != lim_server)
return(2)
0 # pass
,
continue = c(TRUE, TRUE),
trajectory() %>% send(paste("cancel", mod[1])),
trajectory() %>% send(mod[2])
)
main <- trajectory() %>%
check_queue("resource", c("-", "+"), c(decr_count, incr_count-1), max_daemons) %>%
seize("resource") %>%
check_queue("resource", c("+", "-"), c(incr_count-1, decr_count), min_daemons) %>%
timeout_from_attribute("service") %>%
release("resource")
In this way, the main trajectory is quite simple. Then, we need a couple of processes to receive such signals and increase/decrease the capacity after some delay:
change_capacity <- function(resource, mod, delay, limit)
trajectory() %>%
untrap(paste("cancel", mod)) %>%
trap(mod) %>%
wait() %>%
# signal received
untrap(mod) %>%
trap(paste("cancel", mod),
handler = trajectory() %>%
# cancelled! start from the beginning
rollback(Inf)) %>%
timeout(delay) %>%
set_capacity(resource, as.numeric(paste0(mod, 1)), mod="+") %>%
# do we need to keep changing the capacity?
rollback(2, check=function() get_capacity(env, resource) != limit) %>%
# start from the beginning
rollback(Inf)
incr_capacity <- change_capacity("resource", "+", incr_delay, max_daemons)
decr_capacity <- change_capacity("resource", "-", decr_delay, min_daemons)
Finally, we add the resource, our processes and the data to the simulation environment:
env %>%
add_resource("resource", min_daemons) %>%
add_generator("incr", incr_capacity, at(0)) %>%
add_generator("decr", decr_capacity, at(0)) %>%
add_dataframe("arrival", main, data)
Please note that I didn't check this code. It may require some adjustments, but the general idea is there.
Checking the status at regular intervals defeats the entire purpose of having discrete events. We have here an asynchronous process, so the proper way to model this is by using signals.
We need to ask ourselves: when could the queue...
increase? When an arrival hits the
seize()activity. So before trying to seize the resource, we need to check the number of enqueued arrivals and act accordingly:- If it's equal to
decr_count, a signal must be sent to cancel any attempt to decrease the server's capacity. - If it's equal to
incr_count - 1, a signal must be sent to request an increase of the server's capacity. - Do nothing otherwise.
- If it's equal to
decrease? When an arrival is served (i.e., continues to the next activity following
seize(). So after seizing the resource, we also need to check the number of enqueued arrivals:- If it's equal to
incr_count - 1, a signal must be sent to cancel any attempt to increase the server's capacity. - If it's equal to
decr_count, a signal must be sent to request a decrease of the server's capacity. - Do nothing otherwise.
- If it's equal to
The procedure for checking the number of enqueued arrivals and deciding what kind of signal is needed, if any, can be bundled in a reusable function (let's call it check_queue) as follows:
library(simmer)
env <- simmer()
check_queue <- function(.trj, resource, mod, lim_queue, lim_server)
.trj %>% branch(
function()
if (get_queue_count(env, resource) == lim_queue[1])
return(1)
if (get_queue_count(env, resource) == lim_queue[2] &&
get_capacity(env, resource) != lim_server)
return(2)
0 # pass
,
continue = c(TRUE, TRUE),
trajectory() %>% send(paste("cancel", mod[1])),
trajectory() %>% send(mod[2])
)
main <- trajectory() %>%
check_queue("resource", c("-", "+"), c(decr_count, incr_count-1), max_daemons) %>%
seize("resource") %>%
check_queue("resource", c("+", "-"), c(incr_count-1, decr_count), min_daemons) %>%
timeout_from_attribute("service") %>%
release("resource")
In this way, the main trajectory is quite simple. Then, we need a couple of processes to receive such signals and increase/decrease the capacity after some delay:
change_capacity <- function(resource, mod, delay, limit)
trajectory() %>%
untrap(paste("cancel", mod)) %>%
trap(mod) %>%
wait() %>%
# signal received
untrap(mod) %>%
trap(paste("cancel", mod),
handler = trajectory() %>%
# cancelled! start from the beginning
rollback(Inf)) %>%
timeout(delay) %>%
set_capacity(resource, as.numeric(paste0(mod, 1)), mod="+") %>%
# do we need to keep changing the capacity?
rollback(2, check=function() get_capacity(env, resource) != limit) %>%
# start from the beginning
rollback(Inf)
incr_capacity <- change_capacity("resource", "+", incr_delay, max_daemons)
decr_capacity <- change_capacity("resource", "-", decr_delay, min_daemons)
Finally, we add the resource, our processes and the data to the simulation environment:
env %>%
add_resource("resource", min_daemons) %>%
add_generator("incr", incr_capacity, at(0)) %>%
add_generator("decr", decr_capacity, at(0)) %>%
add_dataframe("arrival", main, data)
Please note that I didn't check this code. It may require some adjustments, but the general idea is there.
answered Mar 27 at 18:34
Iñaki ÚcarIñaki Úcar
2932 silver badges9 bronze badges
2932 silver badges9 bronze badges
Thanks so much for this! I found your explanation to be extremely helpful, and you code to be remarkably functional. The only thing I had to change was the check function in the rollback, so that it again checks that the queue is greater than increment count or less than decrement count.
– Jack Rossi
May 9 at 15:45
add a comment |
Thanks so much for this! I found your explanation to be extremely helpful, and you code to be remarkably functional. The only thing I had to change was the check function in the rollback, so that it again checks that the queue is greater than increment count or less than decrement count.
– Jack Rossi
May 9 at 15:45
Thanks so much for this! I found your explanation to be extremely helpful, and you code to be remarkably functional. The only thing I had to change was the check function in the rollback, so that it again checks that the queue is greater than increment count or less than decrement count.
– Jack Rossi
May 9 at 15:45
Thanks so much for this! I found your explanation to be extremely helpful, and you code to be remarkably functional. The only thing I had to change was the check function in the rollback, so that it again checks that the queue is greater than increment count or less than decrement count.
– Jack Rossi
May 9 at 15:45
add a comment |
Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.
Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55364348%2fsimmer-in-r-modelling-changes-in-server-capacity-based-on-queue-length-and-dura%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
What is the question? Where is your model going wrong? How do you know it is wrong?
– Corey Levinson
Mar 26 at 19:13
Paragraphs 5 and 6 are the question. My code executes without error, but the model is not correct, and I can't figure out how to implement it correctly with the standard simmer tools. The true system is constantly checking for times when the queue exceeds a range of lengths for a certain amount of time, at which point it adjusts the capacity of the server. My model is only capable of making this adjustment when there is a new arrival.
– Jack Rossi
Mar 26 at 19:55