From f20f41d219354a3786ac13dfe402fbff67454e0b Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Fri, 3 Mar 2023 19:32:02 +0200 Subject: [PATCH 01/19] #52 - Implement one iteration of the experiment run --- .../control_flow_manager.py | 8 + .../events_performance_experiments.py | 64 ++ .../probability_distributions.py | 14 + .../simulation_properties_parser.py | 13 +- bpdfr_simulation_engine/simulation_setup.py | 2 +- .../events/input/batch-example-end-task.bpmn | 189 ++++++ .../input/batch-example-with-batch.json | 627 ++++++++++++++++++ .../events/perform_events_runner.py | 87 +++ performance_exp/events/testing_files.py | 11 + 9 files changed, 1012 insertions(+), 3 deletions(-) create mode 100644 bpdfr_simulation_engine/events_performance_experiments.py create mode 100644 performance_exp/events/input/batch-example-end-task.bpmn create mode 100644 performance_exp/events/input/batch-example-with-batch.json create mode 100644 performance_exp/events/perform_events_runner.py create mode 100644 performance_exp/events/testing_files.py diff --git a/bpdfr_simulation_engine/control_flow_manager.py b/bpdfr_simulation_engine/control_flow_manager.py index 0ad8e47..121a983 100644 --- a/bpdfr_simulation_engine/control_flow_manager.py +++ b/bpdfr_simulation_engine/control_flow_manager.py @@ -95,6 +95,11 @@ def is_start_or_end_event(self): def is_event(self): return self.type in [BPMN.START_EVENT, BPMN.END_EVENT, BPMN.INTERMEDIATE_EVENT] + def delete_incoming_flow(self, flow_id): + "Delete incoming flow if it exists" + if flow_id in self.incoming_flows: + self.incoming_flows.remove(flow_id) + class ProcessState: def __init__(self, bpmn_graph): @@ -171,6 +176,9 @@ def add_bpmn_element(self, element_id, element_info): self.from_name[element_info.name] = element_id self.nodes_bitset[element_id] = (1 << len(self.element_info)) + def remove_incoming_flow(self, element_id, flow_id): + self.element_info[element_id].delete_incoming_flow(flow_id) + def add_flow_arc(self, flow_id, source_id, target_id): for node_id in [source_id, target_id]: if node_id not in self.element_info: diff --git a/bpdfr_simulation_engine/events_performance_experiments.py b/bpdfr_simulation_engine/events_performance_experiments.py new file mode 100644 index 0000000..f1314f8 --- /dev/null +++ b/bpdfr_simulation_engine/events_performance_experiments.py @@ -0,0 +1,64 @@ +import os +import string + +from bpdfr_simulation_engine.control_flow_manager import ( + BPMN, + EVENT_TYPE, + BPMNGraph, + ElementInfo, +) + + +def _add_events(bpmn_graph: BPMNGraph, sequence_flow_list, element_probability): + # add events + num_inserted_events = 5 + + # keep track of the added events to the model + inserted_events_logs: string = "" + + for i in range(num_inserted_events): + # the flow arc to be replaced + to_be_deleted_flow_arc = sequence_flow_list[i] + to_be_deleted_flow_arc_id = to_be_deleted_flow_arc.attrib["id"] + + source_id = to_be_deleted_flow_arc.attrib["sourceRef"] + target_id = to_be_deleted_flow_arc.attrib["targetRef"] + + new_event_id = f"event_{i}" + + # log info about the newly added event + inserted_events_logs += f"{new_event_id} between {source_id} and {target_id}.\n" + + # add intermediate event + bpmn_graph.add_bpmn_element( + new_event_id, + ElementInfo( + BPMN.INTERMEDIATE_EVENT, + new_event_id, + new_event_id, + EVENT_TYPE.TIMER, + ), + ) + + # remove previously referenced sequence flow in the target activity + bpmn_graph.remove_incoming_flow(target_id, to_be_deleted_flow_arc_id) + + # add sequence flow to and from the newly added event + seq_flow_to_event = f"{source_id}_{new_event_id}" + bpmn_graph.add_flow_arc(seq_flow_to_event, source_id, new_event_id) + seq_flow_from_event = f"{new_event_id}_{target_id}" + bpmn_graph.add_flow_arc(seq_flow_from_event, new_event_id, target_id) + + # duplicate the gateway probability if it existed before + if source_id in element_probability: + element_probability[source_id].update_candidate_key( + to_be_deleted_flow_arc_id, seq_flow_to_event + ) + + # save logs about events + logs_path = os.path.join( + os.path.dirname(__file__), + f"../performance_exp/events/input/events_logs_{num_inserted_events}.txt", + ) + with open(logs_path, "w+") as logs_file: + logs_file.write(inserted_events_logs) diff --git a/bpdfr_simulation_engine/probability_distributions.py b/bpdfr_simulation_engine/probability_distributions.py index d7f536a..97a56a7 100644 --- a/bpdfr_simulation_engine/probability_distributions.py +++ b/bpdfr_simulation_engine/probability_distributions.py @@ -175,6 +175,20 @@ def get_multiple_flows(self): selected.append((self.candidates_list[i], None)) return selected if len(selected) > 0 else [(self.get_outgoing_flow(), None)] + def update_candidate_key(self, old_candidate_id, new_candidate_id): + """ + After inserting an event, we need to change the candidate id in the list of candidates + This needs to happen due to the fact that we removed one gateway and inserted a new one instead + """ + + try: + candidate_index = self.candidates_list.index(old_candidate_id) + except ValueError: + # in case candidate is not on the list, not updating anything + return + + self.candidates_list[candidate_index] = new_candidate_id + def random_uniform(start, end): return numpy.random.uniform(low=start, high=end) diff --git a/bpdfr_simulation_engine/simulation_properties_parser.py b/bpdfr_simulation_engine/simulation_properties_parser.py index e13a6eb..7be5a35 100644 --- a/bpdfr_simulation_engine/simulation_properties_parser.py +++ b/bpdfr_simulation_engine/simulation_properties_parser.py @@ -11,6 +11,7 @@ BPMNGraph, ElementInfo, ) +from bpdfr_simulation_engine.events_performance_experiments import _add_events from bpdfr_simulation_engine.prioritisation import AllPriorityRules from bpdfr_simulation_engine.prioritisation_parser import PrioritisationParser from bpdfr_simulation_engine.probability_distributions import * @@ -234,7 +235,11 @@ def parse_arrival_branching_probabilities(arrival_json, gateway_json): return element_distribution -def parse_simulation_model(bpmn_path): +def parse_simulation_model(bpmn_path, element_probability={}): + """ + element_probability parameter is only used for adding probability for newly inserted sequence flows + when inserting events + """ tree = ET.parse(bpmn_path) root = tree.getroot() @@ -276,7 +281,8 @@ def parse_simulation_model(bpmn_path): # Counting incoming/outgoing flow arcs to handle cases of multiple in/out arcs simultaneously pending_flow_arcs = list() - for flow_arc in process.findall("xmlns:sequenceFlow", bpmn_element_ns): + sequence_flow_list = process.findall("xmlns:sequenceFlow", bpmn_element_ns) + for flow_arc in sequence_flow_list: # Fixing the case in which a task may have multiple incoming/outgoing flow-arcs pending_flow_arcs.append(flow_arc) if flow_arc.attrib["sourceRef"] in elements_map: @@ -332,6 +338,9 @@ def parse_simulation_model(bpmn_path): target_id = join_gateways[target_id] bpmn_graph.add_flow_arc(flow_arc.attrib["id"], source_id, target_id) + # TODO: call this only when running experiments + _add_events(bpmn_graph, sequence_flow_list, element_probability) + bpmn_graph.encode_or_join_predecesors() bpmn_graph.validate_model() return bpmn_graph diff --git a/bpdfr_simulation_engine/simulation_setup.py b/bpdfr_simulation_engine/simulation_setup.py index 04aaedf..909e2ea 100644 --- a/bpdfr_simulation_engine/simulation_setup.py +++ b/bpdfr_simulation_engine/simulation_setup.py @@ -20,7 +20,7 @@ def __init__(self, bpmn_path, json_path, is_event_added_to_log, total_cases): self.event_distibution, self.batch_processing, self.case_attributes, self.prioritisation_rules \ = parse_json_sim_parameters(json_path) - self.bpmn_graph = parse_simulation_model(bpmn_path) + self.bpmn_graph = parse_simulation_model(bpmn_path, self.element_probability) self.bpmn_graph.set_additional_fields_from_json(self.element_probability, \ self.task_resource, self.event_distibution, self.batch_processing) if not self.arrival_calendar: diff --git a/performance_exp/events/input/batch-example-end-task.bpmn b/performance_exp/events/input/batch-example-end-task.bpmn new file mode 100644 index 0000000..9a4b123 --- /dev/null +++ b/performance_exp/events/input/batch-example-end-task.bpmn @@ -0,0 +1,189 @@ + + + + + + + + + + + sid-E469684F-C09F-4A8B-A916-E9927BA15372 + + + + + + + + + + + sid-6FD4FFD3-5784-4D33-9509-234EAB886930 + sid-10E6C62E-2CBD-476A-976B-B862156F5DEC + + + + + + + + + + + sid-9E95A790-241E-4629-8D67-E9A2CE55E3DC + sid-FF95F9DA-C10F-455B-B2FC-FBC1C270C0B4 + + + + + + + + + + + sid-E469684F-C09F-4A8B-A916-E9927BA15372 + sid-FA2D48D3-A316-4C2F-90DB-C2390990D727 + + + + + + + + + + + Flow_0ah4nto + Flow_0plakw8 + + + + + + + + + + + + + + + + + + + + + + + + + + + sid-FA2D48D3-A316-4C2F-90DB-C2390990D727 + sid-6FD4FFD3-5784-4D33-9509-234EAB886930 + sid-9E95A790-241E-4629-8D67-E9A2CE55E3DC + + + + + + + + sid-FF95F9DA-C10F-455B-B2FC-FBC1C270C0B4 + sid-10E6C62E-2CBD-476A-976B-B862156F5DEC + Flow_0ah4nto + + + Flow_0plakw8 + Flow_1xezdfv + + + + Flow_1xezdfv + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/performance_exp/events/input/batch-example-with-batch.json b/performance_exp/events/input/batch-example-with-batch.json new file mode 100644 index 0000000..1707041 --- /dev/null +++ b/performance_exp/events/input/batch-example-with-batch.json @@ -0,0 +1,627 @@ +{ + "resource_profiles": [ + { + "id": "sid-generic-resource", + "name": "Generic_Resource", + "resource_list": [ + { + "id": "Resource_1", + "name": "Resource_1", + "cost_per_hour": 1, + "amount": 1, + "calendar": "247timetable", + "assigned_tasks": [ + "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "sid-503A048D-6344-446A-8D67-172B164CF8FA" + ] + }, + { + "id": "Resource_2", + "name": "Resource_2", + "cost_per_hour": 1, + "amount": 1, + "calendar": "247timetable", + "assigned_tasks": [ + "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "sid-503A048D-6344-446A-8D67-172B164CF8FA" + ] + }, + { + "id": "Resource_3", + "name": "Resource_3", + "cost_per_hour": 1, + "amount": 1, + "calendar": "247timetable", + "assigned_tasks": [ + "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "sid-503A048D-6344-446A-8D67-172B164CF8FA" + ] + }, + { + "id": "Resource_4", + "name": "Resource_4", + "cost_per_hour": 1, + "amount": 1, + "calendar": "247timetable", + "assigned_tasks": [ + "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "sid-503A048D-6344-446A-8D67-172B164CF8FA" + ] + }, + { + "id": "Resource_5", + "name": "Resource_5", + "cost_per_hour": 1, + "amount": 1, + "calendar": "247timetable", + "assigned_tasks": [ + "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "sid-503A048D-6344-446A-8D67-172B164CF8FA" + ] + } + ] + } + ], + "arrival_time_distribution": { + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + "arrival_time_calendar": [ + { + "from": "MONDAY", + "to": "SUNDAY", + "beginTime": "00:00:00.000", + "endTime": "23:59:59.999" + } + ], + "gateway_branching_probabilities": [ + { + "gateway_id": "sid-6B518C80-2B96-4C95-B6DE-F9E4A75FF191", + "probabilities": [ + { + "path_id": "sid-6FD4FFD3-5784-4D33-9509-234EAB886930", + "value": 0.3 + }, + { + "path_id": "sid-9E95A790-241E-4629-8D67-E9A2CE55E3DC", + "value": 0.7 + } + ] + } + ], + "task_resource_distribution": [ + { + "task_id": "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "resources": [ + { + "resource_id": "Resource_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_3", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_4", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_5", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + } + ] + }, + { + "task_id": "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "resources": [ + { + "resource_id": "Resource_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_3", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_4", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_5", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + } + ] + }, + { + "task_id": "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "resources": [ + { + "resource_id": "Resource_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_3", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_4", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_5", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + } + ] + }, + { + "task_id": "sid-503A048D-6344-446A-8D67-172B164CF8FA", + "resources": [ + { + "resource_id": "Resource_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_3", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_4", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_5", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + } + ] + }, + { + "task_id": "Activity_0ngxjs9", + "resources": [ + { + "resource_id": "Resource_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_3", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_4", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_5", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + } + ] + } + ], + "resource_calendars": [ + { + "id": "247timetable", + "name": "247timetable", + "time_periods": [ + { + "from": "MONDAY", + "to": "SUNDAY", + "beginTime": "00:00:00.000", + "endTime": "23:59:59.999" + } + ] + } + ], + "batch_processing": [ + { + "task_id": "sid-503A048D-6344-446A-8D67-172B164CF8FA", + "type": "Sequential", + "batch_frequency": 1.0, + "size_distrib": [ + { + "key": "1", + "value": 6 + }, + { + "key": "3", + "value": 35 + }, + { + "key": "4", + "value": 3 + } + ], + "duration_distrib": [ + { + "key": "3", + "value": 0.8 + } + ], + "firing_rules": [ + [ + { + "attribute": "size", + "comparison": "=", + "value": 3 + } + ] + ] + } + ], + "case_attributes": [ + { + "name": "client_type", + "type": "discrete", + "values": [ + { + "key": "REGULAR", + "value": 0.8 + }, + { + "key": "BUSINESS", + "value": 0.2 + } + ] + }, + { + "name": "loan_amount", + "type": "continuous", + "values": { + "distribution_name": "fix", + "distribution_params": [ + { + "value": 240 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + } + } + ], + "event_distribution": [ + { + "event_id": "event_0", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 900.0 + } + ] + }, + { + "event_id": "event_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 900.0 + } + ] + }, + { + "event_id": "event_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 900.0 + } + ] + } + ] +} \ No newline at end of file diff --git a/performance_exp/events/perform_events_runner.py b/performance_exp/events/perform_events_runner.py new file mode 100644 index 0000000..4a76508 --- /dev/null +++ b/performance_exp/events/perform_events_runner.py @@ -0,0 +1,87 @@ +import datetime +import json +import os + +from bpdfr_simulation_engine.simulation_properties_parser import ( + EVENT_DISTRIBUTION_SECTION, +) +from performance_exp.events.testing_files import process_files +from testing_scripts.bimp_diff_sim_tests import run_diff_res_simulation + + +def main(): + run_one_iteration() + + os._exit(0) + + +def run_one_iteration(): + model_info = process_files["events_exp"] + initial_json_path = os.path.join(os.path.dirname(__file__), model_info["json"]) + bpmn_path = os.path.join(os.path.dirname(__file__), model_info["bpmn"]) + demo_stats = os.path.join(os.path.dirname(__file__), model_info["demo_stats"]) + sim_log = os.path.join(os.path.dirname(__file__), model_info["sim_log"]) + new_json_path = _setup_event_distribution(initial_json_path, 5) + + print("--------------------------------------------------------------------------") + print( + "Starting Simulation of demo example (%d instances)" + % (model_info["total_cases"]) + ) + print("--------------------------------------------------------------------------") + start = datetime.datetime.now() + + _, diff_sim_result = run_diff_res_simulation( + model_info["start_datetime"], + model_info["total_cases"], + bpmn_path, + new_json_path, + demo_stats, + sim_log, + True, + ) + print( + "Simulation Time: %s" + % str( + datetime.timedelta( + seconds=(datetime.datetime.now() - start).total_seconds() + ) + ) + ) + diff_sim_result.print_simulation_results() + + +def _setup_event_distribution(initial_json_path, num_events: int): + """ + Create event distribution for all events that will be later added to the model + Save the newly created json in new location to keep track of the setup for simulations + """ + + event_distr_list = [ + { + "event_id": f"event_{index}", + "distribution_name": "fix", + "distribution_params": [{"value": 900.0}], + } + for index in range(num_events) + ] + + with open(initial_json_path, "r") as f: + json_dict = json.load(f) + + json_dict[EVENT_DISTRIBUTION_SECTION] = event_distr_list + + # save modified json as a new file specifying the number of experiment + # in order to keep track of run experiments + folder_loc = os.path.dirname(initial_json_path) + new_filename = f"events_exp_{num_events}.json" + new_json_path = os.path.join(folder_loc, new_filename) + + with open(new_json_path, "w+") as json_file: + json.dump(json_dict, json_file) + + return new_json_path + + +if __name__ == "__main__": + main() diff --git a/performance_exp/events/testing_files.py b/performance_exp/events/testing_files.py new file mode 100644 index 0000000..2b45644 --- /dev/null +++ b/performance_exp/events/testing_files.py @@ -0,0 +1,11 @@ +process_files = { + "events_exp": { + "bpmn": "input/batch-example-end-task.bpmn", + "json": "input/batch-example-with-batch.json", + "sim_log": "results/demo_example.csv", + "demo_stats": "results/demo_stats.csv", + "start_datetime": "2022-06-21 13:22:30.035185+03:00", + "total_cases": 100, + "disc_params": [60, 0.1, 0.9, 0.6, True], + } +} From 40b6f8530077675cf93d6284386fa67731e9194e Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Sat, 4 Mar 2023 19:28:31 +0200 Subject: [PATCH 02/19] #52 - Add conditions for adding events to the model, remove obsolete outgoing flow of the source element --- .../control_flow_manager.py | 8 ++++ .../events_performance_experiments.py | 18 +++++--- bpdfr_simulation_engine/simulation_engine.py | 3 +- .../simulation_properties_parser.py | 13 ++++-- bpdfr_simulation_engine/simulation_setup.py | 20 ++++++--- .../events/perform_events_runner.py | 43 ++++++++++--------- performance_exp/events/testing_files.py | 7 +-- 7 files changed, 75 insertions(+), 37 deletions(-) diff --git a/bpdfr_simulation_engine/control_flow_manager.py b/bpdfr_simulation_engine/control_flow_manager.py index 121a983..2afbd46 100644 --- a/bpdfr_simulation_engine/control_flow_manager.py +++ b/bpdfr_simulation_engine/control_flow_manager.py @@ -100,6 +100,11 @@ def delete_incoming_flow(self, flow_id): if flow_id in self.incoming_flows: self.incoming_flows.remove(flow_id) + def delete_outgoing_flow(self, flow_id): + "Delete outgoing flow if it exists" + if flow_id in self.outgoing_flows: + self.outgoing_flows.remove(flow_id) + class ProcessState: def __init__(self, bpmn_graph): @@ -179,6 +184,9 @@ def add_bpmn_element(self, element_id, element_info): def remove_incoming_flow(self, element_id, flow_id): self.element_info[element_id].delete_incoming_flow(flow_id) + def remove_outgoing_flow(self, element_id, flow_id): + self.element_info[element_id].delete_outgoing_flow(flow_id) + def add_flow_arc(self, flow_id, source_id, target_id): for node_id in [source_id, target_id]: if node_id not in self.element_info: diff --git a/bpdfr_simulation_engine/events_performance_experiments.py b/bpdfr_simulation_engine/events_performance_experiments.py index f1314f8..5ebb041 100644 --- a/bpdfr_simulation_engine/events_performance_experiments.py +++ b/bpdfr_simulation_engine/events_performance_experiments.py @@ -9,9 +9,16 @@ ) -def _add_events(bpmn_graph: BPMNGraph, sequence_flow_list, element_probability): - # add events - num_inserted_events = 5 +def _add_events( + bpmn_graph: BPMNGraph, + sequence_flow_list, + element_probability, + num_inserted_events: int, +): + if len(sequence_flow_list) < num_inserted_events: + raise ValueError( + "A number of inserted events should not be higher than a number of sequence flows present in the BPMN model." + ) # keep track of the added events to the model inserted_events_logs: string = "" @@ -40,7 +47,8 @@ def _add_events(bpmn_graph: BPMNGraph, sequence_flow_list, element_probability): ), ) - # remove previously referenced sequence flow in the target activity + # remove previously referenced sequence flow in the source & target activity + bpmn_graph.remove_outgoing_flow(source_id, to_be_deleted_flow_arc_id) bpmn_graph.remove_incoming_flow(target_id, to_be_deleted_flow_arc_id) # add sequence flow to and from the newly added event @@ -58,7 +66,7 @@ def _add_events(bpmn_graph: BPMNGraph, sequence_flow_list, element_probability): # save logs about events logs_path = os.path.join( os.path.dirname(__file__), - f"../performance_exp/events/input/events_logs_{num_inserted_events}.txt", + f"../performance_exp/events/input/{num_inserted_events}_events_logs.txt", ) with open(logs_path, "w+") as logs_file: logs_file.write(inserted_events_logs) diff --git a/bpdfr_simulation_engine/simulation_engine.py b/bpdfr_simulation_engine/simulation_engine.py index 4364c0c..bdbd717 100644 --- a/bpdfr_simulation_engine/simulation_engine.py +++ b/bpdfr_simulation_engine/simulation_engine.py @@ -644,9 +644,10 @@ def run_simulation( log_out_path=None, starting_at=None, is_event_added_to_log=False, + num_generated_events=None, ): diffsim_info = SimDiffSetup( - bpmn_path, json_path, is_event_added_to_log, total_cases + bpmn_path, json_path, is_event_added_to_log, total_cases, num_generated_events ) if not diffsim_info: diff --git a/bpdfr_simulation_engine/simulation_properties_parser.py b/bpdfr_simulation_engine/simulation_properties_parser.py index 7be5a35..729a2da 100644 --- a/bpdfr_simulation_engine/simulation_properties_parser.py +++ b/bpdfr_simulation_engine/simulation_properties_parser.py @@ -235,7 +235,9 @@ def parse_arrival_branching_probabilities(arrival_json, gateway_json): return element_distribution -def parse_simulation_model(bpmn_path, element_probability={}): +def parse_simulation_model( + bpmn_path, element_probability={}, num_generated_events=None +): """ element_probability parameter is only used for adding probability for newly inserted sequence flows when inserting events @@ -338,8 +340,13 @@ def parse_simulation_model(bpmn_path, element_probability={}): target_id = join_gateways[target_id] bpmn_graph.add_flow_arc(flow_arc.attrib["id"], source_id, target_id) - # TODO: call this only when running experiments - _add_events(bpmn_graph, sequence_flow_list, element_probability) + if num_generated_events != None: + _add_events( + bpmn_graph, + sequence_flow_list, + element_probability, + num_generated_events, + ) bpmn_graph.encode_or_join_predecesors() bpmn_graph.validate_model() diff --git a/bpdfr_simulation_engine/simulation_setup.py b/bpdfr_simulation_engine/simulation_setup.py index 909e2ea..ce72435 100644 --- a/bpdfr_simulation_engine/simulation_setup.py +++ b/bpdfr_simulation_engine/simulation_setup.py @@ -8,11 +8,21 @@ from bpdfr_simulation_engine.control_flow_manager import ProcessState, ElementInfo, BPMN from bpdfr_simulation_engine.probability_distributions import generate_number_from from bpdfr_simulation_engine.resource_calendar import RCalendar -from bpdfr_simulation_engine.simulation_properties_parser import parse_simulation_model, parse_json_sim_parameters +from bpdfr_simulation_engine.simulation_properties_parser import ( + parse_simulation_model, + parse_json_sim_parameters, +) class SimDiffSetup: - def __init__(self, bpmn_path, json_path, is_event_added_to_log, total_cases): + def __init__( + self, + bpmn_path, + json_path, + is_event_added_to_log, + total_cases, + num_generated_events, + ): self.process_name = ntpath.basename(bpmn_path).split(".")[0] self.start_datetime = datetime.datetime.now(pytz.utc) @@ -20,9 +30,9 @@ def __init__(self, bpmn_path, json_path, is_event_added_to_log, total_cases): self.event_distibution, self.batch_processing, self.case_attributes, self.prioritisation_rules \ = parse_json_sim_parameters(json_path) - self.bpmn_graph = parse_simulation_model(bpmn_path, self.element_probability) - self.bpmn_graph.set_additional_fields_from_json(self.element_probability, \ - self.task_resource, self.event_distibution, self.batch_processing) + self.bpmn_graph = parse_simulation_model( + bpmn_path, self.element_probability, num_generated_events + ) if not self.arrival_calendar: self.arrival_calendar = self.find_arrival_calendar() diff --git a/performance_exp/events/perform_events_runner.py b/performance_exp/events/perform_events_runner.py index 4a76508..d0e71f6 100644 --- a/performance_exp/events/perform_events_runner.py +++ b/performance_exp/events/perform_events_runner.py @@ -10,28 +10,34 @@ def main(): - run_one_iteration() + for index in range(5): + run_one_iteration(9) os._exit(0) -def run_one_iteration(): +def run_one_iteration(num_inserted_events: int): model_info = process_files["events_exp"] initial_json_path = os.path.join(os.path.dirname(__file__), model_info["json"]) bpmn_path = os.path.join(os.path.dirname(__file__), model_info["bpmn"]) - demo_stats = os.path.join(os.path.dirname(__file__), model_info["demo_stats"]) - sim_log = os.path.join(os.path.dirname(__file__), model_info["sim_log"]) - new_json_path = _setup_event_distribution(initial_json_path, 5) + demo_stats = os.path.join( + os.path.dirname(__file__), + model_info["results_folder"], + f"{num_inserted_events}_stats.csv", + ) + sim_log = os.path.join( + os.path.dirname(__file__), + model_info["results_folder"], + f"{num_inserted_events}_logs.csv", + ) + new_json_path = _setup_event_distribution(initial_json_path, num_inserted_events) print("--------------------------------------------------------------------------") - print( - "Starting Simulation of demo example (%d instances)" - % (model_info["total_cases"]) - ) + print(f"Starting Simulation with {num_inserted_events} inserted events") print("--------------------------------------------------------------------------") start = datetime.datetime.now() - _, diff_sim_result = run_diff_res_simulation( + _, _ = run_diff_res_simulation( model_info["start_datetime"], model_info["total_cases"], bpmn_path, @@ -39,16 +45,13 @@ def run_one_iteration(): demo_stats, sim_log, True, + num_inserted_events, ) - print( - "Simulation Time: %s" - % str( - datetime.timedelta( - seconds=(datetime.datetime.now() - start).total_seconds() - ) - ) - ) - diff_sim_result.print_simulation_results() + simulation_time = (datetime.datetime.now() - start).total_seconds() + print(f"Simulation Time: {str(simulation_time)}") + print(f"Simulation Time: {simulation_time}") + + # diff_sim_result.print_simulation_results() def _setup_event_distribution(initial_json_path, num_events: int): @@ -74,7 +77,7 @@ def _setup_event_distribution(initial_json_path, num_events: int): # save modified json as a new file specifying the number of experiment # in order to keep track of run experiments folder_loc = os.path.dirname(initial_json_path) - new_filename = f"events_exp_{num_events}.json" + new_filename = f"{num_events}_events_exp.json" new_json_path = os.path.join(folder_loc, new_filename) with open(new_json_path, "w+") as json_file: diff --git a/performance_exp/events/testing_files.py b/performance_exp/events/testing_files.py index 2b45644..6e9e666 100644 --- a/performance_exp/events/testing_files.py +++ b/performance_exp/events/testing_files.py @@ -2,10 +2,11 @@ "events_exp": { "bpmn": "input/batch-example-end-task.bpmn", "json": "input/batch-example-with-batch.json", - "sim_log": "results/demo_example.csv", - "demo_stats": "results/demo_stats.csv", + "results_folder": "results", + # "sim_log": "results/demo_example.csv", + # "demo_stats": "results/demo_stats.csv", "start_datetime": "2022-06-21 13:22:30.035185+03:00", - "total_cases": 100, + "total_cases": 1000, "disc_params": [60, 0.1, 0.9, 0.6, True], } } From e02d7ebe6df551ada5502a5bbcb1364816c4ef83 Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Sun, 5 Mar 2023 18:51:21 +0200 Subject: [PATCH 03/19] #52 - Return back mistakenly removed code --- bpdfr_simulation_engine/simulation_setup.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bpdfr_simulation_engine/simulation_setup.py b/bpdfr_simulation_engine/simulation_setup.py index ce72435..c571e1d 100644 --- a/bpdfr_simulation_engine/simulation_setup.py +++ b/bpdfr_simulation_engine/simulation_setup.py @@ -33,6 +33,12 @@ def __init__( self.bpmn_graph = parse_simulation_model( bpmn_path, self.element_probability, num_generated_events ) + self.bpmn_graph.set_additional_fields_from_json( + self.element_probability, + self.task_resource, + self.event_distibution, + self.batch_processing + ) if not self.arrival_calendar: self.arrival_calendar = self.find_arrival_calendar() From d75fcf846ef6346196f743f1b668d53640ae0161 Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Sun, 5 Mar 2023 18:52:59 +0200 Subject: [PATCH 04/19] #52 - Show the plot of results, run experiment for the same number of inserted events five times --- .../events/perform_events_runner.py | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/performance_exp/events/perform_events_runner.py b/performance_exp/events/perform_events_runner.py index d0e71f6..30ae745 100644 --- a/performance_exp/events/perform_events_runner.py +++ b/performance_exp/events/perform_events_runner.py @@ -2,6 +2,8 @@ import json import os +import matplotlib.pyplot as plt +import numpy as np from bpdfr_simulation_engine.simulation_properties_parser import ( EVENT_DISTRIBUTION_SECTION, ) @@ -10,10 +12,34 @@ def main(): - for index in range(5): - run_one_iteration(9) - - os._exit(0) + total_number_of_events_to_add = 9 + number_of_events_to_add_list = range(1, 1 + total_number_of_events_to_add) + print(number_of_events_to_add_list) + sim_time_list = [] + for index in number_of_events_to_add_list: + print( + "--------------------------------------------------------------------------" + ) + print(f"Starting Simulation with {index} inserted events") + print( + "--------------------------------------------------------------------------" + ) + + same_index_sim_time_list = [] + for iter_num in range(0, 5): + sim_time = run_one_iteration(index) + print(f"iter {iter_num}: {sim_time}") + same_index_sim_time_list.append(sim_time) + + median_sim_time = np.median(same_index_sim_time_list) + sim_time_list.append(median_sim_time) + + print(sim_time_list) + xpoints = np.array(number_of_events_to_add_list) + ypoints = np.array(sim_time_list) + + plt.plot(xpoints, ypoints) + plt.show() def run_one_iteration(num_inserted_events: int): @@ -32,9 +58,6 @@ def run_one_iteration(num_inserted_events: int): ) new_json_path = _setup_event_distribution(initial_json_path, num_inserted_events) - print("--------------------------------------------------------------------------") - print(f"Starting Simulation with {num_inserted_events} inserted events") - print("--------------------------------------------------------------------------") start = datetime.datetime.now() _, _ = run_diff_res_simulation( @@ -48,9 +71,8 @@ def run_one_iteration(num_inserted_events: int): num_inserted_events, ) simulation_time = (datetime.datetime.now() - start).total_seconds() - print(f"Simulation Time: {str(simulation_time)}") - print(f"Simulation Time: {simulation_time}") + return simulation_time # diff_sim_result.print_simulation_results() From 2881f44751efebaac3842c530141688368c81d6d Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Mon, 6 Mar 2023 10:59:57 +0200 Subject: [PATCH 05/19] #52 - Save final results in a file --- .../events/perform_events_runner.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/performance_exp/events/perform_events_runner.py b/performance_exp/events/perform_events_runner.py index 30ae745..66cda89 100644 --- a/performance_exp/events/perform_events_runner.py +++ b/performance_exp/events/perform_events_runner.py @@ -13,9 +13,10 @@ def main(): total_number_of_events_to_add = 9 - number_of_events_to_add_list = range(1, 1 + total_number_of_events_to_add) + number_of_events_to_add_list = range(0, 1 + total_number_of_events_to_add) print(number_of_events_to_add_list) sim_time_list = [] + median_results_str = "" for index in number_of_events_to_add_list: print( "--------------------------------------------------------------------------" @@ -31,10 +32,25 @@ def main(): print(f"iter {iter_num}: {sim_time}") same_index_sim_time_list.append(sim_time) - median_sim_time = np.median(same_index_sim_time_list) + median_sim_time = np.mean(same_index_sim_time_list) sim_time_list.append(median_sim_time) + # collect results for writing them as txt later + median_results_str += f"{index},{median_sim_time}\n" + + # save received results (number_inserted_events, simulation_time) as a separate file + model_info = process_files["events_exp"] + demo_stats = os.path.join( + os.path.dirname(__file__), + model_info["results_folder"], + f"all_simulation_times.csv", + ) + with open(demo_stats, "w+") as logs_file: + logs_file.write(median_results_str) + print(sim_time_list) + + # show plot of the results xpoints = np.array(number_of_events_to_add_list) ypoints = np.array(sim_time_list) From 1b9d815769d3efa01c37c85778254b61a6112b5e Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Mon, 6 Mar 2023 11:05:41 +0200 Subject: [PATCH 06/19] #52 - Provide the default parameter for number_generated_events --- bpdfr_simulation_engine/simulation_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bpdfr_simulation_engine/simulation_setup.py b/bpdfr_simulation_engine/simulation_setup.py index c571e1d..501fcd5 100644 --- a/bpdfr_simulation_engine/simulation_setup.py +++ b/bpdfr_simulation_engine/simulation_setup.py @@ -21,7 +21,7 @@ def __init__( json_path, is_event_added_to_log, total_cases, - num_generated_events, + num_generated_events=None, ): self.process_name = ntpath.basename(bpmn_path).split(".")[0] self.start_datetime = datetime.datetime.now(pytz.utc) From 364d006c17052d51e916fd7108f8c51a7baea5d3 Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Mon, 6 Mar 2023 11:39:12 +0200 Subject: [PATCH 07/19] #52 - Push missed file, load files for a test once --- performance_exp/events/perform_events_runner.py | 8 ++++---- testing_scripts/bimp_diff_sim_tests.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/performance_exp/events/perform_events_runner.py b/performance_exp/events/perform_events_runner.py index 66cda89..329007a 100644 --- a/performance_exp/events/perform_events_runner.py +++ b/performance_exp/events/perform_events_runner.py @@ -12,6 +12,8 @@ def main(): + model_info = process_files["events_exp"] + total_number_of_events_to_add = 9 number_of_events_to_add_list = range(0, 1 + total_number_of_events_to_add) print(number_of_events_to_add_list) @@ -28,7 +30,7 @@ def main(): same_index_sim_time_list = [] for iter_num in range(0, 5): - sim_time = run_one_iteration(index) + sim_time = run_one_iteration(index, model_info) print(f"iter {iter_num}: {sim_time}") same_index_sim_time_list.append(sim_time) @@ -39,7 +41,6 @@ def main(): median_results_str += f"{index},{median_sim_time}\n" # save received results (number_inserted_events, simulation_time) as a separate file - model_info = process_files["events_exp"] demo_stats = os.path.join( os.path.dirname(__file__), model_info["results_folder"], @@ -58,8 +59,7 @@ def main(): plt.show() -def run_one_iteration(num_inserted_events: int): - model_info = process_files["events_exp"] +def run_one_iteration(num_inserted_events: int, model_info): initial_json_path = os.path.join(os.path.dirname(__file__), model_info["json"]) bpmn_path = os.path.join(os.path.dirname(__file__), model_info["bpmn"]) demo_stats = os.path.join( diff --git a/testing_scripts/bimp_diff_sim_tests.py b/testing_scripts/bimp_diff_sim_tests.py index 4b6366f..9291390 100644 --- a/testing_scripts/bimp_diff_sim_tests.py +++ b/testing_scripts/bimp_diff_sim_tests.py @@ -59,9 +59,9 @@ def run_bimp_simulation(model_file_path, results_file_path, simulation_log, # return load_bimp_simulation_results(results_file_path, simulation_log) -def run_diff_res_simulation(start_date, total_cases, bpmn_model, json_sim_params, out_stats_csv_path, out_log_csv_path, is_event_added_to_log = False): +def run_diff_res_simulation(start_date, total_cases, bpmn_model, json_sim_params, out_stats_csv_path, out_log_csv_path, is_event_added_to_log = False, num_generated_events=None): s_t = datetime.datetime.now() - run_simulation(bpmn_model, json_sim_params, total_cases, out_stats_csv_path, out_log_csv_path, start_date, is_event_added_to_log) + run_simulation(bpmn_model, json_sim_params, total_cases, out_stats_csv_path, out_log_csv_path, start_date, is_event_added_to_log, num_generated_events) sim_time = (datetime.datetime.now() - s_t).total_seconds() # print((datetime.datetime.now() - s_t).total_seconds()) # print("DiffSim Execution Times: %s" % From 059d935003224f592fc0f64ce4e29bc4234912d3 Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Mon, 6 Mar 2023 14:38:15 +0200 Subject: [PATCH 08/19] #52 - Prettify the script for experiments --- .../events_performance_experiments.py | 2 +- .../events/perform_events_runner.py | 60 +++++++++---------- performance_exp/events/testing_files.py | 3 +- 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/bpdfr_simulation_engine/events_performance_experiments.py b/bpdfr_simulation_engine/events_performance_experiments.py index 5ebb041..3891caf 100644 --- a/bpdfr_simulation_engine/events_performance_experiments.py +++ b/bpdfr_simulation_engine/events_performance_experiments.py @@ -66,7 +66,7 @@ def _add_events( # save logs about events logs_path = os.path.join( os.path.dirname(__file__), - f"../performance_exp/events/input/{num_inserted_events}_events_logs.txt", + f"../performance_exp/events/generated_events/{num_inserted_events}_events_logs.txt", ) with open(logs_path, "w+") as logs_file: logs_file.write(inserted_events_logs) diff --git a/performance_exp/events/perform_events_runner.py b/performance_exp/events/perform_events_runner.py index 329007a..2f534c8 100644 --- a/performance_exp/events/perform_events_runner.py +++ b/performance_exp/events/perform_events_runner.py @@ -1,4 +1,3 @@ -import datetime import json import os @@ -7,26 +6,22 @@ from bpdfr_simulation_engine.simulation_properties_parser import ( EVENT_DISTRIBUTION_SECTION, ) -from performance_exp.events.testing_files import process_files +from performance_exp.events.testing_files import process_files_setup from testing_scripts.bimp_diff_sim_tests import run_diff_res_simulation def main(): - model_info = process_files["events_exp"] + model_info = process_files_setup["bpi2012"] + total_number_of_events_to_add = model_info["number_of_added_events"] - total_number_of_events_to_add = 9 number_of_events_to_add_list = range(0, 1 + total_number_of_events_to_add) - print(number_of_events_to_add_list) + sim_time_list = [] median_results_str = "" for index in number_of_events_to_add_list: - print( - "--------------------------------------------------------------------------" - ) + print("-------------------------------------------") print(f"Starting Simulation with {index} inserted events") - print( - "--------------------------------------------------------------------------" - ) + print("-------------------------------------------") same_index_sim_time_list = [] for iter_num in range(0, 5): @@ -34,15 +29,17 @@ def main(): print(f"iter {iter_num}: {sim_time}") same_index_sim_time_list.append(sim_time) - median_sim_time = np.mean(same_index_sim_time_list) + # TODO: should we use mean or median? + median_sim_time = np.median(same_index_sim_time_list) + print(f"median: {median_sim_time}") + sim_time_list.append(median_sim_time) # collect results for writing them as txt later median_results_str += f"{index},{median_sim_time}\n" # save received results (number_inserted_events, simulation_time) as a separate file - demo_stats = os.path.join( - os.path.dirname(__file__), + demo_stats = _get_abs_path( model_info["results_folder"], f"all_simulation_times.csv", ) @@ -51,32 +48,23 @@ def main(): print(sim_time_list) - # show plot of the results - xpoints = np.array(number_of_events_to_add_list) - ypoints = np.array(sim_time_list) - - plt.plot(xpoints, ypoints) - plt.show() + # show plot of the relationship: number of added events - simulation time + _show_plot(np.array(number_of_events_to_add_list), np.array(sim_time_list)) def run_one_iteration(num_inserted_events: int, model_info): - initial_json_path = os.path.join(os.path.dirname(__file__), model_info["json"]) - bpmn_path = os.path.join(os.path.dirname(__file__), model_info["bpmn"]) - demo_stats = os.path.join( - os.path.dirname(__file__), - model_info["results_folder"], - f"{num_inserted_events}_stats.csv", + initial_json_path = _get_abs_path(model_info["json"]) + bpmn_path = _get_abs_path(model_info["bpmn"]) + demo_stats = _get_abs_path( + model_info["results_folder"], f"{num_inserted_events}_stats.csv" ) - sim_log = os.path.join( - os.path.dirname(__file__), + sim_log = _get_abs_path( model_info["results_folder"], f"{num_inserted_events}_logs.csv", ) new_json_path = _setup_event_distribution(initial_json_path, num_inserted_events) - start = datetime.datetime.now() - - _, _ = run_diff_res_simulation( + simulation_time, _ = run_diff_res_simulation( model_info["start_datetime"], model_info["total_cases"], bpmn_path, @@ -86,7 +74,6 @@ def run_one_iteration(num_inserted_events: int, model_info): True, num_inserted_events, ) - simulation_time = (datetime.datetime.now() - start).total_seconds() return simulation_time # diff_sim_result.print_simulation_results() @@ -124,5 +111,14 @@ def _setup_event_distribution(initial_json_path, num_events: int): return new_json_path +def _show_plot(xpoints, ypoints): + plt.plot(xpoints, ypoints) + plt.show() + + +def _get_abs_path(*args): + return os.path.join(os.path.dirname(__file__), *args) + + if __name__ == "__main__": main() diff --git a/performance_exp/events/testing_files.py b/performance_exp/events/testing_files.py index 6e9e666..7c9e707 100644 --- a/performance_exp/events/testing_files.py +++ b/performance_exp/events/testing_files.py @@ -3,10 +3,9 @@ "bpmn": "input/batch-example-end-task.bpmn", "json": "input/batch-example-with-batch.json", "results_folder": "results", - # "sim_log": "results/demo_example.csv", - # "demo_stats": "results/demo_stats.csv", "start_datetime": "2022-06-21 13:22:30.035185+03:00", "total_cases": 1000, "disc_params": [60, 0.1, 0.9, 0.6, True], + "number_of_added_events": 9, # should be equal to the number of sequence flows in the BPMN model } } From 1ab682579be54a9b4202c60476bd340edb384465 Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Mon, 6 Mar 2023 18:29:59 +0200 Subject: [PATCH 09/19] #52 - Adjust the visualised plot --- .../events/perform_events_runner.py | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/performance_exp/events/perform_events_runner.py b/performance_exp/events/perform_events_runner.py index 2f534c8..06927ac 100644 --- a/performance_exp/events/perform_events_runner.py +++ b/performance_exp/events/perform_events_runner.py @@ -11,7 +11,8 @@ def main(): - model_info = process_files_setup["bpi2012"] + model_name = "events_exp" + model_info = process_files_setup[model_name] total_number_of_events_to_add = model_info["number_of_added_events"] number_of_events_to_add_list = range(0, 1 + total_number_of_events_to_add) @@ -49,7 +50,12 @@ def main(): print(sim_time_list) # show plot of the relationship: number of added events - simulation time - _show_plot(np.array(number_of_events_to_add_list), np.array(sim_time_list)) + _show_plot( + np.array(number_of_events_to_add_list), + np.array(sim_time_list), + model_name, + model_info["total_cases"], + ) def run_one_iteration(num_inserted_events: int, model_info): @@ -111,8 +117,18 @@ def _setup_event_distribution(initial_json_path, num_events: int): return new_json_path -def _show_plot(xpoints, ypoints): +def _show_plot(xpoints, ypoints, model_name, num_of_instances): + # give a general title + plt.title(f"Model: {model_name}, instances: {num_of_instances}") + + # name axis + plt.xlabel("Number of added events") + plt.ylabel("Simulation time, sec") + + # provide data points plt.plot(xpoints, ypoints) + + # visualize plt.show() From 52f9f189742ecdae249de2587172003a4f7bfa0b Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Mon, 6 Mar 2023 19:05:52 +0200 Subject: [PATCH 10/19] #52 - Preserve folder structure, update process files setup --- performance_exp/events/generated_events/.gitkeep | 0 performance_exp/events/input/results/.gitkeep | 0 performance_exp/events/testing_files.py | 5 +++++ 3 files changed, 5 insertions(+) create mode 100644 performance_exp/events/generated_events/.gitkeep create mode 100644 performance_exp/events/input/results/.gitkeep diff --git a/performance_exp/events/generated_events/.gitkeep b/performance_exp/events/generated_events/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/performance_exp/events/input/results/.gitkeep b/performance_exp/events/input/results/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/performance_exp/events/testing_files.py b/performance_exp/events/testing_files.py index 7c9e707..eac93e8 100644 --- a/performance_exp/events/testing_files.py +++ b/performance_exp/events/testing_files.py @@ -2,6 +2,11 @@ "events_exp": { "bpmn": "input/batch-example-end-task.bpmn", "json": "input/batch-example-with-batch.json", + "results_folder": "input/results", + "start_datetime": "2022-06-21 13:22:30.035185+03:00", + "total_cases": 1000, + "disc_params": [60, 0.1, 0.9, 0.6, True], + "number_of_added_events": 9, # should be equal to the number of sequence flows in the BPMN model "results_folder": "results", "start_datetime": "2022-06-21 13:22:30.035185+03:00", "total_cases": 1000, From 4e09a372a6e6ae7ad2fad9c9dc95d9d4295fa64a Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Mon, 6 Mar 2023 19:18:47 +0200 Subject: [PATCH 11/19] #53 - Run experiments with adding diifferent number of priority levels --- .../perform_prioritisation_runner.py | 200 ++++++ .../batch-example-end-task.bpmn | 189 ++++++ .../batch-example-with-batch.json | 595 ++++++++++++++++++ .../simple_example/results/.gitkeep | 0 .../prioritisation/testing_files.py | 10 + 5 files changed, 994 insertions(+) create mode 100644 performance_exp/prioritisation/perform_prioritisation_runner.py create mode 100644 performance_exp/prioritisation/simple_example/batch-example-end-task.bpmn create mode 100644 performance_exp/prioritisation/simple_example/batch-example-with-batch.json create mode 100644 performance_exp/prioritisation/simple_example/results/.gitkeep create mode 100644 performance_exp/prioritisation/testing_files.py diff --git a/performance_exp/prioritisation/perform_prioritisation_runner.py b/performance_exp/prioritisation/perform_prioritisation_runner.py new file mode 100644 index 0000000..595c56f --- /dev/null +++ b/performance_exp/prioritisation/perform_prioritisation_runner.py @@ -0,0 +1,200 @@ +import json +import os + +import matplotlib.pyplot as plt +import numpy as np + +from bpdfr_simulation_engine.simulation_properties_parser import ( + PRIORITISATION_RULES_SECTION, +) +from performance_exp.prioritisation.testing_files import process_files_setup +from testing_scripts.bimp_diff_sim_tests import run_diff_res_simulation + + +def main(): + model_name = "simple_example" + model_info = process_files_setup[model_name] + max_number_prioritisation_rules = 6 + + prioritisation_rules_to_add_list = range(0, 1 + max_number_prioritisation_rules) + # run_one_iteration(1, model_info) + + sim_time_list = [] + median_results_str = "" + for index in prioritisation_rules_to_add_list: + print("-------------------------------------------") + print( + f"Starting Simulation with {index} priority levels in the simulation scenario" + ) + print("-------------------------------------------") + + same_index_sim_time_list = [] + for iter_num in range(0, 5): + sim_time = run_one_iteration(index, model_info) + print(f"iter {iter_num}: {sim_time}") + same_index_sim_time_list.append(sim_time) + + # TODO: should we use mean or median? + median_sim_time = np.mean(same_index_sim_time_list) + print(f"median: {median_sim_time}") + + sim_time_list.append(median_sim_time) + + # collect results for writing them as txt later + median_results_str += f"{index},{median_sim_time}\n" + + # save received results (number_priority_levels, simulation_time) as a separate file + demo_stats = _get_abs_path( + model_info["results_folder"], + f"all_simulation_times.csv", + ) + with open(demo_stats, "w+") as logs_file: + logs_file.write(median_results_str) + + print(sim_time_list) + + # show plot of the relationship: number of priority levels - simulation time + _show_plot( + np.array(prioritisation_rules_to_add_list), + np.array(sim_time_list), + model_name, + model_info["total_cases"], + ) + + +def run_one_iteration(num_prioritisation_rules: int, model_info): + initial_json_path = _get_abs_path(model_info["json"]) + bpmn_path = _get_abs_path(model_info["bpmn"]) + demo_stats = _get_abs_path( + model_info["results_folder"], f"{num_prioritisation_rules}_stats.csv" + ) + sim_log = _get_abs_path( + model_info["results_folder"], + f"{num_prioritisation_rules}_logs.csv", + ) + new_json_path = _setup_sim_scenario(initial_json_path, num_prioritisation_rules) + + simulation_time, _ = run_diff_res_simulation( + model_info["start_datetime"], + model_info["total_cases"], + bpmn_path, + new_json_path, + demo_stats, + sim_log, + False, # no events in the log + None, # no added events + ) + + return simulation_time + # diff_sim_result.print_simulation_results() + + +def _setup_sim_scenario(initial_json_path, num_prioritisation_rules: int): + """ + Create case-based prioritisation rules based on the required number (num_prioritisation_rules) + Save the newly created json in new location to keep track of the setup for simulations + """ + + prioritisation_rules = [ + { + "priority_level": 1, + "rules": [ + [ + { + "attribute": "loan_amount", + "comparison": "in", + "value": [2000, "inf"], + } + ], + ], + }, + { + "priority_level": 2, + "rules": [ + [ + { + "attribute": "loan_amount", + "comparison": "in", + "value": [1500, 2000], + } + ], + ], + }, + { + "priority_level": 3, + "rules": [ + [ + { + "attribute": "loan_amount", + "comparison": "in", + "value": [1000, 1500], + } + ], + ], + }, + { + "priority_level": 4, + "rules": [ + [ + { + "attribute": "loan_amount", + "comparison": "in", + "value": [800, 1000], + } + ], + ], + }, + { + "priority_level": 5, + "rules": [ + [{"attribute": "loan_amount", "comparison": "in", "value": [500, 800]}], + ], + }, + { + "priority_level": 6, + "rules": [ + [{"attribute": "loan_amount", "comparison": "in", "value": [0, 500]}], + ], + }, + ] + + with open(initial_json_path, "r") as f: + json_dict = json.load(f) + + json_dict[PRIORITISATION_RULES_SECTION] = prioritisation_rules[ + :num_prioritisation_rules + ] + + # save modified json as a new file specifying the number of experiment + # in order to keep track of run experiments + folder_loc = os.path.dirname(initial_json_path) + new_filename = f"{num_prioritisation_rules}_prioritisation_rules_exp.json" + new_json_path = os.path.join(folder_loc, new_filename) + + with open(new_json_path, "w+") as json_file: + json.dump(json_dict, json_file) + + return new_json_path + + +def _show_plot(xpoints, ypoints, model_name, num_of_instances): + # give a general title + plt.title(f"Model: {model_name}, instances: {num_of_instances}") + + # name axis + plt.xlabel("Number of priority levels") + plt.ylabel("Simulation time, sec") + + # provide data points + plt.plot(xpoints, ypoints) + + # visualize + plt.show() + + +def _get_abs_path(*args): + return os.path.join(os.path.dirname(__file__), *args) + + +if __name__ == "__main__": + main() diff --git a/performance_exp/prioritisation/simple_example/batch-example-end-task.bpmn b/performance_exp/prioritisation/simple_example/batch-example-end-task.bpmn new file mode 100644 index 0000000..9a4b123 --- /dev/null +++ b/performance_exp/prioritisation/simple_example/batch-example-end-task.bpmn @@ -0,0 +1,189 @@ + + + + + + + + + + + sid-E469684F-C09F-4A8B-A916-E9927BA15372 + + + + + + + + + + + sid-6FD4FFD3-5784-4D33-9509-234EAB886930 + sid-10E6C62E-2CBD-476A-976B-B862156F5DEC + + + + + + + + + + + sid-9E95A790-241E-4629-8D67-E9A2CE55E3DC + sid-FF95F9DA-C10F-455B-B2FC-FBC1C270C0B4 + + + + + + + + + + + sid-E469684F-C09F-4A8B-A916-E9927BA15372 + sid-FA2D48D3-A316-4C2F-90DB-C2390990D727 + + + + + + + + + + + Flow_0ah4nto + Flow_0plakw8 + + + + + + + + + + + + + + + + + + + + + + + + + + + sid-FA2D48D3-A316-4C2F-90DB-C2390990D727 + sid-6FD4FFD3-5784-4D33-9509-234EAB886930 + sid-9E95A790-241E-4629-8D67-E9A2CE55E3DC + + + + + + + + sid-FF95F9DA-C10F-455B-B2FC-FBC1C270C0B4 + sid-10E6C62E-2CBD-476A-976B-B862156F5DEC + Flow_0ah4nto + + + Flow_0plakw8 + Flow_1xezdfv + + + + Flow_1xezdfv + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/performance_exp/prioritisation/simple_example/batch-example-with-batch.json b/performance_exp/prioritisation/simple_example/batch-example-with-batch.json new file mode 100644 index 0000000..ed52bf4 --- /dev/null +++ b/performance_exp/prioritisation/simple_example/batch-example-with-batch.json @@ -0,0 +1,595 @@ +{ + "resource_profiles": [ + { + "id": "sid-generic-resource", + "name": "Generic_Resource", + "resource_list": [ + { + "id": "Resource_1", + "name": "Resource_1", + "cost_per_hour": 1, + "amount": 1, + "calendar": "247timetable", + "assigned_tasks": [ + "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "sid-503A048D-6344-446A-8D67-172B164CF8FA" + ] + }, + { + "id": "Resource_2", + "name": "Resource_2", + "cost_per_hour": 1, + "amount": 1, + "calendar": "247timetable", + "assigned_tasks": [ + "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "sid-503A048D-6344-446A-8D67-172B164CF8FA" + ] + }, + { + "id": "Resource_3", + "name": "Resource_3", + "cost_per_hour": 1, + "amount": 1, + "calendar": "247timetable", + "assigned_tasks": [ + "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "sid-503A048D-6344-446A-8D67-172B164CF8FA" + ] + }, + { + "id": "Resource_4", + "name": "Resource_4", + "cost_per_hour": 1, + "amount": 1, + "calendar": "247timetable", + "assigned_tasks": [ + "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "sid-503A048D-6344-446A-8D67-172B164CF8FA" + ] + }, + { + "id": "Resource_5", + "name": "Resource_5", + "cost_per_hour": 1, + "amount": 1, + "calendar": "247timetable", + "assigned_tasks": [ + "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "sid-503A048D-6344-446A-8D67-172B164CF8FA" + ] + } + ] + } + ], + "arrival_time_distribution": { + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + "arrival_time_calendar": [ + { + "from": "MONDAY", + "to": "SUNDAY", + "beginTime": "00:00:00.000", + "endTime": "23:59:59.999" + } + ], + "gateway_branching_probabilities": [ + { + "gateway_id": "sid-6B518C80-2B96-4C95-B6DE-F9E4A75FF191", + "probabilities": [ + { + "path_id": "sid-6FD4FFD3-5784-4D33-9509-234EAB886930", + "value": 0.3 + }, + { + "path_id": "sid-9E95A790-241E-4629-8D67-E9A2CE55E3DC", + "value": 0.7 + } + ] + } + ], + "task_resource_distribution": [ + { + "task_id": "sid-4B24111F-B305-4608-9E12-744B47C44D0D", + "resources": [ + { + "resource_id": "Resource_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_3", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_4", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_5", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + } + ] + }, + { + "task_id": "sid-D048D99D-F549-43B8-8ACB-5AE153B12B0F", + "resources": [ + { + "resource_id": "Resource_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_3", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_4", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_5", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + } + ] + }, + { + "task_id": "sid-02577CBF-ABA3-4EFD-9480-E1DFCF238B1C", + "resources": [ + { + "resource_id": "Resource_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_3", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_4", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_5", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + } + ] + }, + { + "task_id": "sid-503A048D-6344-446A-8D67-172B164CF8FA", + "resources": [ + { + "resource_id": "Resource_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_3", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_4", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_5", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + } + ] + }, + { + "task_id": "Activity_0ngxjs9", + "resources": [ + { + "resource_id": "Resource_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_3", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_4", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + }, + { + "resource_id": "Resource_5", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 120 + }, + { + "value": 0 + }, + { + "value": 1 + } + ] + } + ] + } + ], + "resource_calendars": [ + { + "id": "247timetable", + "name": "247timetable", + "time_periods": [ + { + "from": "MONDAY", + "to": "SUNDAY", + "beginTime": "00:00:00.000", + "endTime": "23:59:59.999" + } + ] + } + ], + "batch_processing": [], + "case_attributes": [ + { + "name": "client_type", + "type": "discrete", + "values": [ + { + "key": "REGULAR", + "value": 0.8 + }, + { + "key": "BUSINESS", + "value": 0.2 + } + ] + }, + { + "name": "loan_amount", + "type": "continuous", + "values": { + "distribution_name": "expon", + "distribution_params": [ + { + "value": 1000 + }, + { + "value": 500.0 + }, + { + "value": 0 + }, + { + "value": 5400 + } + ] + } + } + ], + "event_distribution": [ + { + "event_id": "event_0", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 900.0 + } + ] + }, + { + "event_id": "event_1", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 900.0 + } + ] + }, + { + "event_id": "event_2", + "distribution_name": "fix", + "distribution_params": [ + { + "value": 900.0 + } + ] + } + ] +} \ No newline at end of file diff --git a/performance_exp/prioritisation/simple_example/results/.gitkeep b/performance_exp/prioritisation/simple_example/results/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/performance_exp/prioritisation/testing_files.py b/performance_exp/prioritisation/testing_files.py new file mode 100644 index 0000000..1987140 --- /dev/null +++ b/performance_exp/prioritisation/testing_files.py @@ -0,0 +1,10 @@ +process_files_setup = { + "simple_example": { + "bpmn": "simple_example/batch-example-end-task.bpmn", + "json": "simple_example/batch-example-with-batch.json", + "results_folder": "simple_example/results", + "start_datetime": "2022-06-21 13:22:30.035185+03:00", + "total_cases": 2000, + "disc_params": [60, 0.1, 0.9, 0.6, True], + }, +} From 1b1e287de58c3971ec85d38ecfa8ed4e9a457df7 Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Tue, 7 Mar 2023 16:27:29 +0200 Subject: [PATCH 12/19] #52 - Refactor event runner for performance testing, clarify the parameters for the experiment --- .gitignore | 4 +- .../events/perform_events_runner.py | 42 +++++++++---------- performance_exp/events/testing_files.py | 21 +++++++--- performance_exp/shared_func.py | 22 ++++++++++ 4 files changed, 61 insertions(+), 28 deletions(-) create mode 100644 performance_exp/shared_func.py diff --git a/.gitignore b/.gitignore index 838de26..aa1b7f1 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,6 @@ bimp_test_examples/ *.egg-info .pymon .DS_Store -.vscode/ \ No newline at end of file +.vscode/ +performance_exp/*/*/results +performance_exp/events/generated_events \ No newline at end of file diff --git a/performance_exp/events/perform_events_runner.py b/performance_exp/events/perform_events_runner.py index 06927ac..a765935 100644 --- a/performance_exp/events/perform_events_runner.py +++ b/performance_exp/events/perform_events_runner.py @@ -1,5 +1,6 @@ import json import os +import uuid import matplotlib.pyplot as plt import numpy as np @@ -7,45 +8,42 @@ EVENT_DISTRIBUTION_SECTION, ) from performance_exp.events.testing_files import process_files_setup +from performance_exp.shared_func import get_central_tendency_over_all_iters from testing_scripts.bimp_diff_sim_tests import run_diff_res_simulation def main(): - model_name = "events_exp" + model_name = "events_exp" # "bpi2012_median" model_info = process_files_setup[model_name] total_number_of_events_to_add = model_info["number_of_added_events"] + measure_central_tendency = model_info["measure_central_tendency"] + max_iter_num = model_info["max_iter_num"] + + print(f"Selected log: {model_name}") + print(f"Selected function for central tendency: {measure_central_tendency}") number_of_events_to_add_list = range(0, 1 + total_number_of_events_to_add) sim_time_list = [] - median_results_str = "" + + # file for saving received results (number_inserted_events, simulation_time) + final_plot_results = _get_abs_path( + model_info["results_folder"], + f"all_simulation_times_{uuid.uuid4()}.csv", + ) + for index in number_of_events_to_add_list: print("-------------------------------------------") print(f"Starting Simulation with {index} inserted events") print("-------------------------------------------") - same_index_sim_time_list = [] - for iter_num in range(0, 5): - sim_time = run_one_iteration(index, model_info) - print(f"iter {iter_num}: {sim_time}") - same_index_sim_time_list.append(sim_time) - - # TODO: should we use mean or median? - median_sim_time = np.median(same_index_sim_time_list) - print(f"median: {median_sim_time}") - + median_sim_time = get_central_tendency_over_all_iters( + max_iter_num, run_one_iteration, index, model_info, measure_central_tendency + ) sim_time_list.append(median_sim_time) - # collect results for writing them as txt later - median_results_str += f"{index},{median_sim_time}\n" - - # save received results (number_inserted_events, simulation_time) as a separate file - demo_stats = _get_abs_path( - model_info["results_folder"], - f"all_simulation_times.csv", - ) - with open(demo_stats, "w+") as logs_file: - logs_file.write(median_results_str) + with open(final_plot_results, "a") as plot_file: + plot_file.write(f"{index},{median_sim_time}\n") print(sim_time_list) diff --git a/performance_exp/events/testing_files.py b/performance_exp/events/testing_files.py index eac93e8..be6f6eb 100644 --- a/performance_exp/events/testing_files.py +++ b/performance_exp/events/testing_files.py @@ -1,4 +1,7 @@ -process_files = { +import numpy as np + + +process_files_setup = { "events_exp": { "bpmn": "input/batch-example-end-task.bpmn", "json": "input/batch-example-with-batch.json", @@ -7,10 +10,18 @@ "total_cases": 1000, "disc_params": [60, 0.1, 0.9, 0.6, True], "number_of_added_events": 9, # should be equal to the number of sequence flows in the BPMN model - "results_folder": "results", + "measure_central_tendency": np.median, + "max_iter_num": 5, + }, + "bpi2012_median": { + "bpmn": "bpi2012/BPI_Challenge_2012_W_Two_TS.bpmn", + "json": "bpi2012/sim_scenario.json", + "results_folder": "bpi2012/results", "start_datetime": "2022-06-21 13:22:30.035185+03:00", - "total_cases": 1000, + "total_cases": 13087, # the number taken from the real log file "disc_params": [60, 0.1, 0.9, 0.6, True], - "number_of_added_events": 9, # should be equal to the number of sequence flows in the BPMN model - } + "number_of_added_events": 36, # should be equal to the number of sequence flows in the BPMN model + "measure_central_tendency": np.median, # median since this metric is not impacted by outliers, compared to the mean one + "max_iter_num": 5, + }, } diff --git a/performance_exp/shared_func.py b/performance_exp/shared_func.py new file mode 100644 index 0000000..23c4adb --- /dev/null +++ b/performance_exp/shared_func.py @@ -0,0 +1,22 @@ +def get_central_tendency_over_all_iters( + max_iter_num, run_one_iteration, current_index, model_info, measure_central_tendency +): + """ + Run one iteration n number of times and calculate the central tendency of simulation times + + :param int max_iter_num: Number of iteration to run + :param func run_one_iteration: Function that needs to be run per one iteration + :param int current_index: + :param obj model_info: Description of the input provided by the user + :param func measure_central_tendency: numpy function used for calculating the central tendency (e.g., np.mean, np.median) + """ + same_index_sim_time_list = [] + for iter_num in range(0, max_iter_num): + sim_time = run_one_iteration(current_index, model_info) + print(f"iter {iter_num}: {sim_time}") + same_index_sim_time_list.append(sim_time) + + median_sim_time = measure_central_tendency(same_index_sim_time_list) + print(f"central_tendency: {median_sim_time}") + + return median_sim_time From 8acb5238dc2ed4f8ccc2eaf054ed820f1fc287b5 Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Tue, 7 Mar 2023 16:38:23 +0200 Subject: [PATCH 13/19] #52 - Add bpmn and sim scenario for BPI 2012, events --- performance_exp/events/bpi2012/Archive.zip | Bin 0 -> 8965 bytes performance_exp/events/bpi2012/results/.gitkeep | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 performance_exp/events/bpi2012/Archive.zip create mode 100644 performance_exp/events/bpi2012/results/.gitkeep diff --git a/performance_exp/events/bpi2012/Archive.zip b/performance_exp/events/bpi2012/Archive.zip new file mode 100644 index 0000000000000000000000000000000000000000..795d4274d0903212dd4ecb12b402bb3698fa327d GIT binary patch literal 8965 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 Date: Tue, 7 Mar 2023 19:28:38 +0200 Subject: [PATCH 14/19] #52 - Save fig as a file instead of showing it --- .../events/perform_events_runner.py | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/performance_exp/events/perform_events_runner.py b/performance_exp/events/perform_events_runner.py index a765935..fa84512 100644 --- a/performance_exp/events/perform_events_runner.py +++ b/performance_exp/events/perform_events_runner.py @@ -26,19 +26,27 @@ def main(): sim_time_list = [] + unique_run_id = uuid.uuid4() # file for saving received results (number_inserted_events, simulation_time) final_plot_results = _get_abs_path( model_info["results_folder"], - f"all_simulation_times_{uuid.uuid4()}.csv", + f"{unique_run_id}_plot_data.csv", ) + with open(final_plot_results, "a") as plot_file: + plot_file.write(f"{model_name}\n") + for index in number_of_events_to_add_list: print("-------------------------------------------") print(f"Starting Simulation with {index} inserted events") print("-------------------------------------------") median_sim_time = get_central_tendency_over_all_iters( - max_iter_num, run_one_iteration, index, model_info, measure_central_tendency + max_iter_num, + run_one_iteration, + index, + model_info, + measure_central_tendency, ) sim_time_list.append(median_sim_time) @@ -48,11 +56,16 @@ def main(): print(sim_time_list) # show plot of the relationship: number of added events - simulation time - _show_plot( + plt_path = _get_abs_path( + model_info["results_folder"], + f"{unique_run_id}_plot.png", + ) + _save_plot( np.array(number_of_events_to_add_list), np.array(sim_time_list), model_name, model_info["total_cases"], + plt_path, ) @@ -115,7 +128,7 @@ def _setup_event_distribution(initial_json_path, num_events: int): return new_json_path -def _show_plot(xpoints, ypoints, model_name, num_of_instances): +def _save_plot(xpoints, ypoints, model_name, num_of_instances, plt_path): # give a general title plt.title(f"Model: {model_name}, instances: {num_of_instances}") @@ -126,8 +139,8 @@ def _show_plot(xpoints, ypoints, model_name, num_of_instances): # provide data points plt.plot(xpoints, ypoints) - # visualize - plt.show() + # save as a file + plt.savefig(plt_path, bbox_inches="tight") def _get_abs_path(*args): From 2a7a9a89750b845a0c579444ecc5fc5cbc295378 Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Wed, 8 Mar 2023 16:07:10 +0200 Subject: [PATCH 15/19] #52 - Add new BPI input for events, allow running multiple examples one after another --- performance_exp/events/bpi2012/Archive.zip | Bin 8965 -> 17123 bytes .../events/perform_events_runner.py | 99 ++++++++++-------- performance_exp/events/testing_files.py | 12 +-- 3 files changed, 59 insertions(+), 52 deletions(-) diff --git a/performance_exp/events/bpi2012/Archive.zip b/performance_exp/events/bpi2012/Archive.zip index 795d4274d0903212dd4ecb12b402bb3698fa327d..b420c38bd862175fa71a50dda8d9710197130fb2 100644 GIT binary patch delta 12823 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 delta 4599 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 Date: Wed, 8 Mar 2023 21:33:27 +0200 Subject: [PATCH 16/19] #53 - Extract general method to run the experiment, add bpi setup for prioritisation --- .../events/perform_events_runner.py | 69 +++------------- .../prioritisation/bpi2012/input.zip | Bin 0 -> 49613 bytes .../prioritisation/bpi2012/results/.gitkeep | 0 .../perform_prioritisation_runner.py | 62 +++------------ .../prioritisation/testing_files.py | 24 +++++- performance_exp/shared_func.py | 75 ++++++++++++++++++ 6 files changed, 121 insertions(+), 109 deletions(-) create mode 100644 performance_exp/prioritisation/bpi2012/input.zip create mode 100644 performance_exp/prioritisation/bpi2012/results/.gitkeep diff --git a/performance_exp/events/perform_events_runner.py b/performance_exp/events/perform_events_runner.py index 3e10f72..ddf1e2b 100644 --- a/performance_exp/events/perform_events_runner.py +++ b/performance_exp/events/perform_events_runner.py @@ -1,78 +1,29 @@ import json import os -import uuid import matplotlib.pyplot as plt -import numpy as np from bpdfr_simulation_engine.simulation_properties_parser import ( EVENT_DISTRIBUTION_SECTION, ) from performance_exp.events.testing_files import process_files_setup -from performance_exp.shared_func import get_central_tendency_over_all_iters +from performance_exp.shared_func import ( + run_whole_experiment, +) from testing_scripts.bimp_diff_sim_tests import run_diff_res_simulation def main(): all_models = [ - "bpi2012_median_5", + "events_exp", ] for model_name in all_models: - model_info = process_files_setup[model_name] - total_number_of_events_to_add = model_info["number_of_added_events"] - measure_central_tendency = model_info["measure_central_tendency"] - max_iter_num = model_info["max_iter_num"] - - print(f"Selected log: {model_name}") - print(f"Selected function for central tendency: {measure_central_tendency}") - - number_of_events_to_add_list = range(0, 1 + total_number_of_events_to_add) - - # array to save ordinate (y coordinate) of data points - sim_time_list = [] - - # unique identifier of the experiment run - unique_run_id = uuid.uuid4() - - # file for saving received results (number_inserted_events, simulation_time) - final_plot_results = _get_abs_path( - model_info["results_folder"], - f"{unique_run_id}_plot_data.csv", - ) - - # add name of the model used during this experiment - with open(final_plot_results, "a") as plot_file: - plot_file.write(f"{model_name}\n\n") - - for index in number_of_events_to_add_list: - print("-------------------------------------------") - print(f"Starting Simulation with {index} inserted events") - print("-------------------------------------------") - - median_sim_time = get_central_tendency_over_all_iters( - max_iter_num, - run_one_iteration, - index, - model_info, - measure_central_tendency, - ) - sim_time_list.append(median_sim_time) - - with open(final_plot_results, "a") as plot_file: - plot_file.write(f"{index},{median_sim_time}\n") - - print(sim_time_list) - - # save plot of the relationship: number of added events - simulation time - plt_path = _get_abs_path( - model_info["results_folder"], - f"{unique_run_id}_plot.png", - ) - _save_plot( - np.array(number_of_events_to_add_list), - np.array(sim_time_list), + run_whole_experiment( model_name, - model_info["total_cases"], - plt_path, + process_files_setup[model_name], + "number_of_added_events", + _get_abs_path, + run_one_iteration, + _save_plot, ) diff --git a/performance_exp/prioritisation/bpi2012/input.zip b/performance_exp/prioritisation/bpi2012/input.zip new file mode 100644 index 0000000000000000000000000000000000000000..43aae77f7b9444b5215cecdd9fef302004ee0d4e GIT binary patch literal 49613 zcma&M1yChTv#yJ~```@j?hHCOgS)#g+}#=6-3E7u#o+Gl?(Xh(`M!Pj{r5R1Zp2*? zwX(CKEA!2)=;-d~M_w8n0t4iqpJl1J>c0p7>kkTq7{tQH&e@4kMHvwUdTAZTc=>Dm zW1ZdLK|mqyK|w(NT`T`@3>XlY|1HMaR~(eD7SX4@aEu`G%Wdqt`i7|yfie-p?gc0&X>4< z1pY_5+W#nj`5hF5{QoVVSdV$->q~&%xQ+#8J=0&5ps+(bneQdVpVD z`S0<6bmv?LV7oie_(2=t#SrH1d)(CU%huCA15EM(OH=_T@h2eCqcZsHmo4gE=jP!M z&>CqNRh+ERkT(OMm~dl$FqY<+eaj=@+gMHHlJj`_axm-D)ZSiB)bVoP+WG!Ae-8Ee ze&W+qYTLGJm>xPIQdyL!1j_D#30DZkCVVdDqihF94mr@&6rb@Z;rz5V0!$Mtil zv$NW!ZP|Oqrf1u`x`1kVYdTa3A)$@H+G0k=;K?>oC?rKyBtKo7omBm=?aKOKmSjxK z)swu3aK}pyVVkw<-eg!KOrv0J3%wE#^6-)RGIbT1u*NH(;lY!EX`-%HGs9U+4;utj zCCx-QCM!_YtI-h1@8j00p#|Jf4Zg!upo&!EQUydbuBbPg+`Ej9tNDKJt6l1vzn^p#WAb

