Sistemas de filas

Após uma contagem de, pelo menos, uma hora em um sistema que apresente fila de espera, preferencialmente com mais de um servidor, o aluno deverá apresentar respostas às perguntas que serão apresentadas a seguir.

Terminologias

  • N = O número de clientes no sistema de filas
  • P_n = Probabilidade de que exatamente n clientes estejam no sistema de fila
  • S = número de servidores no sistema de filas (canais de serviço paralelos)
  • l = taxa média de chegada de clientes (número esperado de chegadas por tempo unitário
  • μ = taxa média de serviço de serviço para todo o sistema (número esperado de clientes concluindo o serviço por unidade de tempo)
  • L = número esperado de clientes no sistema
  • L_q = número esperado de clientes na fila
  • W = Tempo de espera no sistema para cada cliente em particular (inclui tempo de serviço)
  • W_q = Tempo de espera na fila para cada cliente em particular
  • 1/l = tempo esperado entre as chegadas
  • 1/μ = tempo de serviço esperado

In [1]:
from datetime import datetime, timedelta
from IPython.display import display
from math import factorial
from matplotlib import pyplot as plt

import io
import numpy as np
import pandas as pd

Σ = sum

%matplotlib inline

Dados


In [2]:
def timetable(a, b):
    return b + timedelta(minutes=int(a))
    
v_timetable = np.vectorize(timetable)

In [3]:
def sampling_generator(
    size: int=20, initial_datetime: datetime=None
) -> np.array:
    """
    
    """
    if initial_datetime is None:
        initial_datetime = datetime.now()
    
    return v_timetable(
        np.random.randint(0, 60, size=size),
        datetime.now()
    )

In [4]:
def mean_diff_time(se_time: pd.Series) -> float:
    """
    
    """
    n = se_time.shape[0]
    l_diff = [0] * (n-1)
    
    for i in range(1, n):
        j = i-1
        l_diff[j] = (se_time[i] - se_time[j]).seconds/60
    
    return np.mean(l_diff)

In [5]:
initial_datetime = datetime.now()

df_chegada = pd.DataFrame({
    'entrada': sampling_generator(
        initial_datetime=initial_datetime
    )
}).sort_values(by='entrada').reset_index(drop=True)

df_saida = pd.DataFrame({
    'saída': sampling_generator(
        initial_datetime=initial_datetime
    )
}).sort_values(by='saída').reset_index(drop=True)

"""
fig, ax = plt.subplots(1, 2)
df_chegada.hist(ax=ax[0])

df_saida.hist(ax=ax[1])
plt.show()
"""
print('tables head')
display(df_chegada.head())
display(df_saida.head())


tables head
entrada
0 2016-06-09 19:31:14.473402
1 2016-06-09 19:31:14.473402
2 2016-06-09 19:35:14.473402
3 2016-06-09 19:35:14.473402
4 2016-06-09 19:37:14.473402
saída
0 2016-06-09 19:32:14.477273
1 2016-06-09 19:38:14.477273
2 2016-06-09 19:41:14.477273
3 2016-06-09 19:42:14.477273
4 2016-06-09 19:43:14.477273

a) Descrição do sistema de filas, local, data e horários da coleta de dados:

Fila do tipo: FIFO

Local: loja Plazafone

Início da coleta:


In [6]:
initial_datetime.strftime('%d de %b de %Y - %l:%M%p')


Out[6]:
'09 de Jun de 2016 -  7:31PM'

b) Número de servidores atendendo = S:


In [7]:
S = 3
print('S:', S)


S: 3

c) O tempo médio entre as chegadas à fila ( um cliente a cada 5 min, por ex.):


In [8]:
μ_chegada = mean_diff_time(df_chegada['entrada'])
# fixando los valores para teste
μ_chegada = 3.05263157895
print('μ_chegada:', μ_chegada, 'mins')


μ_chegada: 3.05263157895 mins

d) A taxa de chegada de usuários no sistema de filas – λ ( clientes por unidade de tempo):

$\lambda = \frac{60 min}{\mu\_chegada} (clientes/hora)$


In [9]:
λ = 60/μ_chegada
print('λ:', λ)


λ: 19.65517241377616

e) O tempo médio de atendimento de cada cliente ( 20 min, por ex.):


In [10]:
μ_atendimento = mean_diff_time(df_saida['saída'])
# fixando valores para teste
μ_atendimento = 2.84210526316
print('μ_atendimento:', μ_atendimento, 'mins')


μ_atendimento: 2.84210526316 mins

f) A taxa de atendimento dos usuários – μ ( clientes por unidade de tempo, por servidor:

$\mu = \frac{60 min}{\mu\_atendimento} (clientes/hora)$

Se existir mais que um servidor, a taxa de atendimento do sistema será multiplicada pelo número de servidores:


In [11]:
μ = 60/(μ_atendimento*S)
print('μ:', μ, 'clientes/hora')


μ: 7.0370370370318245 clientes/hora

g) A ocupação do sistema(em porcentagem);

