Skip to content

Commit

Permalink
adds a new method for simulate_until_max_customers
Browse files Browse the repository at this point in the history
  • Loading branch information
geraintpalmer committed Dec 4, 2024
1 parent 2db3522 commit 60b80f6
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
History
-------

+ **3.2.4 (2024-12-04)**
+ Adds a new method for the `simulate_until_max_customers: "Complete" simulates until a specific number of completed customer journeys; while "Finish" simulates until a specific number of customers have reached the exit node (through bailking or reneging).

+ **3.2.3 (2024-10-15)**
+ Allow some numerical imprecision in the PMF probability sums. This allows for very large arrays of probabilities and use of Pandas and Numpy to define probabilities.

Expand Down
4 changes: 2 additions & 2 deletions ciw/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def __repr__(self):
"""
return "Node %s" % self.id_number

def accept(self, next_individual):
def accept(self, next_individual, completed=False):
"""
Accepts a new customer to the queue:
- remove previous exit date and blockage status
Expand Down Expand Up @@ -654,7 +654,7 @@ def renege(self):
self.write_reneging_record(reneging_individual)
self.reset_individual_attributes(reneging_individual)
self.simulation.statetracker.change_state_renege(self, next_node, reneging_individual, False)
next_node.accept(reneging_individual)
next_node.accept(reneging_individual, completed=False)
self.release_blocked_individual()

def get_reneging_date(self, ind):
Expand Down
13 changes: 10 additions & 3 deletions ciw/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,18 @@ def simulate_until_max_time(self, max_simulation_time, progress_bar=False):
self.progress_bar.close()

def simulate_until_max_customers(
self, max_customers, progress_bar=False, method="Finish"
self, max_customers, progress_bar=False, method="Complete"
):
"""
Runs the simulation until max_customers is reached:
- Method: Complete
Simulates until max_customers has reached the Exit Node after
completing their journey
- Method: Finish
Simulates until max_customers has reached the Exit Node
Simulates until max_customers has reached the Exit Node whether
they have completed their journey or not (included baulkers and
renegers)
- Method: Arrive
Simulates until max_customers have spawned at the Arrival Node
- Method: Accept
Expand All @@ -292,8 +297,10 @@ def simulate_until_max_customers(
if progress_bar:
self.progress_bar = tqdm.tqdm(total=max_customers)

if method == "Finish":
if method == "Complete":
check = lambda: self.nodes[-1].number_of_completed_individuals
elif method == "Finish":
check = lambda: self.nodes[-1].number_of_individuals
elif method == "Arrive":
check = lambda: self.nodes[0].number_of_individuals
elif method == "Accept":
Expand Down
39 changes: 28 additions & 11 deletions ciw/tests/test_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,29 +194,43 @@ def test_simulate_until_max_time_with_pbar_method(self):
self.assertEqual(Q.progress_bar.total, 150)
self.assertEqual(Q.progress_bar.n, 150)

def test_simulate_until_max_customers_finish(self):
def test_simulate_until_max_customers(self):
N = ciw.create_network(
arrival_distributions=[ciw.dists.Exponential(1.0)],
service_distributions=[ciw.dists.Exponential(0.5)],
number_of_servers=[1],
routing=[[0.0]],
queue_capacities=[3],
)
# Test default method, 'Finish'
# Test default method, 'Complete'
ciw.seed(2)
Q1 = ciw.Simulation(N)
Q1.simulate_until_max_customers(10, method="Finish")
self.assertEqual(Q1.nodes[-1].number_of_completed_individuals, 10)
completed_records = Q1.get_all_records(only=["service"])
Q = ciw.Simulation(N)
Q.simulate_until_max_customers(10)
self.assertEqual(Q.nodes[-1].number_of_completed_individuals, 10)
self.assertEqual(Q.nodes[-1].number_of_individuals, 34)
completed_records = Q.get_all_records(only=["service"])
self.assertEqual(len(completed_records), 10)

# Test 'Complete' method
ciw.seed(2)
Q0 = ciw.Simulation(N)
Q0.simulate_until_max_customers(10, method="Complete")
self.assertEqual(Q0.nodes[-1].number_of_completed_individuals, 10)
self.assertEqual(Q0.nodes[-1].number_of_individuals, 34)
completed_records = Q0.get_all_records(only=["service"])
self.assertEqual(len(completed_records), 10)

next_active_node = Q0.find_next_active_node()
end_time_complete = next_active_node.next_event_date

# Test 'Finish' method
ciw.seed(2)
Q2 = ciw.Simulation(N)
Q2.simulate_until_max_customers(10)
self.assertEqual(Q2.nodes[-1].number_of_completed_individuals, 10)
Q2.simulate_until_max_customers(10, method="Finish")
self.assertEqual(Q2.nodes[-1].number_of_completed_individuals, 3)
self.assertEqual(Q2.nodes[-1].number_of_individuals, 10)
completed_records = Q2.get_all_records(only=["service"])
self.assertEqual(len(completed_records), 10)
self.assertEqual(len(completed_records), 3)

next_active_node = Q2.find_next_active_node()
end_time_finish = next_active_node.next_event_date
Expand Down Expand Up @@ -248,8 +262,11 @@ def test_simulate_until_max_customers_finish(self):
next_active_node = Q4.find_next_active_node()
end_time_accept = next_active_node.next_event_date

# Assert that finish time of finish > accept > arrive
self.assertGreater(end_time_finish, end_time_accept)
# Assert that finish time of complete > accept > finish > arrive
self.assertGreater(end_time_complete, end_time_accept)
self.assertGreater(end_time_complete, end_time_finish)
self.assertGreater(end_time_complete, end_time_arrive)
self.assertGreater(end_time_accept, end_time_finish)
self.assertGreater(end_time_accept, end_time_arrive)
self.assertGreater(end_time_finish, end_time_arrive)

Expand Down
2 changes: 1 addition & 1 deletion ciw/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "3.2.3"
__version__ = "3.2.4"
19 changes: 15 additions & 4 deletions docs/Guides/Simulation/sim_numcusts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ This can be done using the :code:`simulate_until_max_customers` method.
The method takes in a variable :code:`max_customers`.
There are three methods of counting customers:

- :code:`'Finish'`: Simulates until :code:`max_customers` has reached the Exit Node.
- :code:`'Complete'`: Simulates until :code:`max_customers` has reached the Exit Node due to completing their journey through the system.
- :code:`'Finish'`: Simulates until :code:`max_customers` has reached the Exit Node, regardless if the customer reaches there without completing their journey, for example by :ref:`baulking <baulking-functions>` or :ref:`reneging <reneging-customers>`.
- :code:`'Arrive'`: Simulates until :code:`max_customers` have spawned at the Arrival Node.
- :code:`'Accept'`: Simulates until :code:`max_customers` have been spawned and accepted (not rejected) at the Arrival Node.

The method of counting customers is specified with the optional keyword argument :code:`method`. The default value is is :code:`'Finish'`.
The method of counting customers is specified with the optional keyword argument :code:`method`. The default value is is :code:`'Complete'`.

Consider an :ref:`M/M/1/3 <kendall-notation>` queue::

Expand All @@ -25,15 +26,25 @@ Consider an :ref:`M/M/1/3 <kendall-notation>` queue::
... queue_capacities=[3]
... )

To simulate until 30 customers have finished service::

To simulate until 30 customers have completed::

>>> ciw.seed(1)
>>> Q = ciw.Simulation(N)
>>> Q.simulate_until_max_customers(30, method='Finish')
>>> Q.simulate_until_max_customers(30, method='Complete')
>>> recs = Q.get_all_records()
>>> len([r for r in recs if r.record_type=="service"])
30

To simulate until 30 customers have finished::

>>> ciw.seed(1)
>>> Q = ciw.Simulation(N)
>>> Q.simulate_until_max_customers(30, method='Finish')
>>> recs = Q.get_all_records()
>>> len(recs)
30

To simulate until 30 customers have arrived::

>>> ciw.seed(1)
Expand Down

0 comments on commit 60b80f6

Please sign in to comment.