Simulation of a M/M/1 queue

Efficiency improvement

Control Variate

In [6]:
include("tally.jl")
Out[6]:
stdev (generic function with 1 method)
In [7]:
include("tallystore.jl")
Out[7]:
add (generic function with 2 methods)
In [8]:
using SimJulia
using Distributions
using RandomStreams

const SEED = 12345

rand_dist(rng::MRG32k3a, Dist::Distribution) = quantile(Dist, rand(rng))

seeds = [SEED, SEED, SEED, SEED, SEED, SEED]
gen = MRG32k3aGen(seeds)
WARNING: Method definition rand_dist(RandomStreams.MRG32k3a, Distributions.Distribution) in module Main at In[1]:8 overwritten at In[8]:7.
Out[8]:
Seed for next MRG32k3a generator:
[12345,12345,12345,12345,12345,12345]
In [9]:
function ci_normal(n::Int64, mean::Float64, stdev::Float64, α::Float64)
    z = quantile(Normal(), 1-α/2)
    w = z*stdev/sqrt(n)
    # Lower bound
    l = mean - w
    # Upper bound
    u = mean + w
    
    return l, u
end
WARNING: Method definition ci_normal(Int64, Float64, Float64, Float64) in module Main at In[2]:2 overwritten at In[9]:2.
Out[9]:
ci_normal (generic function with 1 method)
In [10]:
function ci_tdist(n::Int64, mean::Float64, stdev::Float64, α::Float64)
    z = quantile(TDist(n-1), 1-α/2)
    w = z*stdev/sqrt(n)
    # Lower bound
    l = mean - w
    # Upper bound
    u = mean + w
    
    return l, u
end
WARNING: Method definition ci_tdist(Int64, Float64, Float64, Float64) in module Main at In[3]:2 overwritten at In[10]:2.
Out[10]:
ci_tdist (generic function with 1 method)
In [11]:
function ci_ratio(x, y::TallyStore, α::Float64)
    n = nobs(x.t)
    z = quantile(TDist(n-1), 1-α/2)

    μ1 = average(x.t)
    μ2 = average(y.t)
    # Ratio estimator
    if (μ2 == 0)
        ν = NaN
    else
        ν = μ1/μ2
    end
    
    # Variance of the ratio
    σ = sqrt((variance(x.t) + variance(y.t)*ν*ν - 2*cov(x.obs, y.obs)*ν)/(μ2*μ2))

    w = z*σ/sqrt(n)

    # Lower bound
    l = ν - w
    # Upper bound
    u = ν + w
    
    return ν, l, u
end
Out[11]:
ci_ratio (generic function with 1 method)
In [13]:
println("M/M/1 with processes")

# rates
λ = 150.0
μ = 300.0
ρ = λ/μ

# Working periods
periods = 13
# Period length
period_length = 1.0

# occupancy factor
B = [0.8, 1.0, 1.2, 1.4]
pB = [0.25, 0.55, 0.15, 0.05]

# We consider independent days, so there is no warmup to apply.
warmup = 0;

type System
    W
    B
    arrival
    service
    counter
    arrgen
    servgen
    day
    
    calls
    limit
    
    function System(text::String)
        s = new()
        s.W = Tally(text)
        s.B = 1.0
        s.arrival = Exponential(1.0/λ)
        s.service = Exponential(1.0/μ)
        s.arrgen = next_stream(gen)
        s.servgen = next_stream(gen)
        s.day = next_stream(gen)
        
        s.calls = 0
        s.limit = 1.0/180.0
        
        return s;
    end
end

function restart(s::System)
    init(s.W)
    s.calls = 0
    next_substream!(s.arrgen)
    next_substream!(s.servgen)
    next_substream!(s.day)
end

function set_busynessFactor(s::System, B::Float64)
    s.B = B
    s.arrival = Exponential(1.0/(B*λ))
end
M/M/1 with processes
Out[13]:
set_busynessFactor (generic function with 1 method)
In [14]:
# Compute the expectation of B
EB = pB'*B
Out[14]:
1-element Array{Float64,1}:
 1.0
