Skip to content

Commit 8a755e9

Browse files
committed
add SystemPopulation state tracker
1 parent f59e2f9 commit 8a755e9

4 files changed

Lines changed: 199 additions & 4 deletions

File tree

ciw/tests/test_simulation.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ def test_simulate_until_max_customers_with_pbar_method(self):
197197
self.assertEqual(Q3.progress_bar.total, max_custs)
198198
self.assertEqual(Q3.progress_bar.n, max_custs)
199199

200-
def test_simulate_until_deadlock_method(self):
200+
def test_simulate_until_deadlock_method_naiveblocking(self):
201201
ciw.seed(3)
202202
Q = ciw.Simulation(ciw.create_network_from_yml(
203203
'ciw/tests/testing_parameters/params_deadlock.yml'),
@@ -206,6 +206,15 @@ def test_simulate_until_deadlock_method(self):
206206
Q.simulate_until_deadlock()
207207
self.assertEqual(round(Q.times_to_deadlock[((0, 0), (0, 0))], 8), 53.88526441)
208208

209+
def test_simulate_until_deadlock_method_systempopulation(self):
210+
ciw.seed(3)
211+
Q = ciw.Simulation(ciw.create_network_from_yml(
212+
'ciw/tests/testing_parameters/params_deadlock.yml'),
213+
deadlock_detector=ciw.deadlock.StateDigraph(),
214+
tracker=ciw.trackers.SystemPopulation())
215+
Q.simulate_until_deadlock()
216+
self.assertEqual(round(Q.times_to_deadlock[0], 8), 53.88526441)
217+
209218
def test_detect_deadlock_method(self):
210219
Q = ciw.Simulation(ciw.create_network_from_yml(
211220
'ciw/tests/testing_parameters/params_deadlock.yml'),

ciw/tests/test_state_tracker.py

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,93 @@ def test_base_accept_method_within_simulation(self):
8686
self.assertEqual(Q.statetracker.state, None)
8787

8888

89+
class TestSystemPopulation(unittest.TestCase):
90+
def test_systempop_init_method(self):
91+
Q = ciw.Simulation(ciw.create_network_from_yml(
92+
'ciw/tests/testing_parameters/params.yml'))
93+
B = ciw.trackers.SystemPopulation()
94+
B.initialise(Q)
95+
self.assertEqual(B.simulation, Q)
96+
self.assertEqual(B.state, 0)
97+
98+
def test_systempop_change_state_accept_method(self):
99+
Q = ciw.Simulation(ciw.create_network_from_yml(
100+
'ciw/tests/testing_parameters/params.yml'))
101+
B = ciw.trackers.SystemPopulation()
102+
B.initialise(Q)
103+
self.assertEqual(B.state, 0)
104+
B.change_state_accept(1, 1)
105+
self.assertEqual(B.state, 1)
106+
107+
def test_systempop_change_state_block_method(self):
108+
Q = ciw.Simulation(ciw.create_network_from_yml(
109+
'ciw/tests/testing_parameters/params.yml'))
110+
B = ciw.trackers.SystemPopulation()
111+
B.initialise(Q)
112+
B.state = 1
113+
B.change_state_block(1, 1, 2)
114+
self.assertEqual(B.state, 1)
115+
116+
def test_systempop_change_state_release_method(self):
117+
Q = ciw.Simulation(ciw.create_network_from_yml(
118+
'ciw/tests/testing_parameters/params.yml'))
119+
B = ciw.trackers.SystemPopulation()
120+
B.initialise(Q)
121+
B.state = 15
122+
B.change_state_release(1, 1, 2, False)
123+
self.assertEqual(B.state, 14)
124+
B.change_state_release(1, 1, 2, True)
125+
self.assertEqual(B.state, 13)
126+
127+
def test_systempop_hash_state_method(self):
128+
Q = ciw.Simulation(ciw.create_network_from_yml(
129+
'ciw/tests/testing_parameters/params.yml'))
130+
B = ciw.trackers.SystemPopulation()
131+
B.initialise(Q)
132+
B.state = 13
133+
self.assertEqual(B.hash_state(), 13)
134+
135+
def test_systempop_release_method_within_simulation(self):
136+
params = ciw.create_network_from_yml(
137+
'ciw/tests/testing_parameters/params.yml')
138+
Q = ciw.Simulation(params, tracker=ciw.trackers.SystemPopulation())
139+
N = Q.transitive_nodes[2]
140+
inds = [ciw.Individual(i) for i in range(5)]
141+
N.individuals = [inds]
142+
for ind in N.individuals[0]:
143+
srvr = N.find_free_server()
144+
N.attach_server(srvr, ind)
145+
Q.statetracker.state = 14
146+
self.assertEqual(Q.statetracker.state, 14)
147+
Q.current_time = 43.11
148+
N.release(0, Q.nodes[1])
149+
self.assertEqual(Q.statetracker.state, 14)
150+
N.all_individuals[1].is_blocked = True
151+
Q.current_time = 46.72
152+
N.release(1, Q.nodes[1])
153+
self.assertEqual(Q.statetracker.state, 14)
154+
N.release(1, Q.nodes[-1])
155+
self.assertEqual(Q.statetracker.state, 13)
156+
157+
def test_systempop_block_method_within_simulation(self):
158+
params = ciw.create_network_from_yml(
159+
'ciw/tests/testing_parameters/params.yml')
160+
Q = ciw.Simulation(params, tracker=ciw.trackers.SystemPopulation())
161+
N = Q.transitive_nodes[2]
162+
Q.statetracker.state = 14
163+
self.assertEqual(Q.statetracker.state, 14)
164+
N.block_individual(ciw.Individual(1), Q.nodes[1])
165+
self.assertEqual(Q.statetracker.state, 14)
166+
167+
def test_systempop_accept_method_within_simulation(self):
168+
params = ciw.create_network_from_yml(
169+
'ciw/tests/testing_parameters/params.yml')
170+
Q = ciw.Simulation(params, tracker=ciw.trackers.SystemPopulation())
171+
N = Q.transitive_nodes[2]
172+
self.assertEqual(Q.statetracker.state, 0)
173+
Q.current_time = 45.6
174+
N.accept(ciw.Individual(3, 2))
175+
self.assertEqual(Q.statetracker.state, 1)
89176

90177

91178
class TestNaiveBlocking(unittest.TestCase):
@@ -363,7 +450,7 @@ def test_matrix_accept_method_within_simulation(self):
363450

364451

365452
class TestTrackHistory(unittest.TestCase):
366-
def test_one_node_deterministic_(self):
453+
def test_one_node_deterministic_naiveblocking(self):
367454
N = ciw.create_network(
368455
arrival_distributions=[ciw.dists.Sequential([1.5, 0.3, 2.4, 1.1])],
369456
service_distributions=[ciw.dists.Sequential([1.8, 2.2, 0.2, 0.2, 0.2, 0.2])],
@@ -398,3 +485,39 @@ def test_one_node_deterministic_(self):
398485
[Decimal('15.0'), ((0, 0),)]
399486
]
400487
self.assertEqual(Q.statetracker.history, expected_history)
488+
489+
def test_one_node_deterministic_systempopulation(self):
490+
N = ciw.create_network(
491+
arrival_distributions=[ciw.dists.Sequential([1.5, 0.3, 2.4, 1.1])],
492+
service_distributions=[ciw.dists.Sequential([1.8, 2.2, 0.2, 0.2, 0.2, 0.2])],
493+
number_of_servers=[1]
494+
)
495+
B = ciw.trackers.SystemPopulation()
496+
Q = ciw.Simulation(N, tracker=B, exact=26)
497+
Q.simulate_until_max_time(15.5)
498+
expected_history = [
499+
[Decimal('0.0'), 0],
500+
[Decimal('1.5'), 1],
501+
[Decimal('1.8'), 2],
502+
[Decimal('3.3'), 1],
503+
[Decimal('4.2'), 2],
504+
[Decimal('5.3'), 3],
505+
[Decimal('5.5'), 2],
506+
[Decimal('5.7'), 1],
507+
[Decimal('5.9'), 0],
508+
[Decimal('6.8'), 1],
509+
[Decimal('7.0'), 0],
510+
[Decimal('7.1'), 1],
511+
[Decimal('7.3'), 0],
512+
[Decimal('9.5'), 1],
513+
[Decimal('10.6'), 2],
514+
[Decimal('11.3'), 1],
515+
[Decimal('12.1'), 2],
516+
[Decimal('12.4'), 3],
517+
[Decimal('13.5'), 2],
518+
[Decimal('13.7'), 1],
519+
[Decimal('13.9'), 0],
520+
[Decimal('14.8'), 1],
521+
[Decimal('15.0'), 0]
522+
]
523+
self.assertEqual(Q.statetracker.history, expected_history)

ciw/trackers/state_tracker.py

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,53 @@ def timestamp(self):
4141
self.history.append([self.simulation.current_time, self.hash_state()])
4242

4343

44+
class SystemPopulation(StateTracker):
45+
"""
46+
The system population tracker records the number of customers in the
47+
system, regaerdless of node.
48+
49+
Example:
50+
3
51+
This denotes 3 customers at in the whole system.
52+
"""
53+
def initialise(self, simulation):
54+
"""
55+
Initialises the state tracker class.
56+
"""
57+
self.simulation = simulation
58+
self.state = 0
59+
self.history = []
60+
self.timestamp()
61+
62+
def change_state_accept(self, node_id, cust_clss):
63+
"""
64+
Changes the state of the system when a customer is accepted.
65+
"""
66+
self.state += 1
67+
68+
def change_state_block(self, node_id, destination, cust_clss):
69+
"""
70+
Changes the state of the system when a customer gets blocked.
71+
"""
72+
pass
73+
74+
def change_state_release(self, node_id, destination, cust_clss, blocked):
75+
"""
76+
Changes the state of the system when a customer is released.
77+
"""
78+
self.state -= 1
79+
80+
def hash_state(self):
81+
"""
82+
Returns a hashable state.
83+
"""
84+
return self.state
85+
86+
4487
class NaiveBlocking(StateTracker):
4588
"""
46-
The naive blocking tracker simple records the number of customers
47-
at each node, and how many of those customers are currently blocked.
89+
The naive blocking tracker records the number of customers at each node,
90+
and how many of those customers are currently blocked.
4891
4992
Example:
5093
((3, 0), (1, 4))

docs/Reference/state_trackers.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,30 @@ List of Implemented State Trackers for Deadlock Detection
66

77
Currently Ciw has the following state trackers:
88

9+
- :ref:`population`
910
- :ref:`naive`
1011
- :ref:`matrix`
1112

1213

14+
.. _population:
15+
16+
----------------------------
17+
The SystemPopulation Tracker
18+
----------------------------
19+
20+
The SystemPopulation Tracker records the number of customers in the whole system, regardless of which node they are at.
21+
States take the form of a number:
22+
23+
4
24+
25+
This denotes that there are four customers in the system.
26+
27+
The Simulation object takes in the optional argument :code:`tracker` used as follows::
28+
29+
>>> Q = ciw.Simulation(N, tracker=ciw.trackers.SystemPopulation()) # doctest:+SKIP
30+
31+
32+
1333
.. _naive:
1434

1535
-------------------------

0 commit comments

Comments
 (0)