tVn2YrR(^7mn!eTZVHC+YC^PAnU>9%%a2 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 Date: Thu, 9 Mar 2023 18:36:31 +0200 Subject: [PATCH 17/19] #52 - Add option for normalising the sim time by the total number of activities --- .../events/perform_events_runner.py | 1 + .../perform_prioritisation_runner.py | 6 +- performance_exp/shared_func.py | 76 ++++++++++++++++++- 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/performance_exp/events/perform_events_runner.py b/performance_exp/events/perform_events_runner.py index ddf1e2b..14dfdea 100644 --- a/performance_exp/events/perform_events_runner.py +++ b/performance_exp/events/perform_events_runner.py @@ -24,6 +24,7 @@ def main(): _get_abs_path, run_one_iteration, _save_plot, + False, ) diff --git a/performance_exp/prioritisation/perform_prioritisation_runner.py b/performance_exp/prioritisation/perform_prioritisation_runner.py index 55e2527..193928c 100644 --- a/performance_exp/prioritisation/perform_prioritisation_runner.py +++ b/performance_exp/prioritisation/perform_prioritisation_runner.py @@ -23,6 +23,7 @@ def main(): _get_abs_path, run_one_iteration, _save_plot, + True, ) @@ -141,13 +142,14 @@ def _setup_sim_scenario(initial_json_path, num_prioritisation_rules: int): return new_json_path -def _save_plot(xpoints, ypoints, model_name, num_of_instances, plt_path): +def _save_plot(xpoints, ypoints, model_name, num_of_instances, plt_path, is_ms=False): # give a general title plt.title(f"Model: {model_name}, instances: {num_of_instances}") # name axis plt.xlabel("Number of priority levels") - plt.ylabel("Simulation time, sec") + time_measure = "ms" if is_ms else "sec" + plt.ylabel(f"Simulation time, {time_measure}") # provide data points plt.plot(xpoints, ypoints) diff --git a/performance_exp/shared_func.py b/performance_exp/shared_func.py index 5f298fe..3cc1686 100644 --- a/performance_exp/shared_func.py +++ b/performance_exp/shared_func.py @@ -1,10 +1,18 @@ +import os import uuid import numpy as np +import pandas as pd def get_central_tendency_over_all_iters( - max_iter_num, run_one_iteration, current_index, model_info, measure_central_tendency + max_iter_num, + run_one_iteration, + current_index, + model_info, + measure_central_tendency, + _get_abs_path, + is_normalised=False, ): """ Run one iteration n number of times and calculate the central tendency of simulation times @@ -14,16 +22,41 @@ def get_central_tendency_over_all_iters( :param int current_index: :param obj model_info: Description of the input provided by the user :param func measure_central_tendency: numpy function used for calculating the central tendency (e.g., np.mean, np.median) + :param bool is_normalised: whether the simulation time is divided by the total number of activities during simulation """ same_index_sim_time_list = [] + + results_folder_path = _get_abs_path(model_info["results_folder"]) + current_log_path = get_log_filepath(results_folder_path, current_index) + normalised_data_path = os.path.join(results_folder_path, "normalised_table.csv") + for iter_num in range(0, max_iter_num): sim_time = run_one_iteration(current_index, model_info) + + if is_normalised: + # in case of normalising, we divide the simulation time + # by the number of activities run during the simulation + sim_time, num_total_activities, norm_sim_time = get_normalised_sim_time( + current_log_path, + sim_time, + normalised_data_path, + current_index, + iter_num, + ) + print(f"iter {iter_num}: {sim_time}") same_index_sim_time_list.append(sim_time) median_sim_time = measure_central_tendency(same_index_sim_time_list) print(f"central_tendency: {median_sim_time}") + if is_normalised: + # append row with statistics for the median value + with open(normalised_data_path, "a") as plot_file: + plot_file.write( + f"{current_index},median,{sim_time},{num_total_activities},{norm_sim_time}\n" + ) + return median_sim_time @@ -34,6 +67,7 @@ def run_whole_experiment( _get_abs_path, run_one_iteration, _save_plot, + is_sim_time_normalised, ): total_number_of_x_values = model_info[metric_under_performance_range_str] measure_central_tendency = ( @@ -64,6 +98,15 @@ def run_whole_experiment( with open(final_plot_results, "a") as plot_file: plot_file.write(f"{model_name}\n\n") + # clear file with normalised data + results_folder_path = _get_abs_path(model_info["results_folder"]) + normalised_data = os.path.join(results_folder_path, "normalised_table.csv") + + with open(normalised_data, "a") as plot_file: + plot_file.write( + f"num_priority_levels,iter,sim_time_sec,num_total_activities,norm_sim_time_ms\n" + ) + for index in number_of_events_to_add_list: print("-------------------------------------------") print(f"Starting Simulation with {index} inserted events") @@ -75,6 +118,8 @@ def run_whole_experiment( index, model_info, measure_central_tendency, + _get_abs_path, + is_sim_time_normalised, ) sim_time_list.append(median_sim_time) @@ -90,8 +135,35 @@ def run_whole_experiment( ) _save_plot( np.array(number_of_events_to_add_list), - np.array(sim_time_list), + sim_time_list, model_name, model_info["total_cases"], plt_path, + is_sim_time_normalised, # use ms if True ) + + +def get_log_filepath(results_folder_path, index): + return os.path.join(results_folder_path, f"{index}_logs.csv") + + +def get_total_num_activities(log_path): + df = pd.read_csv(log_path) + return df.shape[0] # number of rows + + +def get_normalised_sim_time( + current_log_path, sim_time, normalised_data_path, current_index, iter_num +): + num_total_activities = get_total_num_activities(current_log_path) + norm_sim_time = sim_time / num_total_activities # seconds + norm_sim_time = norm_sim_time * 1000 # miliseconds + + # append row with statistics for this current iteration + with open(normalised_data_path, "a") as plot_file: + plot_file.write( + f"{current_index},{iter_num},{sim_time},{num_total_activities},{norm_sim_time}\n" + ) + + # normalised sim_time used as a final one + return norm_sim_time, num_total_activities, norm_sim_time From 3a46689131a6f18b3be1823d5ee7c9961ed3dba5 Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Fri, 17 Mar 2023 19:06:25 +0200 Subject: [PATCH 18/19] #54 - Run performance test for different number of batched task together with the different level of rules' complexity --- .../simulation_properties_parser.py | 4 +- performance_exp/batching/bpi2012/input.zip | Bin 0 -> 17123 bytes .../batching/bpi2012/results/.gitkeep | 0 .../batching/perform_batching_runner.py | 283 ++++++++++++++++++ performance_exp/batching/testing_files.py | 35 +++ 5 files changed, 320 insertions(+), 2 deletions(-) create mode 100644 performance_exp/batching/bpi2012/input.zip create mode 100644 performance_exp/batching/bpi2012/results/.gitkeep create mode 100644 performance_exp/batching/perform_batching_runner.py create mode 100644 performance_exp/batching/testing_files.py diff --git a/bpdfr_simulation_engine/simulation_properties_parser.py b/bpdfr_simulation_engine/simulation_properties_parser.py index 729a2da..c842cdd 100644 --- a/bpdfr_simulation_engine/simulation_properties_parser.py +++ b/bpdfr_simulation_engine/simulation_properties_parser.py @@ -28,7 +28,7 @@ PRIORITISATION_RULES_SECTION = "prioritisation_rules" ARRIVAL_TIME_CALENDAR = "arrival_time_calendar" RESOURCE_CALENDARS = "resource_calendars" - +TASK_RESOURCE_DISTR_SECTON = "task_resource_distribution" def parse_json_sim_parameters(json_path): with open(json_path) as json_file: @@ -39,7 +39,7 @@ def parse_json_sim_parameters(json_path): ) calendars_map = parse_resource_calendars(json_data[RESOURCE_CALENDARS]) task_resource_distribution = parse_task_resource_distributions( - json_data["task_resource_distribution"], res_pool + json_data[TASK_RESOURCE_DISTR_SECTON], res_pool ) element_distribution = parse_arrival_branching_probabilities( diff --git a/performance_exp/batching/bpi2012/input.zip b/performance_exp/batching/bpi2012/input.zip new file mode 100644 index 0000000000000000000000000000000000000000..b420c38bd862175fa71a50dda8d9710197130fb2 GIT binary patch literal 17123 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 literal 0 HcmV?d00001 diff --git a/performance_exp/batching/bpi2012/results/.gitkeep b/performance_exp/batching/bpi2012/results/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/performance_exp/batching/perform_batching_runner.py b/performance_exp/batching/perform_batching_runner.py new file mode 100644 index 0000000..af2ec63 --- /dev/null +++ b/performance_exp/batching/perform_batching_runner.py @@ -0,0 +1,283 @@ +import json +import os +import uuid + +import matplotlib.pyplot as plt +import numpy as np +from bpdfr_simulation_engine.simulation_properties_parser import ( + BATCH_PROCESSING_SECTION, + TASK_RESOURCE_DISTR_SECTON, +) +from mpl_toolkits import mplot3d +from performance_exp.batching.testing_files import process_files_setup +from testing_scripts.bimp_diff_sim_tests import run_diff_res_simulation + + +def main(): + model_name = "bpi2012" + # model_name = "simple_example" + model_info = process_files_setup[model_name] + max_num_tasks_with_batching = model_info["max_num_tasks_with_batching"] + max_iter_num = model_info["max_iter_num"] + max_complexity_level = model_info["max_complexity_level"] + + num_batched_tasks_range = range(0, 1 + max_num_tasks_with_batching) + rules_level_range = range(1, 1 + max_complexity_level) + + # unique identifier of the experiment run + unique_run_id = uuid.uuid4() + + # file for saving received results (number_inserted_events, simulation_time) + final_plot_results = _get_abs_path( + model_info["results_folder"], + f"{unique_run_id}_plot_data.csv", + ) + + # add name of the model used during this experiment + with open(final_plot_results, "a") as plot_file: + plot_file.write(f"{model_name}\n\n") + + sim_time_list = [] + all_rule_complex_level = [] + all_batched_task = [] + + for index in num_batched_tasks_range: + print("-------------------------------------------") + print( + f"Starting Simulation with {index} priority levels in the simulation scenario" + ) + print("-------------------------------------------") + + for rule_complexity_level in rules_level_range: + median_sim_time = get_avg_after_all_iters( + max_iter_num, index, model_info, rule_complexity_level + ) + + all_batched_task.append(index) + all_rule_complex_level.append(rule_complexity_level) + sim_time_list.append(median_sim_time) + + # collect data points used for plotting + with open(final_plot_results, "a") as plot_file: + plot_file.write(f"{index},{rule_complexity_level},{median_sim_time}\n") + + print(sim_time_list) + + # save plot of the relationship: number of batched tasks - simulation time + plt_path = _get_abs_path( + model_info["results_folder"], + f"{unique_run_id}_plot.png", + ) + + # show plot of the relationship: number of priority levels - simulation time + print(all_batched_task) + print(sim_time_list) + print(f"np {np.array(sim_time_list)}") + print(all_rule_complex_level) + print(f"np {np.array(all_rule_complex_level)}") + _save_plot_2( + # all_batched_task, + num_batched_tasks_range, + sim_time_list, + all_rule_complex_level, + max_complexity_level, + model_name, + model_info["total_cases"], + plt_path, + ) + + +def get_avg_after_all_iters( + max_iter_num: int, current_run_index: int, model_info, rule_complexity: int +): + same_index_sim_time_list = [] + for iter_num in range(0, max_iter_num): + sim_time = run_one_iteration(current_run_index, model_info, rule_complexity) + print(f"iter {iter_num}: {sim_time}") + same_index_sim_time_list.append(sim_time) + + median_sim_time = np.median(same_index_sim_time_list) + print(f"median: {median_sim_time}") + + return median_sim_time + + +def run_one_iteration(num_tasks_with_batching: int, model_info, rule_complexity: int): + results_folder = model_info["results_folder"] + initial_json_path = _get_abs_path(model_info["json"]) + bpmn_path = _get_abs_path(model_info["bpmn"]) + demo_stats = _get_abs_path(results_folder, f"{num_tasks_with_batching}_stats.csv") + sim_log = _get_abs_path(results_folder, f"{num_tasks_with_batching}_logs.csv") + + new_json_path = _setup_sim_scenario( + initial_json_path, num_tasks_with_batching, rule_complexity + ) + + simulation_time, _ = run_diff_res_simulation( + model_info["start_datetime"], + model_info["total_cases"], + bpmn_path, + new_json_path, + demo_stats, + sim_log, + False, # no events in the log + None, # no added events + ) + + return simulation_time + # diff_sim_result.print_simulation_results() + + +def _setup_sim_scenario( + initial_json_path, num_tasks_with_batching: int, rule_complexity: int +): + """ + Create case-based prioritisation rules based on the required number (num_prioritisation_rules) + Save the newly created json in new location to keep track of the setup for simulations + """ + + one_batching_rule = _get_rule_by_complexity_level(rule_complexity) + + with open(initial_json_path, "r") as f: + json_dict = json.load(f) + + # collect all ids of activities in the BPMN model + all_tasks_distr = json_dict[TASK_RESOURCE_DISTR_SECTON] + all_tasks_id = map(lambda item: item["task_id"], all_tasks_distr) + + # select only number of activities that should have an assigned batching rule + selected_tasks_id = list(all_tasks_id)[:num_tasks_with_batching] + + # create batching setup + new_batching_rules_section = [ + { + "task_id": task_id, + "type": "Sequential", + "batch_frequency": 1.0, + "size_distrib": [ + {"key": "2", "value": 1}, + ], + "duration_distrib": [{"key": "3", "value": 0.8}], + "firing_rules": one_batching_rule, + } + for task_id in selected_tasks_id + ] + + json_dict[BATCH_PROCESSING_SECTION] = new_batching_rules_section + + # save modified json as a new file specifying the number of experiment + # in order to keep track of run experiments + folder_loc = os.path.dirname(initial_json_path) + new_filename = f"{num_tasks_with_batching}_batching_exp.json" + new_json_path = os.path.join(folder_loc, new_filename) + + with open(new_json_path, "w+") as json_file: + json.dump(json_dict, json_file) + + return new_json_path + + +def _get_rule_by_complexity_level(rule_complexity: int): + all_rules = { + "1": [ + [ + {"attribute": "size", "comparison": ">=", "value": 4}, + ] + ], + "2": [ + [ + {"attribute": "daily_hour", "comparison": "<", "value": "12"}, + {"attribute": "week_day", "comparison": "=", "value": "Friday"}, + ] + ], + "3": [ + [ + {"attribute": "daily_hour", "comparison": "<", "value": "12"}, + {"attribute": "week_day", "comparison": "=", "value": "Friday"}, + ], + [ + {"attribute": "size", "comparison": ">=", "value": 4}, + ], + ], + "4": [ + [ + {"attribute": "daily_hour", "comparison": "<", "value": "12"}, + {"attribute": "week_day", "comparison": "=", "value": "Friday"}, + ], + [ + {"attribute": "size", "comparison": ">=", "value": 4}, + {"attribute": "large_wt", "comparison": "<", "value": 3600}, + ], + ], + } + + return all_rules[str(rule_complexity)] + + +def _save_plot(xpoints, ypoints, zpoints, model_name, num_of_instances, plt_path): + fig = plt.figure() + ax = fig.add_subplot(projection="3d") + + ax.scatter3D(xpoints, ypoints, zpoints, c=zpoints, cmap="Greens") + + # give a general title + ax.set_title(f"Model: {model_name}, instances: {num_of_instances}") + + # name axis + ax.set_xlabel("Number of priority levels") + ax.set_ylabel("Simulation time, sec") + + plt.show() + # save as a file + # plt.savefig(plt_path, bbox_inches="tight") + + +def _save_plot_2( + num_batched_task_arr, + sim_time_arr, + rule_complexity_level_arr, + max_complexity_level, + model_name, + num_of_instances, + plt_path, +): + fig = plt.figure() + + # give a general title + # plt.title(f"Model: {model_name}, instances: {num_of_instances}") + + # # provide data points + # plt.plot(xpoints, ypoints) + ax = fig.add_subplot(projection="3d") + colors = ["b", "g", "r", "c", "m", "y"] + + for i, (current_num_batched_task, color) in enumerate( + zip(num_batched_task_arr, colors) + ): + gap = max_complexity_level + start = i * gap # 1 - current_num_batched_task + end = start + gap + xs = sim_time_arr[start:end] + ys = rule_complexity_level_arr[start:end] + print(f"zs = {current_num_batched_task}") + print(start, end, xs, ys) + ax.bar(ys, xs, zs=current_num_batched_task, zdir="y", color=color, alpha=0.8) + + # name axis + ax.set_xlabel("Complexity of the batching rule") + ax.set_ylabel("Number of batched tasks") + ax.set_zlabel("Simulation time, sec") + ax.set_title(f"Model: {model_name}, instances: {num_of_instances}") + + # plt.colorbar() # show color scale + plt.show() + # save as a file + # plt.savefig(plt_path, bbox_inches="tight") + + +def _get_abs_path(*args): + return os.path.join(os.path.dirname(__file__), *args) + + +if __name__ == "__main__": + main() diff --git a/performance_exp/batching/testing_files.py b/performance_exp/batching/testing_files.py new file mode 100644 index 0000000..c275785 --- /dev/null +++ b/performance_exp/batching/testing_files.py @@ -0,0 +1,35 @@ +import numpy as np + + +process_files_setup = { + "simple_example": { + "bpmn": "simple_example/batch-example-end-task.bpmn", + "json": "simple_example/batch-example-with-batch.json", + "results_folder": "simple_example/results", + "start_datetime": "2022-06-21 13:22:30.035185+03:00", + "total_cases": 1000, + "disc_params": [60, 0.1, 0.9, 0.6, True], + "max_num_tasks_with_batching": 5, # should be the max number of tasks in the model + "measure_central_tendency": np.median, + "max_iter_num": 2, + "max_complexity_level": 4, + }, + "bpi2012": { + "bpmn": "bpi2012/input/BPI_Challenge_2012_W_Two_TS.bpmn", + "json": "bpi2012/input/bpi_2012.json", + "results_folder": "bpi2012/results", + "start_datetime": "2011-10-01 11:08:36.700000+03:00", # used to be as close to the real log as possible + "total_cases": 8616, + "disc_params": [ + 60, + 0.5, + 0.5, + 0.1, + True, + ], # to know the input required for discovering the json from the log + "max_num_tasks_with_batching": 6, # should be the max number of tasks in the model + "measure_central_tendency": np.median, # median since this metric is not impacted by outliers, compared to the mean one + "max_iter_num": 5, + "max_complexity_level": 4, + }, +} From 59e7b14c2ae5e333babbb379139dd967d82ce190 Mon Sep 17 00:00:00 2001 From: Iryna Halenok Date: Tue, 21 Mar 2023 16:30:50 +0200 Subject: [PATCH 19/19] #54 - Name axis correctly for the first version of the plot --- performance_exp/batching/perform_batching_runner.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/performance_exp/batching/perform_batching_runner.py b/performance_exp/batching/perform_batching_runner.py index af2ec63..8b645f9 100644 --- a/performance_exp/batching/perform_batching_runner.py +++ b/performance_exp/batching/perform_batching_runner.py @@ -224,8 +224,9 @@ def _save_plot(xpoints, ypoints, zpoints, model_name, num_of_instances, plt_path ax.set_title(f"Model: {model_name}, instances: {num_of_instances}") # name axis - ax.set_xlabel("Number of priority levels") + ax.set_xlabel("Number of batched tasks") ax.set_ylabel("Simulation time, sec") + ax.set_zlabel("Complexity of the batching rule") plt.show() # save as a file