$\rho = \frac{\lambda}{S*\mu} * 100 (\%)$


In [12]:
ρ = (λ/(S*μ))*100
print('ρ:', ρ, '%')


ρ: 93.10344827585077 %

h) A probabilidade de o sistema estar vazio:

$$ P_0 = [ \sum\limits_{n=0}^{S-1} (\frac{(\lambda / \mu)^n}{n!}) + \frac{(\lambda/\mu)^S}{S!(1-(\lambda/(S.\mu)))} ]^{-1} $$

In [13]:
P_0 = (
    Σ([(((λ/μ)**n)/(factorial(n))) for n in range(S)]) +
    (((λ/μ)**S)/(factorial(S) * (1-(λ/(S*μ)))))
)**(-1)

print('P_0:', P_0)


P_0: 0.01656906156266322

i) A probabilidade de todos os servidores estarem ocupados:

$ P_{ocupados} = P(n \leq S) = \frac{(\lambda/\mu)^S}{S!(1-\lambda/(S.\mu))}.P_0 $


In [14]:
P_ocupados = (((λ/μ)**S)/(factorial(S)*(1-(λ/(S*μ))))) * P_0
print('P_ocupados:', P_ocupados)


P_ocupados: 0.8725206743862136

k) O número esperado de usuários na fila:

$ L_q = \frac{(\lambda/\mu)^S . \lambda . \mu . S}{S!(\mu . S - \lambda)^2} . P_0 $


In [15]:
L_q = ((((λ/μ)**S)*λ*μ*S)/(factorial(S)*((μ*S-λ)**2)))*P_0
print('L_q:', L_q, 'usuários na fila')


L_q: 11.779029104193159 usuários na fila

j) O número esperado de usuários no sistema:

$ L = L_q + \frac{\lambda}{\mu} $


In [16]:
L = L_q + (λ/μ)
print('L:', L, 'usuários no sistema')


L: 14.572132552468682 usuários no sistema

l) O tempo médio dos usuários na fila:

$ W_q = \frac{L_q}{\lambda} $


In [17]:
W_q = L_q/λ
print('W_q:', W_q, 'horas')


W_q: 0.5992839368805194 horas

m) O tempo provável dos usuários no sistema:

$ W = \frac{L}{\lambda} $


In [18]:
W = L/λ
print('W:', W, 'horas')


W: 0.7413892000385194 horas

n) Se a taxa de chamadas duplicasse, o que aconteceria com o sistema? E quais as providências que deveriam ser tomadas.


In [19]:
p_dobro = ((λ*2)/(S*μ))
print('p_dobro:', p_dobro*100, '%')

if p_dobro < 1:
    print('Ok: o sistema atinge a estabilidade')
else: 
    print('O sistema não atinge a estabilidade')


p_dobro: 186.20689655170153 %
O sistema não atinge a estabilidade

Antes de pensar em aumentar a quantidade de servidores, deve ser feito um estudo para identificar se é possível otimizar o tempo de atendimento que pode estar sendo prejudicado por algum procedimento ineficiente ou por lentidão dos rescursos computacionais ou de falta de habilidade do servidor. Depois de haver otimização dos recursos, caso não for suficiente, deverá ser avaliada a opção de aumentar o número de servidores nos horários críticos ou apresentar uma proposta para facilitar o atendimento, como pré-atendimento online ou alguma facilidade extra em horários de pouco fluxo de entrada de clientes

Teste


In [20]:
# dados de teste providos pelo professor
t_S = 3
t_λ = 19.655  # Clientes/hora
t_μ = 7.037  # Clientes/hora
t_ρ = 0.93  # %
t_P_0 = 0.016570  # 1,657 % - Probabilidade 0 clientes
# Prob S clientes no sistema 0.060176 -> 6,018 %
t_P_ocupados = 0.87251  # 87,251 %
t_L_q = 11.78  # clientes
t_L = 14.57  # clientes - Número médio clientes no sistema
t_W_q = 0.599  # horas - Tempo médio de espera na fila
t_W = 0.741  # horas - Tempo médio de espera sistema

np.testing.assert_approx_equal(S, t_S)
np.testing.assert_approx_equal(λ, t_λ, 3)
np.testing.assert_approx_equal(μ, t_μ, 3)
np.testing.assert_approx_equal(ρ, t_ρ*100, 1)
np.testing.assert_approx_equal(P_0, t_P_0, 3)
np.testing.assert_approx_equal(P_ocupados, t_P_ocupados, 3)
np.testing.assert_approx_equal(L_q, t_L_q, 3)
np.testing.assert_approx_equal(L, t_L, 3)
np.testing.assert_approx_equal(W_q, W_q, 3)
np.testing.assert_approx_equal(W, t_W, 3)