-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy patharrproc.go
137 lines (122 loc) · 4.47 KB
/
arrproc.go
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
package qsim
import (
"math/rand"
)
// An ArrProc (short for "arrival process") generates new Jobs at some interval.
type ArrProc interface {
Arrive(clock int) (jobs []*Job, interval int)
BeforeArrive(f func(ap ArrProc))
AfterArrive(f func(ap ArrProc, jobs []*Job, interval int))
}
// ConstantArrProc generates jobs at a constant interval.
//
// It implements the ArrProc interface.
type ConstantArrProc struct {
// Interval is the interval at which ConstantArrProc will generate Jobs.
Interval int
// Callback lists
cbBeforeArrive []func(ap ArrProc)
cbAfterArrive []func(ap ArrProc, jobs []*Job, interval int)
}
// Arrive generates a Job and returns the constant value of Interval as the
// number of ticks that will elapse before the next arrival.
//
// clock is the current simulation clock time.
func (ap *ConstantArrProc) Arrive(clock int) (jobs []*Job, interval int) {
ap.beforeArrive()
jobs = append(jobs, NewJob(clock))
interval = ap.Interval
ap.afterArrive(jobs, interval)
return
}
// BeforeArrive adds a callback to run immediately before the Arrival Process
// creates a job. This callback is passed the ArrProc itself.
func (ab *ConstantArrProc) BeforeArrive(f func(ArrProc)) {
ab.cbBeforeArrive = append(ab.cbBeforeArrive, f)
}
func (ab *ConstantArrProc) beforeArrive() {
for _, cb := range ab.cbBeforeArrive {
cb(ab)
}
}
// AfterArrive adds a callback to run immediately after the Arrival Process
// creates a job. This callback is passed the ArrProc itself, the Jobs that
// were created, and the interval that will elapse before the next arrival.
func (ab *ConstantArrProc) AfterArrive(f func(ArrProc, []*Job, int)) {
ab.cbAfterArrive = append(ab.cbAfterArrive, f)
}
func (ab *ConstantArrProc) afterArrive(jobs []*Job, interval int) {
for _, cb := range ab.cbAfterArrive {
cb(ab, jobs, interval)
}
}
// NewConstantArrProc returns a new ConstantArrProc with the given Interval
// value.
func NewConstantArrProc(interval int) (ap *ConstantArrProc) {
ap = new(ConstantArrProc)
ap.Interval = interval
return ap
}
// PoissonArrProc generates jobs according to a Poisson process. This means
// that the distribution of intervals between arrivals is an exponential
// distribution. (If you're wondering, lambda = 1. If not, don't worry about
// it.)
//
// Poisson processes useful for modeling radioactive decay, telephone calls at
// a call center, document requests on a web server, and many other punctual
// phenomena where events occur independently from each other.
//
// The distribution of arrival intervals is a continuous distribution, but we
// quantize time, so to minimize approximation errors you should make sure
// that your tick length is much smaller than your average arrival time. If
// jobs are normally arriving once every few seconds, then your ticks should
// be milliseconds.
//
// PoissonArrProc implements the ArrProc interface.
type PoissonArrProc struct {
Mean float64
// Callback lists
cbBeforeArrive []func(ap ArrProc)
cbAfterArrive []func(ap ArrProc, jobs []*Job, interval int)
}
// Arrive generates a Job and returns the interval that will elapse before the
// subsequent arrival. These arrival intervals are exponentially distributed.
//
// clock is the current simulation clock time.
func (ap *PoissonArrProc) Arrive(clock int) (jobs []*Job, interval int) {
ap.beforeArrive()
jobs = append(jobs, NewJob(clock))
interval = ap.pickInterval()
ap.afterArrive(jobs, interval)
return
}
// BeforeArrive adds a callback to run immediately before the Arrival Process
// creates a job. This callback is passed the ArrProc itself.
func (ap *PoissonArrProc) BeforeArrive(f func(ArrProc)) {
ap.cbBeforeArrive = append(ap.cbBeforeArrive, f)
}
func (ap *PoissonArrProc) beforeArrive() {
for _, cb := range ap.cbBeforeArrive {
cb(ap)
}
}
// AfterArrive adds a callback to run immediately after the Arrival Process
// creates a job. This callback is passed the ArrProc itself, the Jobs that
// were created, and the interval that will elapse before the next arrival.
func (ap *PoissonArrProc) AfterArrive(f func(ArrProc, []*Job, int)) {
ap.cbAfterArrive = append(ap.cbAfterArrive, f)
}
func (ap *PoissonArrProc) afterArrive(jobs []*Job, interval int) {
for _, cb := range ap.cbAfterArrive {
cb(ap, jobs, interval)
}
}
// Picks an arrival interval from an exponential distribution.
func (ab *PoissonArrProc) pickInterval() int {
var r float64
r = rand.ExpFloat64() * ab.Mean
return int(r)
}
func NewPoissonArrProc(mean float64) (ap *PoissonArrProc) {
return &PoissonArrProc{Mean: mean}
}