From 9646f53af79e6215a620ca2959b869f57444b19f Mon Sep 17 00:00:00 2001 From: Matthew Howells Date: Mon, 6 Feb 2023 17:10:29 +0000 Subject: [PATCH] Fixed a bug where pre-emptive priorities did not work with zero servers --- ciw/node.py | 2 +- ciw/tests/test_scheduling.py | 149 +++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/ciw/node.py b/ciw/node.py index 23a063c9..8569ff18 100644 --- a/ciw/node.py +++ b/ciw/node.py @@ -137,7 +137,7 @@ def begin_service_if_possible_accept(self, next_individual): self.decide_class_change(next_individual) free_server = self.find_free_server(next_individual) - if free_server is None and isinf(self.c) is False: + if free_server is None and isinf(self.c) is False and self.c > 0: self.decide_preempt(next_individual) if free_server is not None or isinf(self.c): if isinf(self.c) is False: diff --git a/ciw/tests/test_scheduling.py b/ciw/tests/test_scheduling.py index 10687a4a..95aa148f 100644 --- a/ciw/tests/test_scheduling.py +++ b/ciw/tests/test_scheduling.py @@ -375,3 +375,152 @@ def test_preemptive_schedules_resume_options(self): self.assertEqual(r1.service_end_date, 29) self.assertEqual(r1.service_time, 20) self.assertEqual(r1.waiting_time, 8) + + def test_priority_preemption_when_zero_servers(self): + """ + Test whether pre-emptive priorities and server schedules where there are zero servers work well together. + + We will show two scenarios. + - The first where the one server goes off and back on duty while there are no customers present. + - The second where the server goes off duty but back on duty while there are customers waiting. + """ + # First scenario + N = ciw.create_network( + arrival_distributions={ + 'Class 0': [ciw.dists.Deterministic(7)], + 'Class 1': [ciw.dists.Deterministic(13)] + }, + service_distributions={ + 'Class 0': [ciw.dists.Deterministic(5.5)], + 'Class 1': [ciw.dists.Deterministic(1.5)] + }, + number_of_servers=[[[1, 20.3], [0, 20.6], [1, 100]]], + priority_classes=({ + 'Class 0': 1, + 'Class 1': 0 + }, ['continue']) + ) + + Q = ciw.Simulation(N) + Q.simulate_until_max_time(35) + + recs = Q.get_all_records() + # Individual 1 + self.assertEqual(recs[0].id_number, 1) + self.assertEqual(recs[0].customer_class, 0) + self.assertEqual(recs[0].arrival_date, 7) + self.assertEqual(recs[0].service_start_date, 7) + self.assertEqual(recs[0].service_end_date, 12.5) + self.assertEqual(recs[0].record_type, 'service') + # Individual 2 + self.assertEqual(recs[1].id_number, 2) + self.assertEqual(recs[1].customer_class, 1) + self.assertEqual(recs[1].arrival_date, 13) + self.assertEqual(recs[1].service_start_date, 13) + self.assertEqual(recs[1].service_end_date, 14.5) + self.assertEqual(recs[1].record_type, 'service') + # Individual 3 + self.assertEqual(recs[2].id_number, 3) + self.assertEqual(recs[2].customer_class, 0) + self.assertEqual(recs[2].arrival_date, 14) + self.assertEqual(recs[2].service_start_date, 14.5) + self.assertEqual(recs[2].service_end_date, 20) + self.assertEqual(recs[2].record_type, 'service') + # Individual 5 + self.assertEqual(recs[3].id_number, 5) + self.assertEqual(recs[3].customer_class, 1) + self.assertEqual(recs[3].arrival_date, 26) + self.assertEqual(recs[3].service_start_date, 26) + self.assertEqual(recs[3].service_end_date, 27.5) + self.assertEqual(recs[3].record_type, 'service') + # Individual 4's interrupted service + self.assertEqual(recs[4].id_number, 4) + self.assertEqual(recs[4].customer_class, 0) + self.assertEqual(recs[4].arrival_date, 21) + self.assertEqual(recs[4].service_start_date, 21) + self.assertEqual(recs[4].record_type, 'interrupted service') + # Individual 4's resumed service + self.assertEqual(recs[5].id_number, 4) + self.assertEqual(recs[5].customer_class, 0) + self.assertEqual(recs[5].arrival_date, 21) + self.assertEqual(recs[5].service_start_date, 27.5) + self.assertEqual(recs[5].service_end_date, 28) + self.assertEqual(recs[5].record_type, 'service') + # Individual 6 + self.assertEqual(recs[6].id_number, 6) + self.assertEqual(recs[6].customer_class, 0) + self.assertEqual(recs[6].arrival_date, 28) + self.assertEqual(recs[6].service_start_date, 28) + self.assertEqual(recs[6].service_end_date, 33.5) + self.assertEqual(recs[6].record_type, 'service') + + # Second scenario + N = ciw.create_network( + arrival_distributions={ + 'Class 0': [ciw.dists.Deterministic(7)], + 'Class 1': [ciw.dists.Deterministic(13)] + }, + service_distributions={ + 'Class 0': [ciw.dists.Deterministic(5.5)], + 'Class 1': [ciw.dists.Deterministic(1.5)] + }, + number_of_servers=[[[1, 20.3], [0, 22], [1, 100]]], + priority_classes=({ + 'Class 0': 1, + 'Class 1': 0 + }, ['continue']) + ) + + Q = ciw.Simulation(N) + Q.simulate_until_max_time(35) + + recs = Q.get_all_records() + # Individual 1 + self.assertEqual(recs[0].id_number, 1) + self.assertEqual(recs[0].customer_class, 0) + self.assertEqual(recs[0].arrival_date, 7) + self.assertEqual(recs[0].service_start_date, 7) + self.assertEqual(recs[0].service_end_date, 12.5) + self.assertEqual(recs[0].record_type, 'service') + # Individual 2 + self.assertEqual(recs[1].id_number, 2) + self.assertEqual(recs[1].customer_class, 1) + self.assertEqual(recs[1].arrival_date, 13) + self.assertEqual(recs[1].service_start_date, 13) + self.assertEqual(recs[1].service_end_date, 14.5) + self.assertEqual(recs[1].record_type, 'service') + # Individual 3 + self.assertEqual(recs[2].id_number, 3) + self.assertEqual(recs[2].customer_class, 0) + self.assertEqual(recs[2].arrival_date, 14) + self.assertEqual(recs[2].service_start_date, 14.5) + self.assertEqual(recs[2].service_end_date, 20) + self.assertEqual(recs[2].record_type, 'service') + # Individual 5 + self.assertEqual(recs[3].id_number, 5) + self.assertEqual(recs[3].customer_class, 1) + self.assertEqual(recs[3].arrival_date, 26) + self.assertEqual(recs[3].service_start_date, 26) + self.assertEqual(recs[3].service_end_date, 27.5) + self.assertEqual(recs[3].record_type, 'service') + # Individual 4's interrupted service + self.assertEqual(recs[4].id_number, 4) + self.assertEqual(recs[4].customer_class, 0) + self.assertEqual(recs[4].arrival_date, 21) + self.assertEqual(recs[4].service_start_date, 22) + self.assertEqual(recs[4].record_type, 'interrupted service') + # Individual 4's resumed service + self.assertEqual(recs[5].id_number, 4) + self.assertEqual(recs[5].customer_class, 0) + self.assertEqual(recs[5].arrival_date, 21) + self.assertEqual(recs[5].service_start_date, 27.5) + self.assertEqual(recs[5].service_end_date, 29) + self.assertEqual(recs[5].record_type, 'service') + # Individual 6 + self.assertEqual(recs[6].id_number, 6) + self.assertEqual(recs[6].customer_class, 0) + self.assertEqual(recs[6].arrival_date, 28) + self.assertEqual(recs[6].service_start_date, 29) + self.assertEqual(recs[6].service_end_date, 34.5) + self.assertEqual(recs[6].record_type, 'service') +