|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +""" |
| 3 | +Created on Sat Sep 12 14:00:13 2020 |
| 4 | +
|
| 5 | +@author: Miguel Rizzo |
| 6 | +""" |
| 7 | + |
| 8 | +##single server |
| 9 | + |
| 10 | +#Importing Libraries |
| 11 | +import pandas as pd ,seaborn as sns, numpy as np ,matplotlib.pyplot as plt |
| 12 | +import warnings |
| 13 | +warnings.filterwarnings('ignore') |
| 14 | +# set seed for reproducibility |
| 15 | +np.random.seed(0) |
| 16 | + |
| 17 | +#Single server, single queue simulation |
| 18 | +l = 1 # average number of arrivals per minute |
| 19 | +µ =1.5 # average number of people served per minute |
| 20 | +ncust =1000# number of customers |
| 21 | +c=1 # number of servers |
| 22 | +utilization={} |
| 23 | +service_times = [] # list of service times once they reach the front |
| 24 | + |
| 25 | + #generating inter arrival times using exponential distribution |
| 26 | +while c<=5: |
| 27 | + if c==1: |
| 28 | + inter_arrival_times = list(np.random.exponential(scale=1/l,size=ncust)) |
| 29 | + |
| 30 | + arrival_times= []# list of arrival times of a person joining the queue |
| 31 | + finish_times = [] # list of finish times after waiting and being served |
| 32 | + |
| 33 | + arrival_times = [0 for i in range(ncust)] |
| 34 | + finish_times = [0 for i in range(ncust)] |
| 35 | + |
| 36 | + arrival_times[0]=round(inter_arrival_times[0],4)#arrival of first customer |
| 37 | + |
| 38 | + #Generate arrival times |
| 39 | + |
| 40 | + for i in range(1,ncust): |
| 41 | + arrival_times[i]=round((arrival_times[i-1]+inter_arrival_times[i]),4) |
| 42 | + |
| 43 | + |
| 44 | + # Generate random service times for each customer |
| 45 | + if c==1: |
| 46 | + service_times = list(np.random.exponential(scale=1/µ,size=ncust)) |
| 47 | + |
| 48 | + |
| 49 | + #Generate finish times |
| 50 | + finish_times[0]= round((arrival_times[0]+service_times[0]),4) |
| 51 | + for i in range(1,ncust): |
| 52 | + previous_finish=finish_times[:i] |
| 53 | + previous_finish.sort(reverse=True) |
| 54 | + previous_finish=previous_finish[:c] |
| 55 | + if i< c: |
| 56 | + finish_times[i] = round(arrival_times[i] + service_times[i],4) |
| 57 | + else: |
| 58 | + finish_times[i]=round((max(arrival_times[i],min(previous_finish))+service_times[i]),4) |
| 59 | + |
| 60 | + |
| 61 | + # Total time spent in the system by each customer |
| 62 | + total_times =[abs(round((finish_times[i]-arrival_times[i]),4)) for i in range(ncust)] |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | + # Time spent@waiting before being served (time spent in the queue) |
| 67 | + wait_times = [abs(round((total_times[i] - service_times[i]),4)) for i in range(ncust)] |
| 68 | + |
| 69 | + |
| 70 | + #creating a dataframe with all the data of the model |
| 71 | + data = pd.DataFrame(list(zip(arrival_times,finish_times,service_times,total_times,wait_times,inter_arrival_times)), |
| 72 | + columns =['arrival_times','finish_times', 'service_times','total_times','wait_times','inter_arrival_times']) |
| 73 | + |
| 74 | + #generating the timeline , and their description (arrivals, departures) |
| 75 | + |
| 76 | + tbe=list([0]) |
| 77 | + timeline=['simulation starts'] |
| 78 | + for i in range(0,ncust): |
| 79 | + tbe.append(data['arrival_times'][i]) |
| 80 | + tbe.append(data['finish_times'][i]) |
| 81 | + timeline.append('customer ' +str(i+1)+' arrived') |
| 82 | + timeline.append('customer ' +str(i+1)+' left') |
| 83 | + |
| 84 | + |
| 85 | + #generating a dataframe with the timeline and description of events |
| 86 | + |
| 87 | + timeline = pd.DataFrame(list(zip(tbe,timeline)), |
| 88 | + columns =['time','Timeline']).sort_values(by='time').reset_index() |
| 89 | + timeline=timeline.drop(columns='index') |
| 90 | + |
| 91 | + #generating the number of customers inside the system at any given time of the simulation |
| 92 | + # and recording idle and working times |
| 93 | + |
| 94 | + timeline['n']=0 |
| 95 | + x=0 |
| 96 | + for i in range(1,(2*ncust)-1): |
| 97 | + if len(((timeline.Timeline[i]).split()))>2: |
| 98 | + z=str(timeline['Timeline'][i]).split()[2] |
| 99 | + else: |
| 100 | + continue |
| 101 | + if z =='arrived': |
| 102 | + x = x+1 |
| 103 | + timeline['n'][i]=x |
| 104 | + else: |
| 105 | + x=x-1 |
| 106 | + if x==-1: |
| 107 | + x=0 |
| 108 | + timeline['n'][i]=x |
| 109 | + |
| 110 | + |
| 111 | + |
| 112 | + #computing time between events |
| 113 | + t= list() |
| 114 | + for i in timeline.index: |
| 115 | + if i == (2*ncust) -2 : |
| 116 | + continue |
| 117 | + if i < 2*ncust: |
| 118 | + x=timeline.time[i+1] |
| 119 | + else: |
| 120 | + x=timeline.time[i] |
| 121 | + y=timeline.time[i] |
| 122 | + t.append(round((x-y),4)) |
| 123 | + |
| 124 | + t.append(0) |
| 125 | + timeline['tbe']=t |
| 126 | + |
| 127 | + #computing the probability of 'n' customers being in the system |
| 128 | + |
| 129 | + Pn=timeline.groupby('n').tbe.agg(sum)/sum(t) |
| 130 | + Tn=timeline.groupby('n').tbe.agg('count') |
| 131 | + |
| 132 | + |
| 133 | + #checking central tendency measures and dispersion of the data |
| 134 | + timeline.n.describe() |
| 135 | + |
| 136 | + |
| 137 | + #computing expected number of customers in the system |
| 138 | + Ls=(sum(Pn*Pn.index)) |
| 139 | + |
| 140 | + |
| 141 | + #computing expected customers waiting in line |
| 142 | + Lq=sum((Pn.index[c+1:]-1)*(Pn[c+1:])) |
| 143 | + |
| 144 | + #plots |
| 145 | + |
| 146 | + |
| 147 | + plt.figure(figsize=(12,4)) |
| 148 | + sns.lineplot(x=data.index,y=wait_times,color='black').set(xticklabels=[]) |
| 149 | + plt.xlabel('Customer number') |
| 150 | + plt.ylabel('minutes') |
| 151 | + plt.title('Wait time of customers with '+str(c)+ ' servers') |
| 152 | + sns.despine() |
| 153 | + plt.show() |
| 154 | + |
| 155 | + if c==1: |
| 156 | + plt.figure(figsize=(7,7)) |
| 157 | + sns.distplot(inter_arrival_times,kde=False,color='r') |
| 158 | + plt.title('Time between Arrivals') |
| 159 | + plt.xlabel('Minutes') |
| 160 | + plt.ylabel('Frequency') |
| 161 | + sns.despine() |
| 162 | + plt.show() |
| 163 | + |
| 164 | + plt.figure(figsize=(8,8)) |
| 165 | + sns.distplot(service_times,kde=False) |
| 166 | + plt.title('Service Times') |
| 167 | + plt.xlabel('Minutes') |
| 168 | + plt.ylabel('Frequency') |
| 169 | + sns.despine() |
| 170 | + plt.show() |
| 171 | + |
| 172 | + plt.figure(figsize=(8,8)) |
| 173 | + sns.barplot(x=Pn.index,y=Pn,color='g') |
| 174 | + plt.title('Probability of n customers in the system with '+str(c)+ ' servers') |
| 175 | + plt.xlabel('number of customers') |
| 176 | + plt.ylabel('Probability') |
| 177 | + sns.despine() |
| 178 | + plt.show() |
| 179 | + |
| 180 | + ############################ |
| 181 | + '''plt.figure(figsize=(7,7)) |
| 182 | + sns.barplot(['Idle','Occupied'],[Pn[0],1-Pn[0]],color='mediumpurple') |
| 183 | + plt.title('Utilization %') |
| 184 | + plt.xlabel('System state') |
| 185 | + plt.ylabel('Probability') |
| 186 | + sns.despine() |
| 187 | + plt.show()''' |
| 188 | + ########################## |
| 189 | + utilization.setdefault(c,(Ls-Lq)/c) |
| 190 | + |
| 191 | + |
| 192 | + print('Output:','\n', |
| 193 | + 'Servers : '+str(c),'\n ' |
| 194 | + 'Time Between Arrivals : ',str(data.inter_arrival_times.mean()),'\n', |
| 195 | + 'Service Time: (1/µ)',str(data.service_times.mean()),'\n' |
| 196 | + ' Utilization (c): ',str((Ls-Lq)/c),'\n', |
| 197 | + 'Expected wait time in line (Wq):',str(data['wait_times'].mean()),'\n', |
| 198 | + 'Expected time spent on the system (Ws):',str(data.total_times.mean()),'\n', |
| 199 | + 'Expected number of customers in line (Lq):',str(Lq),'\n', |
| 200 | + 'Expected number of clients in the system (Ls):',str(Ls),'\n ' |
| 201 | + 'Expected number of occupied servers :',str(Ls-Lq),'\n') |
| 202 | + |
| 203 | + c=c+1 |
| 204 | + |
| 205 | +utilization=pd.Series(utilization) |
| 206 | +plt.figure(figsize=(6,6)) |
| 207 | +sns.pointplot(x=utilization.index,y=utilization) |
| 208 | +plt.xlabel('Number of servers') |
| 209 | +plt.ylabel('Utilization') |
| 210 | +plt.title('number of servers vs Utilization') |
| 211 | + |
0 commit comments