In [15]:
# Expected arrivals
EA = periods*period_length*λ
Out[15]:
1950.0
In [21]:
s = System("Waiting Times")
Out[21]:
System(Tally("Waiting Times",0,0.0,Inf,-Inf,0.0,0.0,0.0),1.0,Distributions.Exponential{Float64}(θ=0.006666666666666667),Distributions.Exponential{Float64}(θ=0.0033333333333333335),#undef,Full state of MRG32k3a generator:
Cg = [12345,12345,12345,12345,12345,12345]
Bg = [12345,12345,12345,12345,12345,12345]
Ig = [12345,12345,12345,12345,12345,12345],Full state of MRG32k3a generator:
Cg = [3692455944,1366884236,2968912127,335948734,4161675175,475798818]
Bg = [3692455944,1366884236,2968912127,335948734,4161675175,475798818]
Ig = [3692455944,1366884236,2968912127,335948734,4161675175,475798818],Full state of MRG32k3a generator:
Cg = [1015873554,1310354410,2249465273,994084013,2912484720,3876682925]
Bg = [1015873554,1310354410,2249465273,994084013,2912484720,3876682925]
Ig = [1015873554,1310354410,2249465273,994084013,2912484720,3876682925],0,0.005555555555555556)
In [16]:
# Allow a simulation with a fixed number of clients

function source(env::Environment, s::System, limit::Float64)
    i = 0
    while (true)
        yield(Timeout(env, rand_dist(s.arrgen, s.arrival)))
        if (now(env) > limit) break end
        i += 1
        Process(env, customer, s, i, s.counter)
    end
end

function source_fixed(env::Environment, s::System, counter::Resource, nCusts::Int64)
    for i = 1:nCusts
        yield(Timeout(env, rand_dist(s.arrgen, s.arrival)))
        Process(env, customer, s, i, counter)
    end
end

function customer(env::Environment, s::System, idx::Int, counter::Resource)
    # Record the arrival time in the system
    arrive = now(env)
    yield(Request(counter))
    # The simulation clock now contains the time when the client goes to the server.
    # Record the waiting time
    if (idx > warmup)
        wait = now(env) - arrive
        add(s.W, wait)
        if (wait <= s.limit)
            s.calls += 1
        end
    end
    yield(Timeout(env, rand_dist(s.servgen, s.service)))
    yield(Release(counter))
end
Out[16]:
customer (generic function with 1 method)
In [18]:
function gen_day(s::System)
    u = rand(s.day)
    i = 1
    p = pB[1]
    while (p < u)
        i += 1
        p += pB[i]
    end
    s.B = B[i]
    s.arrival = Exponential(1.0/(s.B*λ))
    # println("B: $(s.B), u: $u, i: $i")
end
WARNING: Method definition gen_day(Main.System) in module Main at In[17]:2 overwritten at In[18]:2.
Out[18]:
gen_day (generic function with 1 method)
In [19]:
function onesim(s::System)    
    env = Environment()
    s.counter = Resource(env, 1)

    # We consider a system over 24 hours
    Process(env, source, s, periods*period_length)
    run(env)
end
Out[19]:
onesim (generic function with 1 method)
In [22]:
# We genereate the day-dependent quantities
gen_day(s)
    
onesim(s)
In [23]:
average(s.W)
Out[23]:
0.0033006779213345626
In [24]:
nobs(s.W)
Out[24]:
1972
In [25]:
s.calls
Out[25]:
1558
In [26]:
# Service levels
SL = s.calls/nobs(s.W)
Out[26]:
0.7900608519269777
In [27]:
meanWaits = TallyStore("Average waiting times")
Out[27]:
TallyStore(Float64[],Tally("Average waiting times",0,0.0,Inf,-Inf,0.0,0.0,0.0))
In [28]:
totWaits = TallyStore("Cumulative waiting times")
Out[28]:
TallyStore(Float64[],Tally("Cumulative waiting times",0,0.0,Inf,-Inf,0.0,0.0,0.0))
In [29]:
nObs = TallyStore("Number of observations")
nCalls = TallyStore("Number of calls answered in less than $(s.limit*3600) seconds")
nOver = TallyStore("Number of calls answered in more than $(s.limit*3600) seconds")
Out[29]:
TallyStore(Float64[],Tally("Number of calls answered in more than 20.0 seconds",0,0.0,Inf,-Inf,0.0,0.0,0.0))
In [30]:
nSim = 100
Out[30]:
100
In [31]:
for n=1:nSim
    restart(s)
    gen_day(s)
    onesim(s)
    w = average(s.W)
    N = nobs(s.W)
    add(meanWaits, w)
    add(totWaits, sum(s.W))
    add(nObs, Float64(N))
    add(nCalls, Float64(s.calls))
    add(nOver, Float64(N-s.calls))
    println("Sim $n. Average waiting time: $w. Number of observations: $N")
