Skip to content

Commit 8f5c8ad

Browse files
Merge pull request #210 from MHowells/Fix_Pre-emption_Bug_With_Schedules
Fixed a bug where pre-emptive priorities did not work with zero servers
2 parents 86caae1 + 9646f53 commit 8f5c8ad

2 files changed

Lines changed: 150 additions & 1 deletion

File tree

ciw/node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ def begin_service_if_possible_accept(self, next_individual):
137137
self.decide_class_change(next_individual)
138138

139139
free_server = self.find_free_server(next_individual)
140-
if free_server is None and isinf(self.c) is False:
140+
if free_server is None and isinf(self.c) is False and self.c > 0:
141141
self.decide_preempt(next_individual)
142142
if free_server is not None or isinf(self.c):
143143
if isinf(self.c) is False:

ciw/tests/test_scheduling.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,3 +375,152 @@ def test_preemptive_schedules_resume_options(self):
375375
self.assertEqual(r1.service_end_date, 29)
376376
self.assertEqual(r1.service_time, 20)
377377
self.assertEqual(r1.waiting_time, 8)
378+
379+
def test_priority_preemption_when_zero_servers(self):
380+
"""
381+
Test whether pre-emptive priorities and server schedules where there are zero servers work well together.
382+
383+
We will show two scenarios.
384+
- The first where the one server goes off and back on duty while there are no customers present.
385+
- The second where the server goes off duty but back on duty while there are customers waiting.
386+
"""
387+
# First scenario
388+
N = ciw.create_network(
389+
arrival_distributions={
390+
'Class 0': [ciw.dists.Deterministic(7)],
391+
'Class 1': [ciw.dists.Deterministic(13)]
392+
},
393+
service_distributions={
394+
'Class 0': [ciw.dists.Deterministic(5.5)],
395+
'Class 1': [ciw.dists.Deterministic(1.5)]
396+
},
397+
number_of_servers=[[[1, 20.3], [0, 20.6], [1, 100]]],
398+
priority_classes=({
399+
'Class 0': 1,
400+
'Class 1': 0
401+
}, ['continue'])
402+
)
403+
404+
Q = ciw.Simulation(N)
405+
Q.simulate_until_max_time(35)
406+
407+
recs = Q.get_all_records()
408+
# Individual 1
409+
self.assertEqual(recs[0].id_number, 1)
410+
self.assertEqual(recs[0].customer_class, 0)
411+
self.assertEqual(recs[0].arrival_date, 7)
412+
self.assertEqual(recs[0].service_start_date, 7)
413+
self.assertEqual(recs[0].service_end_date, 12.5)
414+
self.assertEqual(recs[0].record_type, 'service')
415+
# Individual 2
416+
self.assertEqual(recs[1].id_number, 2)
417+
self.assertEqual(recs[1].customer_class, 1)
418+
self.assertEqual(recs[1].arrival_date, 13)
419+
self.assertEqual(recs[1].service_start_date, 13)
420+
self.assertEqual(recs[1].service_end_date, 14.5)
421+
self.assertEqual(recs[1].record_type, 'service')
422+
# Individual 3
423+
self.assertEqual(recs[2].id_number, 3)
424+
self.assertEqual(recs[2].customer_class, 0)
425+
self.assertEqual(recs[2].arrival_date, 14)
426+
self.assertEqual(recs[2].service_start_date, 14.5)
427+
self.assertEqual(recs[2].service_end_date, 20)
428+
self.assertEqual(recs[2].record_type, 'service')
429+
# Individual 5
430+
self.assertEqual(recs[3].id_number, 5)
431+
self.assertEqual(recs[3].customer_class, 1)
432+
self.assertEqual(recs[3].arrival_date, 26)
433+
self.assertEqual(recs[3].service_start_date, 26)
434+
self.assertEqual(recs[3].service_end_date, 27.5)
435+
self.assertEqual(recs[3].record_type, 'service')
436+
# Individual 4's interrupted service
437+
self.assertEqual(recs[4].id_number, 4)
438+
self.assertEqual(recs[4].customer_class, 0)
439+
self.assertEqual(recs[4].arrival_date, 21)
440+
self.assertEqual(recs[4].service_start_date, 21)
441+
self.assertEqual(recs[4].record_type, 'interrupted service')
442+
# Individual 4's resumed service
443+
self.assertEqual(recs[5].id_number, 4)
444+
self.assertEqual(recs[5].customer_class, 0)
445+
self.assertEqual(recs[5].arrival_date, 21)
446+
self.assertEqual(recs[5].service_start_date, 27.5)
447+
self.assertEqual(recs[5].service_end_date, 28)
448+
self.assertEqual(recs[5].record_type, 'service')
449+
# Individual 6
450+
self.assertEqual(recs[6].id_number, 6)
451+
self.assertEqual(recs[6].customer_class, 0)
452+
self.assertEqual(recs[6].arrival_date, 28)
453+
self.assertEqual(recs[6].service_start_date, 28)
454+
self.assertEqual(recs[6].service_end_date, 33.5)
455+
self.assertEqual(recs[6].record_type, 'service')
456+
457+
# Second scenario
458+
N = ciw.create_network(
459+
arrival_distributions={
460+
'Class 0': [ciw.dists.Deterministic(7)],
461+
'Class 1': [ciw.dists.Deterministic(13)]
462+
},
463+
service_distributions={
464+
'Class 0': [ciw.dists.Deterministic(5.5)],
465+
'Class 1': [ciw.dists.Deterministic(1.5)]
466+
},
467+
number_of_servers=[[[1, 20.3], [0, 22], [1, 100]]],
468+
priority_classes=({
469+
'Class 0': 1,
470+
'Class 1': 0
471+
}, ['continue'])
472+
)
473+
474+
Q = ciw.Simulation(N)
475+
Q.simulate_until_max_time(35)
476+
477+
recs = Q.get_all_records()
478+
# Individual 1
479+
self.assertEqual(recs[0].id_number, 1)
480+
self.assertEqual(recs[0].customer_class, 0)
481+
self.assertEqual(recs[0].arrival_date, 7)
482+
self.assertEqual(recs[0].service_start_date, 7)
483+
self.assertEqual(recs[0].service_end_date, 12.5)
484+
self.assertEqual(recs[0].record_type, 'service')
485+
# Individual 2
486+
self.assertEqual(recs[1].id_number, 2)
487+
self.assertEqual(recs[1].customer_class, 1)
488+
self.assertEqual(recs[1].arrival_date, 13)
489+
self.assertEqual(recs[1].service_start_date, 13)
490+
self.assertEqual(recs[1].service_end_date, 14.5)
491+
self.assertEqual(recs[1].record_type, 'service')
492+
# Individual 3
493+
self.assertEqual(recs[2].id_number, 3)
494+
self.assertEqual(recs[2].customer_class, 0)
495+
self.assertEqual(recs[2].arrival_date, 14)
496+
self.assertEqual(recs[2].service_start_date, 14.5)
497+
self.assertEqual(recs[2].service_end_date, 20)
498+
self.assertEqual(recs[2].record_type, 'service')
499+
# Individual 5
500+
self.assertEqual(recs[3].id_number, 5)
501+
self.assertEqual(recs[3].customer_class, 1)
502+
self.assertEqual(recs[3].arrival_date, 26)
503+
self.assertEqual(recs[3].service_start_date, 26)
504+
self.assertEqual(recs[3].service_end_date, 27.5)
505+
self.assertEqual(recs[3].record_type, 'service')
506+
# Individual 4's interrupted service
507+
self.assertEqual(recs[4].id_number, 4)
508+
self.assertEqual(recs[4].customer_class, 0)
509+
self.assertEqual(recs[4].arrival_date, 21)
510+
self.assertEqual(recs[4].service_start_date, 22)
511+
self.assertEqual(recs[4].record_type, 'interrupted service')
512+
# Individual 4's resumed service
513+
self.assertEqual(recs[5].id_number, 4)
514+
self.assertEqual(recs[5].customer_class, 0)
515+
self.assertEqual(recs[5].arrival_date, 21)
516+
self.assertEqual(recs[5].service_start_date, 27.5)
517+
self.assertEqual(recs[5].service_end_date, 29)
518+
self.assertEqual(recs[5].record_type, 'service')
519+
# Individual 6
520+
self.assertEqual(recs[6].id_number, 6)
521+
self.assertEqual(recs[6].customer_class, 0)
522+
self.assertEqual(recs[6].arrival_date, 28)
523+
self.assertEqual(recs[6].service_start_date, 29)
524+
self.assertEqual(recs[6].service_end_date, 34.5)
525+
self.assertEqual(recs[6].record_type, 'service')
526+

0 commit comments

Comments
 (0)