Para resolver este problema se desarrollaron varias funciones:
Funciones de la forma MMk_queue.R. Estas funciones reciben como parametro el dia de la semana, y en base a la distribucion de llegadas para los 7 dias de la semana, generan un dataframe por dia (8 hrs = 480 minutos). Se desarrollaron 7 funciones, una para tipo de cola: MM1_queue.R , MM2_queue.R, MM3_queue.R, MM4_queue.R , MM5_queue.R, MM6_queue.R y MM7_queue.R.
Luego se desarrollo script que barre por los 7 dias de la semana y hace esto por 52 semanas (1 año). Es decir se genera un dataframe de un año por cada una de las 7 configuraciones de cola.
La funcion queue_performance.R, recibe el dataframe correspondiente a un año para cada cola (MMk_queue.R) y calcula los parametros de rendimiento de la cola.
Estas funciones reciben como parametro el dia de la semana, que va de 1 a 7 (1 = Lunes, 2 = Martes,…, 7 = Domingo) y devuelven un dataframe de duracion 480 minutos y que toma en cuenta el numero de servidores: 1,2,3,4,5,6 o 7.
Su funcionamiento es el siguiente:
Se generan los tiempos de llegada de acuerdo al dia. El limite maximo de arribos es de hasta 480 minutos ya que el banco trabaja 8 hrs. (10:00 a 18:00 hrs).
Los primeros k clientes entran directo al servicio, es decir no hacen cola ya que hay k servidores disponibles.
A partir del cliente k+1 hay que revisar que servidor esta disponible. Si el tiempo de llegada del siguiente cliente es mayor que el tiempo de liberacion de cualquiera de los k servidores, el usuario entra directo a servicio.
Si el tiempo de llegada del siguiente cliente es menor que el tiempo de desocupacion de cualquiera de los k servidores, el cliente espera hasta que cualquier servidor se desocupe. El primer servidor desocupado es el que da el servicio. Esto se verifica con la funcion min().
Un ejemplo de esta funcion para k = 3 (3 servidores) se muestra a continuacion:
MM3_queue <- function(dia=1) {
# Synopsis: Funcion que simula una cola de k servidores. Se recibe como parametro el dia
# de la semana y en base a esto se calcula la distribucion de llegada. La funcion devuelve
# un dataframe de 480 minutos (8 hrs.)
# Initialize
if (dia==1) p <- c(0.1,0.15,0.1,0.35,0.25,0.05,0)
if (dia==2) p <- c(0.1,0.1,0.15,0.2,0.35,0.1,0)
if (dia==3) p <- c(0,0.1,0.1,0.2,0.1,0.25,0.25)
if (dia==4) p <- c(0,0.15,0.2,0.2,0.15,0.15,0.15)
if (dia==5) p <- c(0.15,0.15,0.2,0.2,0.1,0.1,0.1)
if (dia==6) p <- c(0.2,0.15,0.1,0.5,0.05,0,0)
if (dia==7) p <- c(0.35,0.25,0.2,0.1,0.1,0,0)
inter_times <- c(0,1,2,3,4,5,6)
arrival_times <- 0
interarrival_times <- 0
k <- 3
# Interarrival times. Se calcula el numero N de clientes que llegan a la cola
# de acuerdo a la probabilidad de llegada.
arrival_times[1] <- sample(inter_times,1,replace = T,prob = p)
N <- 1
while (arrival_times[N] < 480) {
N <- N + 1
interarrival_times[N] <- sample(inter_times,1,replace = T,prob = p)
arrival_times[N] <- arrival_times[N-1] + interarrival_times[N]
}
# Service times
service_times <- ceiling(abs(rnorm(N,mean=8,sd=5)))
# vectors to track service time and departure
enter_service_times <- rep(0,N)
completion_times <- rep(0,N)
idle_time_server <- rep(0,N)
server_time <- rep(0,k)
# first k customers. Para k=3 , los primeros tres clientes no hacen cola.
for (j in 1:k) {
enter_service_times[j] <- arrival_times[j]
completion_times[j] <- enter_service_times[j]+service_times[j]
server_time[j] <- completion_times[j]
}
# Loop through the remaining customers. Esta parte calcula la cola. Basicamente se revisa
# el servidor que este disponible con la funcion min(x,y) y ese se asigna para el siguiente
# cliente en cola
for (i in seq(from=(k+1), to=N, by=1)) {
# En esta parte se revisa si cuando el siguiente cliente llega hay algun servidor
# disponible
if (arrival_times[i] >= server_time[1]) {
enter_service_times[i] <- arrival_times[i]
completion_times[i] <- enter_service_times[i]+service_times[i]
server_time[1] <- completion_times[i]
} else if (arrival_times[i] >= server_time[2]) {
enter_service_times[i] <- arrival_times[i]
completion_times[i] <- enter_service_times[i]+service_times[i]
server_time[2] <- completion_times[i]
} else if (arrival_times[i] >= server_time[3]) {
enter_service_times[i] <- arrival_times[i]
completion_times[i] <- enter_service_times[i]+service_times[i]
server_time[3] <- completion_times[i]
# Si el siguiente cliente en cola, encuentra los servidores ocupados, esta parte
# revisa cual de los tres servidores esta libre antes. Esto se revisa via la funcion
# min(x,y,z)
} else if (server_time[1] == min(server_time)) {
enter_service_times[i] <- server_time[1]
completion_times[i] <- enter_service_times[i]+service_times[i]
server_time[1] <- completion_times[i]
} else if (server_time[2] == min(server_time)) {
enter_service_times[i] <- server_time[2]
completion_times[i] <- enter_service_times[i]+service_times[i]
server_time[2] <- completion_times[i]
} else if (server_time[3] == min(server_time)) {
enter_service_times[i] <- server_time[3]
completion_times[i] <- enter_service_times[i]+service_times[i]
server_time[3] <- completion_times[i]
}
}
waiting_time_q <- enter_service_times - arrival_times
total_time <- completion_times - arrival_times
df <- data.frame(entre_llegadas=interarrival_times,llegadas=arrival_times,tiempo_servicio=service_times,inicio_servicio=enter_service_times,finalizacion=completion_times)
return(df)
}
El resultado de la funcion es:
head(MM3_queue(),10)
## entre_llegadas llegadas tiempo_servicio inicio_servicio finalizacion
## 1 0 4 13 4 17
## 2 3 7 2 7 9
## 3 2 9 15 9 24
## 4 4 13 2 13 15
## 5 4 17 11 17 28
## 6 4 21 7 21 28
## 7 3 24 7 24 31
## 8 0 24 6 28 34
## 9 5 29 2 29 31
## 10 1 30 2 31 33
El tamaño promedio puede ser por hora, por dia o por semana. Debido a que los 7 dias tienen distribuciones distintas vamos a calcular el tamaño promedio de la cola para 1 semana (7 dias), para cada uno de las 7 colas. Para esto vamos a generar un dataframe de los 7 dias, para cada una de las colas, desde 1 servidor a 7, por 52 semanas (1 año). Esto es equivalente a simular cada semana durante un año:
y2 <- 0
for (k in 1:52) {
x <- 0
for (i in 1:7) {
x <- MM2_queue(i)
y2 <- rbind(y2,x)
}
}
y3 <- 0
for (k in 1:52) {
x <- 0
for (i in 1:7){
x <- MM3_queue(i)
y3 <- rbind(y3,x)
}
}
y4 <- 0
for (k in 1:52) {
x <- 0
for (i in 1:7) {
x <- MM4_queue(i)
y4 <- rbind(y4,x)
}
}
y5 <- 0
for (k in 1:52) {
x <- 0
for (i in 1:7) {
x <- MM5_queue(i)
y5 <- rbind(y5,x)
}
}
y6 <- 0
for (k in 1:52) {
x <- 0
for (i in 1:7) {
x <- MM6_queue(i)
y6 <- rbind(y6,x)
}
}
y7 <- 0
for (k in 1:52) {
x <- 0
for (i in 1:7) {
x <- MM7_queue(i)
y7 <- rbind(y7,x)
}
}
Y ahora con la funcion queue_performance.R, calculamos los parametros de cada cola:
queue_performance(y2)
## promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1 247.7809 0.9793744 8.720529 256.5014
## promedio_llegada clientes_en_cola
## 1 2.428703 70228
queue_performance(y3)
## promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1 98.17752 0.8342312 8.702596 106.8801
## promedio_llegada clientes_en_cola
## 1 2.425851 59927
queue_performance(y4)
## promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1 41.77052 0.5637223 8.735122 50.50564
## promedio_llegada clientes_en_cola
## 1 2.436613 40296
queue_performance(y5)
## promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1 20.24168 0.374932 8.766396 29.00808
## promedio_llegada clientes_en_cola
## 1 2.429887 26874
queue_performance(y6)
## promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1 7.590505 0.2839698 8.717028 16.30753
## promedio_llegada clientes_en_cola
## 1 2.415205 20487
queue_performance(y7)
## promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1 1.308965 0.1800293 8.724897 10.03386
## promedio_llegada clientes_en_cola
## 1 2.433974 12882
El parametro prob_cola mide la probabilidad de hacer cola y el parametro clientes_en_cola mide el numero de clientes en promedio que hacen cola:
Por ejemplo, si el banco tiene 3 cajeros, el 83% de sus clientes hacen cola o el equivalente a 165 clientes por dia.º
Nuevamente vemos los parametros de rendimiento de cada cola. Debido a que las colas de 2,3 y 4 servidores tienen tiempos promedio de espera grandes, volvemos a calcular solo para colas de 5,6 y 7 servidores:
queue_performance(y5)
## promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1 20.24168 0.374932 8.766396 29.00808
## promedio_llegada clientes_en_cola
## 1 2.429887 26874
queue_performance(y6)
## promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1 7.590505 0.2839698 8.717028 16.30753
## promedio_llegada clientes_en_cola
## 1 2.415205 20487
queue_performance(y7)
## promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1 1.308965 0.1800293 8.724897 10.03386
## promedio_llegada clientes_en_cola
## 1 2.433974 12882
Vemos que con 5 agentes o cajeros, el tiempo promedio de espera esta arriba de los 15 mins. Por lo tanto si el banco no quiere que un cliente este mas de 15 mins, debe tener al menos 6 agentes.
Aqui nos piden calcular el tamaño de la cola. Es decir, en un momento en particular ¿cuantos clientes estan esperando entrar a servicio?. Si este numero supera 10, el resto son rechazados. Para resolver esto la logica es la siguiente:
A partir de un dataframe, se genera otro dataframe con el listado de clientes que hicieron cola. Esto se hace para cada cola: MM2, MM3,…,MM7.
Debido a que el tamaño de la cola se mide en base a la diferencia entre el inicio de servicio (cuando un cliente pasa con cajero) y la llegada del cliente, se cuenta el numero de clientes que esperan en cola antes de que el primero que hizo cola inicie el servicio.
Se genera un vector con los tamaños de la cola, antes que el primer cliente reciba servicio.
La funcion queue_mean_length.R , calcula el tamaño promedio de la cola que excede 10, es decir devuelve el promedio de clientes que fueron rechazados ya que el banco solo permite, en un momento dado tener 10.
La funcion es la siguiente:
queue_mean_length <- function(d=MM2_queue()) {
count <- rep(0,1000)
for (k in 1:1000) {
# d <- MM2_queue()
z <- which(d$inicio_servicio -d$llegadas !=0)
d <- d[z,] # Dataframe solo de los que hicieron cola
a <- rep(1000000,5)
d <- rbind(d,a)
i <- 1
j <- 0
c <- rep(0,50)
while (i < (length(d$llegadas)-5)) {
j <- j + 1
flag <- 0
minimo <- d$inicio_servicio[i]
while (flag == 0) {
if (d$llegadas[i+1] < minimo) {
c[j] <- c[j] + 1
i <- i + 1
flag <- 0
}
if (d$llegadas[i+1] >= minimo) {
c[j] <- c[j] + 1
i <- i +1
flag <- 1
}
}
}
c <- c[-which(c==0)]
c <- c[which(c-10>0)]
count[k] <- sum(c)
}
return(mean(count))
}
Para las diferentes configuraciones de servidores tenemos:
queue_mean_length(MM2_queue())
## [1] 159
queue_mean_length(MM3_queue())
## [1] 152
queue_mean_length(MM4_queue())
## [1] 0
queue_mean_length(MM5_queue())
## [1] 0
queue_mean_length(MM6_queue())
## [1] 0
queue_mean_length(MM7_queue())
## [1] 0
Esto representa el promedio de clientes rechazados, cuando la cola en el banco ya esta en 10. Para las colas de 6 y 7 podemos ver que no hay clientes rechazados cuando se supera 10, debido a que muy seguramente la cola nunca llega a 10.
La funcion queue_performance.R se muestra acontinuacion. Esta funcion calcula, para un dataframe de una cola en particular, todos los paramentros de rendimiento de la cola.
queue_performance <- function(x=MM2_queue()) {
# Synopsis: Recibe un dataframe de una cola de k servidores y calcula los parametros de rendimiento
# de la cola.
# Initialize
c <- 0
# Queue for N clients: Cola de N clientes
N <- length(x$llegadas)
idle_time_server <- rep(0,N) # Vector de tiempo desocupado
waiting_time_q <- x$inicio_servicio-x$llegadas # tiempo de espera en la cola
total_time <- x$finalizacion-x$llegadas # tiempo total en el sistema
service_times <- x$finalizacion-x$inicio_servicio # tiempo de servicio
interarrival_times <- x$entre_llegadas # tiempo entre llegadas de clientes
arrival_times <- x$llegadas # llegadas de los clientes
completion_times <- x$finalizacion # Finalizacion del servicio
enter_service_times <- x$inicio_servicio # Inicio del servicio
# Performance Calculations
w_bar <- mean(waiting_time_q) # tiempo promedio de espera en la cola
t_bar <- mean (total_time) # tiempo promedio en el sistema
s_bar <- mean(service_times) # tiempro promedio de servicio
i_bar <- mean(interarrival_times) # tiempo promedio de llegada
# Calculo de las personas que hacen cola.
for (k in 1:N) {
if (arrival_times[k] == enter_service_times[k]) {c <- c + 1}
}
prob_queue <- 1- (c/N)
P_queue <- round(N*prob_queue, digits = 0) # Promedio de personas que hacen cola
df2 <- data.frame(promedio_espera=w_bar,prob_cola=prob_queue,promedio_servicio=s_bar,promedio_en_sis=t_bar,promedio_llegada=i_bar,clientes_en_cola=P_queue)
return(df2)
}