end
Sim 1. Average waiting time: 0.003720571871425421. Number of observations: 1941
Sim 2. Average waiting time: 0.0033023487299231784. Number of observations: 1946
Sim 3. Average waiting time: 0.003308842792981638. Number of observations: 1985
Sim 4. Average waiting time: 0.0020712515586998885. Number of observations: 1599
Sim 5. Average waiting time: 0.00318239428812974. Number of observations: 1969
Sim 6. Average waiting time: 0.0022165349423393715. Number of observations: 1565
Sim 7. Average waiting time: 0.0031093091894904513. Number of observations: 1911
Sim 8. Average waiting time: 0.0035067456703061703. Number of observations: 1913
Sim 9. Average waiting time: 0.004361536640892026. Number of observations: 2332
Sim 10. Average waiting time: 0.002788153049901509. Number of observations: 1543
Sim 11. Average waiting time: 0.0033044579571697465. Number of observations: 2009
Sim 12. Average waiting time: 0.005351663428118502. Number of observations: 2354
Sim 13. Average waiting time: 0.0037011665935685538. Number of observations: 1969
Sim 14. Average waiting time: 0.002222835692320654. Number of observations: 1585
Sim 15. Average waiting time: 0.003083746690268348. Number of observations: 2001
Sim 16. Average waiting time: 0.002981714412114932. Number of observations: 1911
Sim 17. Average waiting time: 0.0030555114420788305. Number of observations: 1912
Sim 18. Average waiting time: 0.003506207953125015. Number of observations: 1952
Sim 19. Average waiting time: 0.002147729622634049. Number of observations: 1524
Sim 20. Average waiting time: 0.004017856775483353. Number of observations: 1974
Sim 21. Average waiting time: 0.002485216084133899. Number of observations: 1546
Sim 22. Average waiting time: 0.004661197599766311. Number of observations: 2024
Sim 23. Average waiting time: 0.004966603990133761. Number of observations: 2289
Sim 24. Average waiting time: 0.0034056000818116225. Number of observations: 2004
Sim 25. Average waiting time: 0.002185046938322891. Number of observations: 1527
Sim 26. Average waiting time: 0.005131626400502986. Number of observations: 2297
Sim 27. Average waiting time: 0.0035400720213672604. Number of observations: 1976
Sim 28. Average waiting time: 0.003925742844799619. Number of observations: 2001
Sim 29. Average waiting time: 0.002159921613170449. Number of observations: 1580
Sim 30. Average waiting time: 0.006826953493210012. Number of observations: 2386
Sim 31. Average waiting time: 0.004455497009499094. Number of observations: 2338
Sim 32. Average waiting time: 0.002100989397221596. Number of observations: 1561
Sim 33. Average waiting time: 0.00352848272757416. Number of observations: 1982
Sim 34. Average waiting time: 0.004230986820538758. Number of observations: 2309
Sim 35. Average waiting time: 0.002739789663713523. Number of observations: 1998
Sim 36. Average waiting time: 0.0034294708876148007. Number of observations: 1963
Sim 37. Average waiting time: 0.0026234106096698797. Number of observations: 1860
Sim 38. Average waiting time: 0.003076118354897628. Number of observations: 1987
Sim 39. Average waiting time: 0.0019343895700099703. Number of observations: 1546
Sim 40. Average waiting time: 0.004483529987310878. Number of observations: 2301
Sim 41. Average waiting time: 0.005583573815630634. Number of observations: 2396
Sim 42. Average waiting time: 0.004268794482114983. Number of observations: 2379
Sim 43. Average waiting time: 0.007036793306398343. Number of observations: 2680
Sim 44. Average waiting time: 0.002070422473702122. Number of observations: 1523
Sim 45. Average waiting time: 0.0028692847724691526. Number of observations: 1870
Sim 46. Average waiting time: 0.0029869276748592196. Number of observations: 1915
Sim 47. Average waiting time: 0.0033796155465497285. Number of observations: 1897
Sim 48. Average waiting time: 0.0026807871314295634. Number of observations: 1907
Sim 49. Average waiting time: 0.003201227638651335. Number of observations: 1943
Sim 50. Average waiting time: 0.0035021930466402375. Number of observations: 1955
Sim 51. Average waiting time: 0.0032460889196848195. Number of observations: 1860
Sim 52. Average waiting time: 0.006551053413253542. Number of observations: 2631
Sim 53. Average waiting time: 0.004011178022626635. Number of observations: 2025
Sim 54. Average waiting time: 0.0023507725443465983. Number of observations: 1562
Sim 55. Average waiting time: 0.003598456628406958. Number of observations: 1882
Sim 56. Average waiting time: 0.0037543619702599786. Number of observations: 1989
Sim 57. Average waiting time: 0.002293895654865687. Number of observations: 1556
Sim 58. Average waiting time: 0.0017167234751628273. Number of observations: 1468
Sim 59. Average waiting time: 0.003225295360282114. Number of observations: 1918
Sim 60. Average waiting time: 0.0026874339820442644. Number of observations: 1587
Sim 61. Average waiting time: 0.002373378603908627. Number of observations: 1566
Sim 62. Average waiting time: 0.007539973663741074. Number of observations: 2776
Sim 63. Average waiting time: 0.0054043294059095736. Number of observations: 2431
Sim 64. Average waiting time: 0.0034142224158132902. Number of observations: 1958
Sim 65. Average waiting time: 0.003595158561912034. Number of observations: 1905
Sim 66. Average waiting time: 0.004524966945656877. Number of observations: 2300
Sim 67. Average waiting time: 0.005227245274521963. Number of observations: 2362
Sim 68. Average waiting time: 0.002124035108624874. Number of observations: 1595
Sim 69. Average waiting time: 0.003965701884256056. Number of observations: 2025
Sim 70. Average waiting time: 0.002991405995208019. Number of observations: 1876
Sim 71. Average waiting time: 0.0019775434650848886. Number of observations: 1610
Sim 72. Average waiting time: 0.0026371549320197475. Number of observations: 1894
Sim 73. Average waiting time: 0.003956835286060474. Number of observations: 1945
Sim 74. Average waiting time: 0.0035845956210402347. Number of observations: 1988
Sim 75. Average waiting time: 0.003203398131711602. Number of observations: 1926
Sim 76. Average waiting time: 0.002793836123756446. Number of observations: 1926
Sim 77. Average waiting time: 0.003840152506316152. Number of observations: 2011
Sim 78. Average waiting time: 0.0035558692053428076. Number of observations: 1981
Sim 79. Average waiting time: 0.0036073116135940846. Number of observations: 1924
Sim 80. Average waiting time: 0.0025413869174538244. Number of observations: 1933
Sim 81. Average waiting time: 0.002289314187629245. Number of observations: 1592
Sim 82. Average waiting time: 0.0036922998675991987. Number of observations: 2001
Sim 83. Average waiting time: 0.0033322202236578274. Number of observations: 1981
Sim 84. Average waiting time: 0.0020868459129171086. Number of observations: 1536
Sim 85. Average waiting time: 0.003205900093939716. Number of observations: 1964
Sim 86. Average waiting time: 0.009808768526355002. Number of observations: 2762
Sim 87. Average waiting time: 0.0037189215923070485. Number of observations: 1975
Sim 88. Average waiting time: 0.004781296103707322. Number of observations: 2321
Sim 89. Average waiting time: 0.0023608684354718542. Number of observations: 1637
Sim 90. Average waiting time: 0.0029689934147985133. Number of observations: 1931
Sim 91. Average waiting time: 0.004861925800462296. Number of observations: 2330
Sim 92. Average waiting time: 0.0027863192705589617. Number of observations: 1978
Sim 93. Average waiting time: 0.0020736865475774104. Number of observations: 1545
Sim 94. Average waiting time: 0.004020642014971374. Number of observations: 2338
Sim 95. Average waiting time: 0.002239474249580041. Number of observations: 1558
Sim 96. Average waiting time: 0.0034113089551479486. Number of observations: 1914
Sim 97. Average waiting time: 0.003129351054501316. Number of observations: 1976
Sim 98. Average waiting time: 0.0021993465817713746. Number of observations: 1558
Sim 99. Average waiting time: 0.008001207400572509. Number of observations: 2654
Sim 100. Average waiting time: 0.0036504215793713777. Number of observations: 1896
In [32]:
average(nObs.t)
Out[32]:
1956.9199999999994
In [33]:
average(nCalls.t)
Out[33]:
1498.4399999999998
In [34]:
variance(nCalls.t)
Out[34]:
11962.854949494951
In [35]:
variance(nCalls.t)/nSim
Out[35]:
119.62854949494951
In [36]:
# Indirect estimator
EA-average(nOver.t)
Out[36]:
1491.52
In [37]:
variance(nOver.t)
Out[37]:
48599.908686868665
In [38]:
covariance = cov(nCalls.obs, nObs.obs)
Out[38]:
27481.611313131314
In [39]:
# Estimator with control variate
average(nCalls.t)-covariance*(average(nObs.t)-EA)/variance(nObs.t)
Out[39]:
1496.3638845357636
In [40]:
# Construct the new estimator
x_vc = Tally("Control Variate estimator")

