shrewd 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/Gemfile +11 -0
- data/README.md +416 -0
- data/Rakefile +0 -0
- data/lib/shrewd.rb +1 -0
- data/lib/shrewd/entities/event.rb +56 -0
- data/lib/shrewd/entities/process.rb +83 -0
- data/lib/shrewd/entities/variable.rb +58 -0
- data/lib/shrewd/simulation.rb +166 -0
- data/shrewd.gemspec +14 -0
- data/spec/integration/simple_spec.rb +145 -0
- data/spec/models/event_spec.rb +50 -0
- data/spec/models/process_spec.rb +51 -0
- data/spec/models/simulation_spec.rb +180 -0
- data/spec/models/variable_spec.rb +195 -0
- data/spec/spec_helper.rb +15 -0
- metadata +61 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# EventSpec
|
|
2
|
+
#
|
|
3
|
+
# Tests for the Shrewd::EventSpec class
|
|
4
|
+
|
|
5
|
+
require 'shrewd/simulation'
|
|
6
|
+
require 'shrewd/entities/event'
|
|
7
|
+
require 'shrewd/entities/process'
|
|
8
|
+
|
|
9
|
+
describe Shrewd::Event do
|
|
10
|
+
|
|
11
|
+
# Shared variables
|
|
12
|
+
let(:name) { 'Initial' }
|
|
13
|
+
let(:description) { 'Description' }
|
|
14
|
+
let(:processes) { [ Shrewd::Process.new('Process1'),
|
|
15
|
+
Shrewd::Process.new('Process2') ] }
|
|
16
|
+
|
|
17
|
+
describe "initialization" do
|
|
18
|
+
|
|
19
|
+
context "with name only" do
|
|
20
|
+
before :each do
|
|
21
|
+
@event = Shrewd::Event.new(name)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should be valid" do
|
|
25
|
+
expect(@event).to be_an_instance_of Shrewd::Event
|
|
26
|
+
expect(@event.name).to eql name
|
|
27
|
+
expect(@event.description).to be_empty
|
|
28
|
+
expect(@event.processes).to eql Array.new
|
|
29
|
+
expect(@event.action).to be_nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "with all parameters" do
|
|
35
|
+
let(:action) { Proc.new { |variables| } }
|
|
36
|
+
|
|
37
|
+
before :each do
|
|
38
|
+
@event = Shrewd::Event.new(name, description, processes, action)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should be valid" do
|
|
42
|
+
expect(@event).to be_an_instance_of Shrewd::Event
|
|
43
|
+
expect(@event.name).to eql name
|
|
44
|
+
expect(@event.description).to eql description
|
|
45
|
+
expect(@event.processes).to eql processes
|
|
46
|
+
expect(@event.action).to eql action
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# ProcessSpec
|
|
2
|
+
#
|
|
3
|
+
# Tests for Shrewd::ProcessSpec class
|
|
4
|
+
|
|
5
|
+
module Shrewd
|
|
6
|
+
require 'shrewd/entities/process'
|
|
7
|
+
require 'shrewd/entities/event'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe Shrewd::Process do
|
|
11
|
+
|
|
12
|
+
describe "initialization" do
|
|
13
|
+
let(:name) { 'Service Event' }
|
|
14
|
+
let(:description) { 'Servicing a customer.' }
|
|
15
|
+
let(:event) { Shrewd::Event.new('Event') }
|
|
16
|
+
let(:conditions) { Proc.new { |variables| true } }
|
|
17
|
+
let(:delay) { Proc.new { |variables| 15 } }
|
|
18
|
+
|
|
19
|
+
context "with only name" do
|
|
20
|
+
before :each do
|
|
21
|
+
@process = Shrewd::Process.new(name)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should be valid" do
|
|
25
|
+
expect(@process).to be_an_instance_of Shrewd::Process
|
|
26
|
+
expect(@process.name).to eql name
|
|
27
|
+
expect(@process.description).to be_empty
|
|
28
|
+
expect(@process.event).to be_nil
|
|
29
|
+
expect(@process.conditions).to be_nil
|
|
30
|
+
expect(@process.delay).to be_nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "with all parameters" do
|
|
35
|
+
before :each do
|
|
36
|
+
@process = Shrewd::Process.new(name, description,
|
|
37
|
+
event, conditions, delay)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should be valid" do
|
|
41
|
+
expect(@process).to be_an_instance_of Shrewd::Process
|
|
42
|
+
expect(@process.name).to eql name
|
|
43
|
+
expect(@process.description).to eql description
|
|
44
|
+
expect(@process.event).to eql event
|
|
45
|
+
expect(@process.conditions).to eql conditions
|
|
46
|
+
expect(@process.delay).to eql delay
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# SimulationSpec
|
|
2
|
+
#
|
|
3
|
+
# Tests for the Shrewd::Simulation class
|
|
4
|
+
|
|
5
|
+
require 'shrewd/simulation'
|
|
6
|
+
|
|
7
|
+
describe Shrewd::Simulation do
|
|
8
|
+
|
|
9
|
+
# Shared variables
|
|
10
|
+
let(:state_variables) { [ Shrewd::Variable.new('Queue'),
|
|
11
|
+
Shrewd::Variable.new('Employees', '', 5)] }
|
|
12
|
+
let(:process_length) { 20 }
|
|
13
|
+
let(:simulation_length) { 1000 }
|
|
14
|
+
let(:initial_processes) do
|
|
15
|
+
process = Shrewd::Process.new('Process1')
|
|
16
|
+
process.delay = Proc.new { process_length }
|
|
17
|
+
|
|
18
|
+
event = Shrewd::Event.new('Arrival')
|
|
19
|
+
event.processes << process
|
|
20
|
+
process.event = event
|
|
21
|
+
|
|
22
|
+
[ process ]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Create a simulation instance before each test
|
|
26
|
+
before :each do
|
|
27
|
+
@simulation = Shrewd::Simulation.new(state_variables, initial_processes)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Validate new simulation instance
|
|
31
|
+
describe "#new" do
|
|
32
|
+
it "should be a simulation" do
|
|
33
|
+
expect(@simulation).to be_an_instance_of Shrewd::Simulation
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "instantiates variables correctly" do
|
|
37
|
+
variables = @simulation.instance_variable_get(:@variables)
|
|
38
|
+
expect(variables).to be_an_instance_of Hash
|
|
39
|
+
|
|
40
|
+
variables.values.each do |variable|
|
|
41
|
+
expect(variable).to be_an_instance_of Shrewd::Variable
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
variables.each do |key, value|
|
|
45
|
+
expect(key).to eql value.name.downcase.gsub(/\s+/,"_").to_sym
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
expect(@simulation.initial_processes).to be_an_instance_of Array
|
|
49
|
+
expect(@simulation.initial_processes).to eql initial_processes
|
|
50
|
+
|
|
51
|
+
@simulation.initial_processes.each do |process|
|
|
52
|
+
expect(process).to be_an_instance_of Shrewd::Process
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe "#start" do
|
|
58
|
+
before :each do
|
|
59
|
+
@simulation.start(simulation_length)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "generates a start event" do
|
|
63
|
+
expect(@simulation.print_log.size).to eql (simulation_length/process_length) + 1
|
|
64
|
+
expect(@simulation.print_log.first[:event].name).to eql 'Start'
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe "#print_log" do
|
|
69
|
+
it "generates a log" do
|
|
70
|
+
expect(@simulation.print_log).to be_an_instance_of Array
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe "#create_initial_event" do
|
|
75
|
+
before :each do
|
|
76
|
+
@simulation.send(:create_initial_event)
|
|
77
|
+
@queue = @simulation.instance_variable_get(:@queue)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "adds initial event to the queue" do
|
|
81
|
+
expect(@queue.size).to eql 1
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "creates initial event" do
|
|
85
|
+
initial_event = @queue.first[:event]
|
|
86
|
+
expect(initial_event).to be_an_instance_of Shrewd::Event
|
|
87
|
+
expect(initial_event.name).to eql 'Start'
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "adds initial processes to initial event" do
|
|
91
|
+
initial_event = @queue.first[:event]
|
|
92
|
+
expect(initial_event.processes.size).to be > 0
|
|
93
|
+
expect(initial_event.processes).to eql initial_processes
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe "#add_to_queue" do
|
|
98
|
+
let(:first_name) { 'First' }
|
|
99
|
+
let(:first_time) { 5 }
|
|
100
|
+
let(:second_name) { 'Second' }
|
|
101
|
+
let(:second_time) { 10 }
|
|
102
|
+
let(:third_name) { 'Third' }
|
|
103
|
+
let(:third_time) { 7 }
|
|
104
|
+
let(:fourth_name) { 'Fourth' }
|
|
105
|
+
let(:fourth_time) { 3 }
|
|
106
|
+
|
|
107
|
+
before :each do
|
|
108
|
+
@initial_event = Shrewd::Event.new(first_name)
|
|
109
|
+
@simulation.send(:add_to_queue, { time: first_time, event: @initial_event })
|
|
110
|
+
@queue = @simulation.instance_variable_get(:@queue)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "adds an event to the queue" do
|
|
114
|
+
expect(@queue).to be_an_instance_of Array
|
|
115
|
+
expect(@queue).to_not be_empty
|
|
116
|
+
expect(@queue.first[:event].name).to eql first_name
|
|
117
|
+
expect(@queue.first[:time]).to eql first_time
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Test base binary search
|
|
121
|
+
context "multiples events" do
|
|
122
|
+
before :each do
|
|
123
|
+
@second_event = Shrewd::Event.new(second_name)
|
|
124
|
+
@simulation.send(:add_to_queue, { time: second_time,
|
|
125
|
+
event: @second_event })
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "adds second event to the queue" do
|
|
129
|
+
expect(@queue.size).to eql 2
|
|
130
|
+
expect(@queue[1][:event].name).to eql second_name
|
|
131
|
+
expect(@queue[1][:time]).to eql second_time
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
context "with third and fourth event" do
|
|
135
|
+
before :each do
|
|
136
|
+
@third_event = Shrewd::Event.new(third_name)
|
|
137
|
+
@fourth_event = Shrewd::Event.new(fourth_name)
|
|
138
|
+
|
|
139
|
+
@simulation.send(:add_to_queue, { time: third_time,
|
|
140
|
+
event: @third_event })
|
|
141
|
+
@simulation.send(:add_to_queue, { time: fourth_time,
|
|
142
|
+
event: @fourth_event })
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "adds third and fourth events to the queue" do
|
|
146
|
+
expect(@queue.size).to eql 4
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "places events in order" do
|
|
150
|
+
time = 0
|
|
151
|
+
@queue.each do |item|
|
|
152
|
+
expect(item[:time]).to be > time
|
|
153
|
+
time = item[:time]
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
describe "#reset" do
|
|
161
|
+
before :each do
|
|
162
|
+
@simulation.start(1000)
|
|
163
|
+
@simulation.reset
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "resets system state" do
|
|
167
|
+
log = @simulation.print_log
|
|
168
|
+
queue = @simulation.instance_variable_get(:@queue)
|
|
169
|
+
clock = @simulation.instance_variable_get(:@clock)
|
|
170
|
+
variables = @simulation.instance_variable_get(:@variables)
|
|
171
|
+
initial = @simulation.instance_variable_get(:@initial_state)
|
|
172
|
+
|
|
173
|
+
expect(log).to be_empty
|
|
174
|
+
expect(queue).to be_empty
|
|
175
|
+
expect(clock).to eql 0
|
|
176
|
+
expect(variables).to eql initial
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# VariableSpec
|
|
2
|
+
#
|
|
3
|
+
# Tests for the Shrewd::Variable class
|
|
4
|
+
|
|
5
|
+
require 'shrewd/entities/variable'
|
|
6
|
+
|
|
7
|
+
describe Shrewd::Variable do
|
|
8
|
+
|
|
9
|
+
# Shared variables
|
|
10
|
+
let(:name) { 'Queue' }
|
|
11
|
+
let(:description) { 'Number of people in line.' }
|
|
12
|
+
let(:initial_value) { 5 }
|
|
13
|
+
|
|
14
|
+
describe "initialization" do
|
|
15
|
+
|
|
16
|
+
# Common examples for validating a variable
|
|
17
|
+
shared_examples "valid variable" do
|
|
18
|
+
|
|
19
|
+
it "should be a variable" do
|
|
20
|
+
expect(@variable).to be_an_instance_of Shrewd::Variable
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should have the correct properties" do
|
|
24
|
+
expect(@variable.name).to eql name
|
|
25
|
+
expect(@variable.description).to eql description
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context "when default value provided" do
|
|
31
|
+
|
|
32
|
+
before :each do
|
|
33
|
+
@variable = Shrewd::Variable.new(name, description, initial_value)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
include_examples "valid variable"
|
|
37
|
+
|
|
38
|
+
it "should have the provided default value" do
|
|
39
|
+
expect(@variable.value).to eql initial_value
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context "when no default value provided" do
|
|
45
|
+
|
|
46
|
+
before :each do
|
|
47
|
+
@variable = Shrewd::Variable.new(name, description)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
include_examples "valid variable"
|
|
51
|
+
|
|
52
|
+
it "should have a default of 0" do
|
|
53
|
+
expect(@variable.value).to eql 0
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe "increment" do
|
|
61
|
+
|
|
62
|
+
let(:positive_amount) { 4 }
|
|
63
|
+
let(:negative_amount) { -2 }
|
|
64
|
+
|
|
65
|
+
before :each do
|
|
66
|
+
@variable = Shrewd::Variable.new(name, description, initial_value)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
context "by default amount" do
|
|
70
|
+
|
|
71
|
+
before :each do
|
|
72
|
+
@variable.increment
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "should add one to initial value" do
|
|
76
|
+
expected_value = initial_value + 1
|
|
77
|
+
expect(@variable.value).to eql expected_value
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context "by positive amount" do
|
|
82
|
+
|
|
83
|
+
before :each do
|
|
84
|
+
@variable.increment positive_amount
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "should add positive amount to initial value" do
|
|
88
|
+
expected_value = initial_value + positive_amount
|
|
89
|
+
expect(@variable.value).to eql expected_value
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
context "by negative amount" do
|
|
95
|
+
|
|
96
|
+
before :each do
|
|
97
|
+
@variable.increment negative_amount
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "should subtract negative amount from initial value" do
|
|
101
|
+
expected_value = initial_value + negative_amount
|
|
102
|
+
expect(@variable.value).to eql expected_value
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
describe "decrement" do
|
|
109
|
+
|
|
110
|
+
let(:positive_amount) { 2 }
|
|
111
|
+
let(:negative_amount) { -2 }
|
|
112
|
+
|
|
113
|
+
before :each do
|
|
114
|
+
@variable = Shrewd::Variable.new(name, description, initial_value)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
context "by default amount" do
|
|
118
|
+
|
|
119
|
+
before :each do
|
|
120
|
+
@variable.decrement
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "should subtract one from initial value" do
|
|
124
|
+
expected_value = initial_value - 1
|
|
125
|
+
expect(@variable.value).to eql expected_value
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
context "by provided positive amount" do
|
|
130
|
+
|
|
131
|
+
before :each do
|
|
132
|
+
@variable.decrement positive_amount
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "should subtract positive amount from initial value" do
|
|
136
|
+
expected_value = initial_value - positive_amount
|
|
137
|
+
expect(@variable.value).to eql expected_value
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
context "by provided negative amount" do
|
|
143
|
+
|
|
144
|
+
before :each do
|
|
145
|
+
@variable.decrement negative_amount
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it "should add negative amount to initial value" do
|
|
149
|
+
expected_value = initial_value - negative_amount
|
|
150
|
+
expect(@variable.value).to eql expected_value
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
describe "compare" do
|
|
157
|
+
|
|
158
|
+
context "with self" do
|
|
159
|
+
before :each do
|
|
160
|
+
@variable1 = Shrewd::Variable.new(name, description, initial_value)
|
|
161
|
+
@variable2 = @variable1
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
it "should be equal" do
|
|
165
|
+
expect(@variable1 == @variable2.value).to be true
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
context "with variable with same value" do
|
|
170
|
+
before :each do
|
|
171
|
+
@variable1 = Shrewd::Variable.new(name, description, initial_value)
|
|
172
|
+
@variable2 = Shrewd::Variable.new(name, description, initial_value)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it "should be equal" do
|
|
176
|
+
expect(@variable1 == @variable2.value).to be true
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
context "with a variable with different value" do
|
|
181
|
+
let(:different_value) { initial_value + 3 }
|
|
182
|
+
|
|
183
|
+
before :each do
|
|
184
|
+
@variable1 = Shrewd::Variable.new(name, description, initial_value)
|
|
185
|
+
@variable2 = Shrewd::Variable.new(name, description, different_value)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it "should not be equal" do
|
|
189
|
+
expect(@variable1 == @variable2.value).to be false
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
end
|
|
195
|
+
end
|