diff --git a/backend/__pycache__/agent.cpython-311.pyc b/backend/__pycache__/agent.cpython-311.pyc index 87f701a04a31d900d91fd18b6bc837516be90163..51f4f916a98f67a7704f896ffc5c1d4ef0b81626 100644 Binary files a/backend/__pycache__/agent.cpython-311.pyc and b/backend/__pycache__/agent.cpython-311.pyc differ diff --git a/backend/__pycache__/environment.cpython-311.pyc b/backend/__pycache__/environment.cpython-311.pyc index 51daa198751b4836531ffe9cc564ed462aed29b8..4b3cb87be7554aa6bcb531d2a1fd6d299d80c0a5 100644 Binary files a/backend/__pycache__/environment.cpython-311.pyc and b/backend/__pycache__/environment.cpython-311.pyc differ diff --git a/backend/__pycache__/eventlog.cpython-311.pyc b/backend/__pycache__/eventlog.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c000c77be103887b9d6c9671a5555bb455cc198 Binary files /dev/null and b/backend/__pycache__/eventlog.cpython-311.pyc differ diff --git a/backend/__pycache__/simplesimmodel.cpython-311.pyc b/backend/__pycache__/simplesimmodel.cpython-311.pyc index 7f8f062a2173a3f3440055bc14475b66274869c3..def6d5e7c495421b42862ead8fe246f98d50bf31 100644 Binary files a/backend/__pycache__/simplesimmodel.cpython-311.pyc and b/backend/__pycache__/simplesimmodel.cpython-311.pyc differ diff --git a/backend/agent.py b/backend/agent.py index 111df067c5097be66021c5d64734dcc9f66f6117..e75453c055229586c9597b39b5e9cc52d4327e28 100644 --- a/backend/agent.py +++ b/backend/agent.py @@ -18,26 +18,44 @@ def q_learning(space, activities): case_space = env.observation_space['case'].nvec event_space = env.observation_space['event'].n - for i in process_space: num_states *= i - for i in case_space: num_states *= i - num_states *= event_space + """ + for i in process_space: num_states *= (i+1) + for i in case_space: num_states *= (i+1) + num_states *= event_space + 1 + """ + num_states = pow(2,14) + + """ + process_space = env.observation_space['process'] + case_space = env.observation_space['case'] + event_space = env.observation_space['event'] + + state_shape = [] + for i in process_space: state_shape.append(i.n + 1) + for j in case_space: state_shape.append(j.n + 1) + state_shape.append(event_space.n) + state_shape = tuple(state_shape) + """ num_actions = env.action_space.n - Q = np.zeros((num_states, num_actions), dtype=np.int16) + + # Q = np.zeros(state_shape + (num_actions,), dtype=np.int8) + Q = np.zeros((num_states, num_actions), dtype = int) # Set the hyperparameters alpha = 0.1 # learning rate - gamma = 0.99 # discount factor + gamma = 0.1 # discount factor epsilon = 0.1 # exploration rate mean_time = 0 + mean_reward = 0 # Train the agent using Q-learning - num_episodes = 100 + num_episodes = 1000 for episode in range(num_episodes): state, _ = env.reset() - state = env.flatten_observation(state) + state = env.flatten_observation_to_int(state) done = False start = env.process.env.now while not done: @@ -52,18 +70,39 @@ def q_learning(space, activities): next_state, reward, done, _ = env.step(action) # Update the Q-value for the current state-action pair - Q[state][action] = Q[state][action] + alpha * (reward + gamma * np.max(Q[next_state]) - Q[state][action]) + Q[state][action] = (1-alpha)*Q[state][action] + alpha * (reward + gamma * np.max(Q[next_state]) - Q[state][action]) + #Q[state][action] = (1-alpha)*Q[state][action] + alpha*reward # Transition to the next state + old_state = state state = next_state + + """ + if old_state != state: + print(state) + print(action) + print(Q[state][action]) + """ + time = env.process.env.now - start mean_time += time + mean_reward += reward + - """ if (episode % 20 == 19): + mean_reward /= 20 mean_time /= 20 - print(f"Episode {episode-19} to episode {episode}: mean time = {mean_time}") - """ + print(f"Episode {episode-19} to episode {episode}: mean time = {mean_time}, mean reward: {mean_reward}") + + if episode == 19: + start_reward = mean_reward + + # print(f"Episode {episode}: time = {time}, reward = {reward}") + + if episode == 999: + end_reward = mean_reward + improvement = end_reward - start_reward + print(f"Reward improved by {improvement}") - print(f"Episode {episode}: time = {time}") \ No newline at end of file + return Q diff --git a/backend/environment.py b/backend/environment.py index b96b6425d7216e12269ab8b8a50577c25a72ae05..1ee254b01386f500a7728900d07f3ff8855ee4af 100644 --- a/backend/environment.py +++ b/backend/environment.py @@ -7,7 +7,6 @@ import simplesimmodel as model Environment for the RL agent """ - class BusinessProcessEnv(gym.Env): def __init__(self, space, activities): @@ -73,19 +72,21 @@ class BusinessProcessEnv(gym.Env): case_obj = self.process.case_objects[self.process.case_id] - print(f"Agent did case {self.process.case_id} activity {action}.") + # print(f"Agent did case {self.process.case_id} activity {action}.") next_state = self.get_current_state(case_obj) self.current_state = next_state - next_state = self.flatten_observation(next_state) + next_state = self.flatten_observation_to_int(next_state) - self.reward += -(stop - start) + time = stop - start + reward = 10000 - time + self.reward += reward done = True if (len(self.process.done_cases) == 5 or len(self.process.active_cases) == 0) else False return next_state, self.reward, done, None else: - self.reward += -100 - next_state = self.flatten_observation(self.current_state) + self.reward += 0 + next_state = self.flatten_observation_to_int(self.current_state) done = False return next_state, self.reward, done, None @@ -125,4 +126,74 @@ class BusinessProcessEnv(gym.Env): return flattened + def flatten_observation_to_int(self, observation): + state = 0 + state += observation['event']*pow(2,10) + state += observation['case'][1]*pow(2,2) + state += observation['case'][2]*pow(2,2) + event = observation['event'] + if event == 0: + state += observation['process'][0]*pow(2,6) + elif event == 1: + state += observation['process'][1]*pow(2,6) + elif 1 < event <=3: + state += observation['process'][2]*pow(2,6)+observation['process'][3]*pow(2,7)+observation['process'][4]*pow(2,8) + elif 3 < event <=6: + state += observation['process'][5]*pow(2,6)+observation['process'][6]*pow(2,7) + elif 6 < event <= 8: + state += observation['process'][7]*pow(2,6)+observation['process'][8]*pow(2,7)+observation['process'][9]*pow(2,8) + elif 8 < event <= 11: + state += observation['process'][10]*pow(2,6)+observation['process'][11]*pow(2,7)+observation['process'][12]*pow(2,8) + elif 11 < event <= 14: + state += observation['process'][0]*pow(2,6) + else: + pass + + return state + +def main(): + process = [] + num_s = 1 + process.append(num_s) + num_ot = 5 + process.append(num_ot) + num_sh_a = 3 + process.append(num_sh_a) + num_sh_b = 3 + process.append(num_sh_b) + num_sh_c = 3 + process.append(num_sh_c) + num_m_a = 3 + process.append(num_m_a) + num_m_b = 2 + process.append(num_m_b) + num_p_a = 4 + process.append(num_p_a) + num_p_b = 5 + process.append(num_p_b) + num_p_c = 4 + process.append(num_p_c) + num_ds_a = 8 + process.append(num_ds_a) + num_ds_b = 8 + process.append(num_ds_b) + num_ds_c = 8 + process.append(num_ds_c) + + case = [] + for i in range(15): + case.append(1) + + space = [process, case] + activities = 16 + + env = BusinessProcessEnv(space, activities) + state = env.current_state + flattened = env.flatten_observation_to_int(state) + print(flattened) + for value in range(env.action_space.n): + print(value) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/backend/eventlog.py b/backend/eventlog.py index 36848b5a3dd9d5e01f478cce5539b5d7175c10e8..7a3625ef7aca88f1debea601923e4acfb86ad3a5 100644 --- a/backend/eventlog.py +++ b/backend/eventlog.py @@ -1,33 +1,172 @@ import pandas as pd import simplesimmodel as model +import numpy as np """ Event log generator for our simulation model: - generate an event log - update an event log (adding new events) +- export event log +- get current state of an event log """ def add_start_event(process, event_id, case_id, activity, start_timestamp): + process.event_log.append(event_id) process.event_log[event_id] = { 'CaseID': case_id, 'Activity': activity, 'StartTimestamp': float(start_timestamp), 'EndTimestamp': None } + process.event_counter += 1 def add_end_event(process, event_id, end_timestamp): - # if event_id in process.event_log: event = process.event_log[event_id] event['EndTimestamp'] = end_timestamp - # process.event_log.append(event) - # del process.event_log[event_id] -# add functions for adding events with their attributes to the log -def export_to_csv(env, file_path): - event_log_df = pd.DataFrame.from_dict(env.bigeventlog) - event_log_df.to_csv(file_path) +def export_to_csv(process, file_path): + event_log_df = pd.DataFrame.from_dict(process.event_log) + event_log_df.to_csv(file_path, index=False) def export_to_xes(process, file_path): # Use appropriate code to export to XES format - pass \ No newline at end of file + pass + +def get_active_cases(): + event_log = pd.read_csv(r'D:\test\optis.csv') + active_cases = event_log.groupby('CaseID').filter(lambda x: 'order completed' not in x['Activity'].values)['CaseID'].unique().tolist() + return active_cases + + +def get_state(case_id): + + process = [] + num_s = 1 + process.append(num_s) + num_ot = 5 + process.append(num_ot) + num_sh_a = 3 + process.append(num_sh_a) + num_sh_b = 3 + process.append(num_sh_b) + num_sh_c = 3 + process.append(num_sh_c) + num_m_a = 3 + process.append(num_m_a) + num_m_b = 2 + process.append(num_m_b) + num_p_a = 4 + process.append(num_p_a) + num_p_b = 5 + process.append(num_p_b) + num_p_c = 4 + process.append(num_p_c) + num_ds_a = 8 + process.append(num_ds_a) + num_ds_b = 8 + process.append(num_ds_b) + num_ds_c = 8 + process.append(num_ds_c) + + case = [] + for i in range(15): + case.append(0) + + activity_mapping = { + 'place order': 1, + 'arrange standard order': 2, + 'arrange custom order': 3, + 'pick from stock A': 4, + 'pick from stock B': 5, + 'pick from stock C': 6, + 'manufacture A': 7, + 'manufacture B': 8, + 'pack A': 9, + 'pack B': 10, + 'pack C': 11, + 'attempt delivery A': 12, + 'attempt delivery B': 13, + 'attempt delivery C': 14, + 'order completed': 15, + } + + event_log = pd.read_csv(r'D:\test\optis.csv') + # Sort the event log by case ID and start timestamp + event_log.sort_values(by=['CaseID', 'StartTimestamp'], inplace=True) + + # Group the event log by case ID and get the last activity for each case + last_activities = event_log.groupby('CaseID').tail(1).reset_index() + + # Remap the activity names to numbers using the mapping dictionary + last_activities['Activity'] = last_activities['Activity'].map(activity_mapping) + + # Filter the cases where the end timestamp of the last activity is None or empty + unfinished_cases = last_activities[last_activities['EndTimestamp'].isnull()]['CaseID'].tolist() + + # Update the state of the ressources given all unfinished cases + for i in unfinished_cases: + activity = last_activities[last_activities['CaseID'] == i]['Activity'].values[0] + if activity == 1 or activity == 15: + process[0] -= 1 + elif activity == 2 or activity == 3: + process[1] -= 1 + else: + process[activity-2] -= 1 + + # Get the state of the case for the given Case ID + filtered_log = event_log[event_log['CaseID'] == case_id] + activities = filtered_log['Activity'].map(activity_mapping).tolist() + for i in activities: + case[i-1] += 1 + + # Get the last event for the given Case ID + event = last_activities[last_activities['CaseID'] == case_id]['Activity'].values[0] + + state = { + 'process': process, + 'case': case, + 'event': event + } + + print(state) + + """ + flattened = [] + for i in state['process']: flattened.append(i) + for j in state['case']: flattened.append(j) + flattened.append(state['event']) + + + flattened = 0 + flattened += state['event'] + for i in state['case']: flattened += i + for j in state['process']: flattened += j*process[j] + + print(flattened) + """ + flat_state = 0 + flat_state += state['event']*pow(2,10) + print(flat_state) + flat_state += state['case'][1]*pow(2,1) + flat_state += state['case'][2]*pow(2,2) + event = state['event'] + if event == 0: + flat_state += state['process'][0]*pow(2,6) + elif event == 1: + flat_state += state['process'][1]*pow(2,6) + elif 1 < event <=3: + flat_state += state['process'][2]*pow(2,6)+state['process'][3]*pow(2,7)+state['process'][4]*pow(2,8) + elif 3 < event <=6: + flat_state += state['process'][5]*pow(2,6)+state['process'][6]*pow(2,7) + elif 6 < event <= 8: + flat_state += state['process'][7]*pow(2,6)+state['process'][8]*pow(2,7)+state['process'][9]*pow(2,8) + elif 8 < event <= 11: + flat_state += state['process'][10]*pow(2,6)+state['process'][11]*pow(2,7)+state['process'][12]*pow(2,8) + elif 11 < event <= 14: + flat_state += state['process'][0]*pow(2,6) + else: + pass + + print(flat_state) + return flat_state diff --git a/backend/input.py b/backend/input.py new file mode 100644 index 0000000000000000000000000000000000000000..e8c6f1e805443c6f965ca5c3909457684b3d5063 --- /dev/null +++ b/backend/input.py @@ -0,0 +1,2 @@ +import pandas as pd + diff --git a/backend/main.py b/backend/main.py new file mode 100644 index 0000000000000000000000000000000000000000..fdee31d6eb3e8d2bf65037450ec61528c9b21529 --- /dev/null +++ b/backend/main.py @@ -0,0 +1,91 @@ +import simpy +import random +import numpy as np +import simplesimmodel as model +import environment +import agent +import eventlog as log +import pandas as pd + +def main(): + # Setup + # we can use a random seed if we want to generate the same results every time (maybe useful later for the training) + # random.seed(42) + # initialize the number of resources + + process = [] + num_s = 1 + process.append(num_s) + num_ot = 5 + process.append(num_ot) + num_sh_a = 3 + process.append(num_sh_a) + num_sh_b = 3 + process.append(num_sh_b) + num_sh_c = 3 + process.append(num_sh_c) + num_m_a = 3 + process.append(num_m_a) + num_m_b = 2 + process.append(num_m_b) + num_p_a = 4 + process.append(num_p_a) + num_p_b = 5 + process.append(num_p_b) + num_p_c = 4 + process.append(num_p_c) + num_ds_a = 7 + process.append(num_ds_a) + num_ds_b = 7 + process.append(num_ds_b) + num_ds_c = 7 + process.append(num_ds_c) + + case = [] + for i in range(15): + case.append(1) + + space = [process, case] + activities = 16 + + # q learning + Q = agent.q_learning(space, activities) + # print(Q) + + # generate event log + env = simpy.Environment() + business_process = model.BusinessProcess(env, process) + business_process.event_log_flag = True + env.process(model.run_process(env, business_process)) + env.run(until = 10000) + log.export_to_csv(business_process, r'D:\test\optis.csv') + + # extract active cases from event log + active_cases = log.get_active_cases() + print(active_cases) + + # test agent + for i in range(20): + caseid = random.choice(active_cases) + state = log.get_state(caseid) + + action = np.argmax(Q[state]) + print(action) + #print(Q) + print(Q[state]) + + state = Q[0] + action = np.argmax(state) + print(action) + print(state) + + state = Q[64] + action = np.argmax(state) + print(action) + print(state) + + + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/backend/simplesimmodel.py b/backend/simplesimmodel.py index fe23eb4b077fbfcf15c62daa4a7e844ac1e875e0..18cb95273cd687ac419a8d7c8cf3fce44011e738 100644 --- a/backend/simplesimmodel.py +++ b/backend/simplesimmodel.py @@ -3,6 +3,7 @@ import random import numpy as np import environment import agent +import eventlog as log """ Simulation model for a simpler business process, including: @@ -56,7 +57,11 @@ class BusinessProcess(object): self.done_cases = set([]) - random.seed(1) + self.event_log_flag = False + self.event_log = [] + self.event_counter = 0 + + # random.seed(1) def place_order(self, case): yield self.env.timeout(0) @@ -162,20 +167,25 @@ def execute_case(env, case, process): case_obj.agent = True # place order + case_obj.state[0] += 1 + case_obj.current = 1 with process.system.request() as request: yield request - case_obj.state[0] += 1 - case_obj.current = 1 + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "place order", env.now) yield env.process(process.place_order(case)) - if case_obj.agent: print(f"Case {case}: 'placed order' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + # if case_obj.agent: print(f"Case {case}: 'placed order' at {env.now:.2f}") # if the last action was made from the agent set the process flag to be able to return to the environment's step function if case_obj.agent: process.flag = False - with process.system.request() as request: - yield request + with process.system.request() as request: + yield request # before a new action is executed check if the agent is controlling the case and set the flag to true if yes if process.case_id == case: case_obj.agent = True @@ -184,32 +194,40 @@ def execute_case(env, case, process): choice = random.randint(2,3) if not case_obj.agent else process.next if choice == 2: case_obj.standard_order = True + case_obj.state[1] += 1 + case_obj.current = 2 with process.order_taker.request() as request: yield request - case_obj.state[1] += 1 - case_obj.current = 2 - if case_obj.agent: print(f"Case {case}: started 'arrange standard order' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'arrange standard order' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "arrange standard order", env.now) yield env.process(process.arrange_standard_order(case)) - if case_obj.agent: print(f"Case {case}: finished 'arrange standard order' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + # if case_obj.agent: print(f"Case {case}: finished 'arrange standard order' at {env.now:.2f}") if case_obj.agent: process.flag = False - - with process.system.request() as request: - yield request + with process.system.request() as request: + yield request else: + case_obj.state[2] += 1 + case_obj.current = 3 case_obj.standard_order = False with process.order_taker.request() as request: yield request - case_obj.state[2] += 1 - case_obj.current = 3 - if case_obj.agent: print(f"Case {case}: started 'arrange custom order' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'arrange custom order' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "arrange custom order", env.now) yield env.process(process.arrange_custom_order(case)) - if case_obj.agent: print(f"Case {case}: finished 'arrange custom order' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + # if case_obj.agent: print(f"Case {case}: finished 'arrange custom order' at {env.now:.2f}") if case_obj.agent: process.flag = False - - with process.system.request() as request: - yield request + with process.system.request() as request: + yield request if process.case_id == case: case_obj.agent = True @@ -223,70 +241,92 @@ def execute_case(env, case, process): # choose stock or manufacturer if choice == 4: + case_obj.state[3] += 1 + case_obj.current = 4 with process.stock_handler_a.request() as request: yield request - case_obj.state[3] += 1 - case_obj.current = 4 - if case_obj.agent: print(f"Case {case}: started 'pick from stock A' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'pick from stock A' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "pick from stock A", env.now) yield env.process(process.pick_from_stock_a(case)) - if case_obj.agent: print(f"Case {case}: finished 'pick from stock A' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + # if case_obj.agent: print(f"Case {case}: finished 'pick from stock A' at {env.now:.2f}") if case_obj.agent: process.flag = False - - with process.system.request() as request: - yield request + with process.system.request() as request: + yield request elif choice == 5: + case_obj.state[4] += 1 + case_obj.current = 5 with process.stock_handler_b.request() as request: yield request - case_obj.state[4] += 1 - case_obj.current = 5 - if case_obj.agent: print(f"Case {case}: started 'pick from stock B' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'pick from stock B' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "pick from stock B", env.now) yield env.process(process.pick_from_stock_b(case)) - if case_obj.agent: print(f"Case {case}: finished 'pick from stock B' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + + # if case_obj.agent: print(f"Case {case}: finished 'pick from stock B' at {env.now:.2f}") if case_obj.agent: process.flag = False - - with process.system.request() as request: - yield request + with process.system.request() as request: + yield request elif choice == 6: + case_obj.state[5] += 1 + case_obj.current = 6 with process.stock_handler_c.request() as request: yield request - case_obj.state[5] += 1 - case_obj.current = 6 - if case_obj.agent: print(f"Case {case}: started 'pick from stock C' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'pick from stock C' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "pick from stock C", env.now) yield env.process(process.pick_from_stock_c(case)) - if case_obj.agent: print(f"Case {case}: finished 'pick from stock C' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + # if case_obj.agent: print(f"Case {case}: finished 'pick from stock C' at {env.now:.2f}") if case_obj.agent: process.flag = False - - with process.system.request() as request: - yield request + with process.system.request() as request: + yield request elif choice == 7: + case_obj.state[6] += 1 + case_obj.current = 7 with process.manufacturer_a.request() as request: yield request - case_obj.state[6] += 1 - case_obj.current = 7 - if case_obj.agent: print(f"Case {case}: started 'manufacture A' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'manufacture A' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "manufacture A", env.now) yield env.process(process.manufacture_a(case)) - if case_obj.agent: print(f"Case {case}: finished 'manufacture A' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + + # if case_obj.agent: print(f"Case {case}: finished 'manufacture A' at {env.now:.2f}") if case_obj.agent: process.flag = False - - with process.system.request() as request: - yield request + with process.system.request() as request: + yield request else: + case_obj.state[7] += 1 + case_obj.current = 8 with process.manufacturer_b.request() as request: yield request - case_obj.state[7] += 1 - case_obj.current = 8 - if case_obj.agent: print(f"Case {case}: started 'manufacture B' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'manufacture B' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "manufacture B", env.now) yield env.process(process.manufacture_b(case)) - if case_obj.agent: print(f"Case {case}: finished 'manufacture B' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + # if case_obj.agent: print(f"Case {case}: finished 'manufacture B' at {env.now:.2f}") if case_obj.agent: process.flag = False - - with process.system.request() as request: - yield request + with process.system.request() as request: + yield request if process.case_id == case: case_obj.agent = True @@ -294,99 +334,135 @@ def execute_case(env, case, process): choice = random.randint(9,11) if not case_obj.agent else process.next if choice == 9: + case_obj.state[8] += 1 + case_obj.current = 9 with process.packer_a.request() as request: yield request - case_obj.state[8] += 1 - case_obj.current = 9 - if case_obj.agent: print(f"Case {case}: started 'pack A' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'pack A' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "pack A", env.now) yield env.process(process.pack_a(case)) - if case_obj.agent: print(f"Case {case}: finished 'pack A' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + + # if case_obj.agent: print(f"Case {case}: finished 'pack A' at {env.now:.2f}") if case_obj.agent: - process.flag = False - - with process.system.request() as request: - yield request + process.flag = False + with process.system.request() as request: + yield request elif choice == 10: + case_obj.state[9] += 1 + case_obj.current = 10 with process.packer_b.request() as request: yield request - case_obj.state[9] += 1 - case_obj.current = 10 - if case_obj.agent: print(f"Case {case}: started 'pack B' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'pack B' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "pack B", env.now) yield env.process(process.pack_b(case)) - if case_obj.agent: print(f"Case {case}: finished 'pack B' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + + # if case_obj.agent: print(f"Case {case}: finished 'pack B' at {env.now:.2f}") if case_obj.agent: - process.flag = False + process.flag = False - with process.system.request() as request: - yield request + with process.system.request() as request: + yield request else: + case_obj.state[10] += 1 + case_obj.current = 11 with process.packer_c.request() as request: yield request - case_obj.state[10] += 1 - case_obj.current = 11 - if case_obj.agent: print(f"Case {case}: started 'pack C' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'pack C' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "pack C", env.now) yield env.process(process.pack_c(case)) - if case_obj.agent: print(f"Case {case}: finished 'pack C' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + + # if case_obj.agent: print(f"Case {case}: finished 'pack C' at {env.now:.2f}") if case_obj.agent: - process.flag = False - - with process.system.request() as request: - yield request + process.flag = False + with process.system.request() as request: + yield request if process.case_id == case: case_obj.agent = True # choose delivery choice = random.randint(12,14) if not case_obj.agent else process.next if choice == 12: + case_obj.state[11] += 1 + case_obj.current = 12 with process.delivery_service_a.request() as request: yield request - case_obj.state[11] += 1 - case_obj.current = 12 - if case_obj.agent: print(f"Case {case}: started 'attempt delivery A' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'attempt delivery A' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "attempt delivery A", env.now) yield env.process(process.attempt_delivery_a(case)) - if case_obj.agent: print(f"Case {case}: finished 'attempt delivery A' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + + # if case_obj.agent: print(f"Case {case}: finished 'attempt delivery A' at {env.now:.2f}") if case_obj.agent: - process.flag = False - - with process.system.request() as request: - yield request + process.flag = False + with process.system.request() as request: + yield request elif choice == 13: + case_obj.state[12] += 1 + case_obj.current = 13 with process.delivery_service_b.request() as request: yield request - case_obj.state[12] += 1 - case_obj.current = 13 - if case_obj.agent: print(f"Case {case}: started 'attempt delivery B' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'attempt delivery B' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "attempt delivery B", env.now) yield env.process(process.attempt_delivery_b(case)) - if case_obj.agent: print(f"Case {case}: finished 'attempt delivery B' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + + # if case_obj.agent: print(f"Case {case}: finished 'attempt delivery B' at {env.now:.2f}") if case_obj.agent: - process.flag = False - - with process.system.request() as request: - yield request + process.flag = False + with process.system.request() as request: + yield request else: + case_obj.state[13] += 1 + case_obj.current = 14 with process.delivery_service_c.request() as request: yield request - case_obj.state[13] += 1 - case_obj.current = 14 - if case_obj.agent: print(f"Case {case}: started 'attempt delivery C' at {env.now:.2f}") + # if case_obj.agent: print(f"Case {case}: started 'attempt delivery C' at {env.now:.2f}") + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "attempt delivery C", env.now) yield env.process(process.attempt_delivery_c(case)) - if case_obj.agent: print(f"Case {case}: finished 'attempt delivery C' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + + # if case_obj.agent: print(f"Case {case}: finished 'attempt delivery C' at {env.now:.2f}") if case_obj.agent: - process.flag = False - - with process.system.request() as request: - yield request + process.flag = False + with process.system.request() as request: + yield request if process.case_id == case: case_obj.agent = True # case completed + case_obj.state[14] += 1 + case_obj.current = 15 with process.system.request() as request: yield request - case_obj.state[14] += 1 - case_obj.current = 15 + if process.event_log_flag: + event_counter = process.event_counter + log.add_start_event(process, event_counter, case, "order completed", env.now) yield env.process(process.order_completed(case)) - if case_obj.agent: print(f"Case {case}: 'completed' at {env.now:.2f}") + if process.event_log_flag: + log.add_end_event(process, event_counter, env.now) + # if case_obj.agent: print(f"Case {case}: 'completed' at {env.now:.2f}") if case in process.active_cases: @@ -399,6 +475,13 @@ def execute_case(env, case, process): process.done_cases.add(process.case_id) process.flag = False + +""" +Get the cureent state of the process and a specific case +- available ressouces +- events which already happened in the case +- current event of the case +""" def get_current_state(process, case): process_state = [] @@ -447,6 +530,9 @@ def get_current_state(process, case): return process_state, cur_case, event +""" +Defines how often new orders (cases) come in and starts executing them +""" def run_process(env, process): # process = Process(env, num_ot, num_m, num_sh_a, num_sh_b, num_sh_c, num_m_a, num_m_b, num_ds_a, num_ds_b, num_ds_c) @@ -457,63 +543,11 @@ def run_process(env, process): # the new incoming orders while case < 1000: waittime = random.randint(10,15) + if case % 20 == 0: + waittime = 100 yield env.timeout(waittime) # Wait a bit before generating a new case case += 1 # process.active_cases.append(case) env.process(execute_case(env, case, process)) -def main(): - # Setup - # we can use a random seed if we want to generate the same results every time (maybe useful later for the training) - # random.seed(42) - # initialize the number of resources - - process = [] - num_s = 1 - process.append(num_s) - num_ot = 5 - process.append(num_ot) - num_sh_a = 3 - process.append(num_sh_a) - num_sh_b = 3 - process.append(num_sh_b) - num_sh_c = 3 - process.append(num_sh_c) - num_m_a = 3 - process.append(num_m_a) - num_m_b = 2 - process.append(num_m_b) - num_p_a = 4 - process.append(num_p_a) - num_p_b = 5 - process.append(num_p_b) - num_p_c = 4 - process.append(num_p_c) - num_ds_a = 8 - process.append(num_ds_a) - num_ds_b = 8 - process.append(num_ds_b) - num_ds_c = 8 - process.append(num_ds_c) - - case = [] - for i in range(15): - case.append(1) - - space = [process, case] - activities = 16 - - business_env = environment.BusinessProcessEnv(space, activities) - print(business_env.observation_space.shape) - print(business_env.observation_space.sample()) - - state, _ = business_env.reset() - print(state) - print(business_env.current_state) - print(state['event']) - print(business_env.flatten_observation(state)) - agent.q_learning(space, activities) - -if __name__ == "__main__": - main() diff --git a/simpy_tutorial/eventlog.py b/simpy_tutorial/eventlog.py index 8a31eaf99ca99fbcee7db494ea8598148373147e..e7f2df2928a2f0eed752a42715a78b00eac001b1 100644 --- a/simpy_tutorial/eventlog.py +++ b/simpy_tutorial/eventlog.py @@ -24,15 +24,10 @@ def add_end_event(process, event_id, end_timestamp): # add functions for adding events with their attributes to the log -<<<<<<<< HEAD:simpy_tutorial/eventlog.py -def export_to_csv(env, file_path): - event_log_df = pd.DataFrame.from_dict(env.bigeventlog) - event_log_df.to_csv(file_path) -======== + def export_to_csv(process, file_path): event_log_df = pd.DataFrame.from_dict(process.event_log) event_log_df.to_csv(file_path, index=False) ->>>>>>>> 575b59827b5f928da4165070a4a1d51a85eed774:Simpy_Tutorial/eventlog.py def export_to_xes(process, file_path): # Use appropriate code to export to XES format