for i = 1:nSim
    add(x_vc, nCalls.obs[i]-covariance*(nObs.obs[i]-EA)/variance(nObs.t))
end
In [41]:
average(x_vc)
Out[41]:
1496.363884535764
In [42]:
variance(x_vc)
Out[42]:
3717.9130088411243

Stratification

In [64]:
# We first define the number of observations per strate
nB = length(B)
nDays = Array(Int64, nB)
for i = 1:nB
    nDays[i] = round(nSim*pB[i])
end
In [65]:
nDays
Out[65]:
4-element Array{Int64,1}:
  50
 110
  30
  10

Note: this allocation could be improved by ensuring that each strate has enough observations and that the sum is equal to the number of simulations previously set.

In [66]:
servedCalls = Array(Tally, nB)

for i=1:nB
    servedCalls[i] = Tally("Served calls in time for strate %i")
end
In [67]:
for i = 1:nB
    set_busynessFactor(s, B[i])
    for n=1:nDays[i]
        restart(s)
        onesim(s)
        add(servedCalls[i], Float64(s.calls))
    end
end
In [68]:
# Strate details

for i = 1:nB
    println("Strate $i. Mean: ", average(servedCalls[i]),
            " Variance: ", variance(servedCalls[i]))
end
Strate 1. Mean: 1335.3 Variance: 1677.6428571428562
Strate 2. Mean: 1523.6272727272733 Variance: 2157.5203502919044
Strate 3. Mean: 1613.7666666666667 Variance: 2814.8057471264337
Strate 4. Mean: 1552.5 Variance: 2472.277777777778
In [72]:
mean = 0.0
for i = 1:nB
    mean += pB[i]*average(servedCalls[i])
