1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
""" bcc_OO.py
Queue with blocked customers cleared
Jobs (e.g messages) arrive randomly at rate 1.0 per minute at a
2-server system. Mean service time is 0.75 minutes and the
service-time distribution is (1) exponential, (2) Erlang-5, or (3)
hyperexponential with p=1/8,m1=2.0, and m2=4/7. However no
queue is allowed; a job arriving when all the servers are busy is
rejected.
Develop and run a simulation program to estimate the probability of
rejection (which, in steady-state, is the same as p(c)) Measure
and compare the probability for each service time distribution.
Though you should test the program with a trace, running just a few
jobs, the final runs should be of 10000 jobs without a trace. Stop
the simulation when 10000 jobs have been generated.
"""
from SimPy.Simulation import *
from random import seed,Random,expovariate,uniform
## Model components ------------------------
dist = ""
def bcc(lam, mu,s):
""" bcc - blocked customers cleared model
- returns p[i], i = 0,1,..s.
- ps = p[s] = prob of blocking
- lameff = effective arrival rate = lam*(1-ps)
See Winston 22.11 for Blocked Customers Cleared Model (Erlang B formula)
"""
rho = lam/mu
n = range(s+1)
p = [0]*(s+1)
p[0] = 1
sump = 1.0
for i in n[1:]:
p[i] = (rho/i)*p[i-1]
sump = sump + p[i]
p0 = 1.0/sump
for i in n:
p[i] = p[i]*p0
p0 = p[0]
ps = p[s]
lameff = lam*(1-ps)
L = rho*(1-ps)
return {'lambda':lam,'mu':mu,'s':s,
'p0':p0,'p[i]':p,'ps':ps, 'L':L}
def ErlangVariate(mean,K):
""" Erlang random variate
mean = mean
K = shape parameter
g = rv to be used
"""
sum = 0.0 ; mu = K/mean
for i in range(K):
sum += expovariate(mu)
return (sum)
def HyperVariate(p,m1,m2):
""" Hyperexponential random variate
p = prob of branch 1
m1 = mean of exponential, branch 1
m2 = mean of exponential, branch 2
g = rv to be used
"""
if random() < p:
return expovariate(1.0/m1)
else: return expovariate(1.0/m2)
def testHyperVariate():
""" tests the HyerVariate rv generator"""
ERR=0
x = (1.0981,1.45546,5.7470156)
p = 0.0, 1.0 ,0.5
g = Random(1113355)
for i in range(3):
x1 = HyperVariate(p[i],1.0,10.0,g)
#print p[i], x1
assert abs(x1 - x[i]) < 0.001,'HyperVariate error'
def erlangB(rho,c):
""" Erlang's B formula for probabilities in no-queue
Returns p[n] list
see also SPlus and R version in que.q mmcK
que.py has bcc.
"""
n = range(c+1) ; pn = range(c+1)
term = 1
pn[0] = 1
sum = 1 ; term = 1.0
i=1
while i < (c+1):
term *= rho/i
pn[i] = term
sum += pn[i]
i += 1
for i in n: pn[i] = pn[i]/sum
return(pn)
class JobGen(Process):
""" generates a sequence of Jobs
"""
def execute(self,JobRate,MaxJob,mu):
global NoInService, Busy
for i in range(MaxJob):
j = Job(sim=self.sim)
self.sim.activate(j,j.execute(i,mu),delay=0.0)
t = expovariate(JobRate)
MT.tally(t)
yield hold,self,t
self.trace("Job generator finished")
def trace(self,message):
if JobGenTRACING: print "%8.4f \t%s"%(self.sim.now(), message)
class Job(Process):
""" Jobs that are either accepted or rejected
"""
def execute(self,i,mu):
""" Job execution, only if accepted"""
global NoInService,Busy,dist,NoRejected
if NoInService < c:
self.trace("Job %2d accepted b=%1d"%(i,Busy))
NoInService +=1
if NoInService == c:
Busy =1
try: BM.accum(Busy,now())
except: "accum error BM=",BM
#yield hold,self,Job.g.expovariate(self.mu); dist= "Exponential"
yield hold,self,ErlangVariate(1.0/mu,5); dist= "Erlang "
#yield hold,self,HyperVariate(1.0/8,m1=2.0,m2=4.0/7,g=Job.g); dist= "HyperExpon "
NoInService -=1
Busy =0
BM.accum(Busy,self.sim.now())
self.trace("Job %2d leaving b=%1d"%(i,Busy))
else:
self.trace("Job %2d REJECT b=%1d"%(i,Busy))
NoRejected +=1
def trace(self,message):
if JobTRACING: print "%8.4f \t%s"%(self.sim.now(), message)
## Experiment data -------------------------
c = 2
lam = 1.0 ## per minute
mu = 1.0/0.75 ## per minute
p = 1.0/8 ; m1= 2.0; m2 = 4.0/7.0
K = 5
rho = lam/mu
NoRejected = 0
NoInService = 0
Busy = 0
JobRate = lam
JobMax = 10000
JobTRACING = 0
JobGenTRACING = 0
## Model/Experiment ------------------------------
seed(111333)
s=Simulation()
BM=Monitor(sim=s)
MT = Monitor(sim=s)
s.initialize()
jbg = JobGen(sim=s)
s.activate(jbg,jbg.execute(1.0,JobMax,mu),0.0)
s.simulate(until=20000.0)
## Analysis/output -------------------------
print 'bcc'
print "time at the end =",s.now()
print "now=",s.now(), " startTime ",BM.startTime
print "No Rejected = %d, ratio= %s"%(NoRejected,(1.0*NoRejected)/JobMax)
print "Busy proportion (%6s) = %8.6f"%(dist,BM.timeAverage(s.now()),)
print "Erlang pc (th) = %8.6f"%(erlangB(rho,c)[c],)
|