end
In [73]:
mean
Out[73]:
1491.5100000000004
In [74]:
σ2 = 0.0
for i = 1:nB
    σ2 += pB[i]*pB[i]*variance(servedCalls[i])/nobs(servedCalls[i])
end
σ2 *= nSim
Out[74]:
2151.881657904116
In [75]:
total = 0
nSim = 200
for i=1:nB
    nDays[i] = round(pB[i]*stdev(servedCalls[i]))
    total += nDays[i]
end
for i = 1:nB
    nDays[i] = round(nDays[i]*nSim/total)
end
In [76]:
nDays
Out[76]:
4-element Array{Int64,1}:
  43
 113
  35
   9
In [77]:
for i=1:nB
    servedCalls[i] = Tally("Served calls in time for strate %i")
end

for i = 1:nB
    set_busynessFactor(s, B[i])
    for n=1:nDays[i]
        restart(s)
        onesim(s)
        add(servedCalls[i], Float64(s.calls))
    end
end
In [78]:
# Strate details

for i = 1:nB
    println("Strate $i. Mean: ", average(servedCalls[i]),
            " Variance: ", variance(servedCalls[i]))
end
Strate 1. Mean: 1331.9302325581398 Variance: 1472.3045404208187
Strate 2. Mean: 1522.8761061946902 Variance: 1675.7880847029064
Strate 3. Mean: 1602.7428571428572 Variance: 2005.9025210083983
Strate 4. Mean: 1579.0 Variance: 3685.2499999999995
In [79]:
σ2 = 0.0
for i = 1:nB
    σ2 += pB[i]*pB[i]*variance(servedCalls[i])/nobs(servedCalls[i])
end
σ2 *= nSim
Out[79]:
1787.8473443018017
In [ ]: