def split_loop_infrequent(cut, l, activity_key): n = len(cut) new_logs = [log.EventLog() for i in range(0, n)] for trace in l: s = cut[0] st = log.Trace() for act in trace: if act in s: st.insert(act) else: j = 0 for j in range(0, len(cut)): if cut[j] == s: break new_logs[j].append(st) st = log.Trace() for partition in cut: if act[activity_key] in partition: s.append(partition) # L_j <- L_j + [st] with sigma_j = s j = 0 for j in range(0, len(cut)): if cut[j] == s: break new_logs[j].append(st) if s != cut[0]: new_logs[0].append(log.EventLog()) return new_logs
def split_sequence(cut, l, activity_key): new_logs = [] for c in cut: # for all cut-partitions lo = log.EventLog() for trace in l: # for all traces in the log_skeleton not_in_c = True trace_new = log.Trace() for j in range(0, len(trace)): # for every event in the current trace if trace[j][activity_key] in c: not_in_c = False while trace[j][activity_key] in c: trace_new.append( trace[j] ) # we only add the events that match the cut partition if j + 1 < len(trace): j += 1 else: j += 1 break lo.append(trace_new) break if not_in_c: lo.append(trace_new) new_logs.append(lo) if len(new_logs) > 0: return new_logs
def get_best_worst_cost(petri_net, initial_marking, final_marking, parameters=None): """ Gets the best worst cost of an alignment Parameters ----------- petri_net Petri net initial_marking Initial marking final_marking Final marking parameters Parameters Returns ----------- best_worst_cost Best worst cost of alignment """ best_worst = pm4py.algo.conformance.alignments.versions.state_equation_a_star.apply( log_implementation.Trace(), petri_net, initial_marking, final_marking, parameters=parameters) return best_worst['cost'] // alignments.utils.STD_MODEL_LOG_MOVE_COST
def split_loop(cut, l, activity_key): new_logs = [] for c in cut: # for cut partition lo = log.EventLog() for trace in l: # for all traces j = 0 while j in range(0, len(trace)): # for all events if trace[j][activity_key] in c: trace_new = log.Trace() # declared here and not above, so that we can generate multiple traces from one trace and # cut (repetition) # append those events that are contained in c: while trace[j][activity_key] in c: trace_new.append(trace[j]) if j + 1 < len(trace): j += 1 else: j += 1 break lo.append(trace_new) else: j += 1 if len(lo) != 0: new_logs.append(lo) return new_logs
def apply_from_variant(variant, petri_net, initial_marking, final_marking, parameters=None): """ Apply the alignments from the specification of a single variant Parameters ------------- variant Variant (as string delimited by the "variant_delimiter" parameter) petri_net Petri net initial_marking Initial marking final_marking Final marking parameters Parameters of the algorithm (same as 'apply' method, plus 'variant_delimiter' that is , by default) Returns ------------ dictionary: `dict` with keys **alignment**, **cost**, **visited_states**, **queued_states** """ if parameters is None: parameters = {} activity_key = DEFAULT_NAME_KEY if parameters is None or PARAMETER_CONSTANT_ACTIVITY_KEY not in parameters else \ parameters[ pm4pyutil.constants.PARAMETER_CONSTANT_ACTIVITY_KEY] trace = log_implementation.Trace() variant_delimiter = exec_utils.get_param_value(Parameters.PARAMETER_VARIANT_DELIMITER, parameters, ",") variant_split = variant.split(variant_delimiter) if type(variant) is str else variant for i in range(len(variant_split)): trace.append(log_implementation.Event({activity_key: variant_split[i]})) return apply(trace, petri_net, initial_marking, final_marking, parameters=parameters)
def get_best_worst_cost(petri_net, initial_marking, final_marking, parameters=None): """ Gets the best worst cost of an alignment Parameters ----------- petri_net Petri net initial_marking Initial marking final_marking Final marking Returns ----------- best_worst_cost Best worst cost of alignment """ trace = log_implementation.Trace() new_parameters = copy(parameters) if PARAM_TRACE_COST_FUNCTION not in new_parameters or len(new_parameters[PARAM_TRACE_COST_FUNCTION]) < len(trace): new_parameters[PARAM_TRACE_COST_FUNCTION] = list( map(lambda e: utils.STD_MODEL_LOG_MOVE_COST, trace)) best_worst = pm4py.algo.conformance.alignments.versions.state_equation_a_star.apply(trace, petri_net, initial_marking, final_marking, parameters=new_parameters) if best_worst['cost'] > 0: return best_worst['cost'] // utils.STD_MODEL_LOG_MOVE_COST return 0
def get_best_worst_cost(petri_net, initial_marking, final_marking, parameters=None): """ Gets the best worst cost of an alignment Parameters ----------- petri_net Petri net initial_marking Initial marking final_marking Final marking Returns ----------- best_worst_cost Best worst cost of alignment """ if parameters is None: parameters = {} trace = log_implementation.Trace() best_worst = apply(trace, petri_net, initial_marking, final_marking, parameters=parameters) if best_worst['cost'] > 0: return best_worst['cost'] // align_utils.STD_MODEL_LOG_MOVE_COST return 0
def apply_playout(net, initial_marking, no_traces=100, max_trace_length=100, case_id_key=xes_constants.DEFAULT_TRACEID_KEY, activity_key=xes_constants.DEFAULT_NAME_KEY, timestamp_key=xes_constants.DEFAULT_TIMESTAMP_KEY, final_marking=None): """ Do the playout of a Petrinet generating a log Parameters ---------- net Petri net to play-out initial_marking Initial marking of the Petri net no_traces Number of traces to generate max_trace_length Maximum number of events per trace (do break) case_id_key Trace attribute that is the case ID activity_key Event attribute that corresponds to the activity timestamp_key Event attribute that corresponds to the timestamp final_marking If provided, the final marking of the Petri net """ # assigns to each event an increased timestamp from 1970 curr_timestamp = 10000000 log = log_instance.EventLog() for i in range(no_traces): trace = log_instance.Trace() trace.attributes[case_id_key] = str(i) marking = copy(initial_marking) while len(trace) < max_trace_length: if not semantics.enabled_transitions( net, marking): # supports nets with possible deadlocks break all_enabled_trans = semantics.enabled_transitions(net, marking) if final_marking is not None and marking == final_marking: trans = choice(list(all_enabled_trans.union({None}))) else: trans = choice(list(all_enabled_trans)) if trans is None: break if trans.label is not None: event = log_instance.Event() event[activity_key] = trans.label event[timestamp_key] = datetime.datetime.fromtimestamp( curr_timestamp) trace.append(event) # increases by 1 second curr_timestamp += 1 marking = semantics.execute(trans, net, marking) log.append(trace) return log
def activity_concurrent(self, l, activities, activity_key, parameters=None): from pm4py.algo.discovery.inductive.variants.im.data_structures import subtree_plain as subtree small_log = log.EventLog() test_log = log.EventLog() key = None activities_copy = copy(activities) empty_trace = log.Trace() idx = index_containing(l, activities, activity_key) for key, value in activities_copy.items( ): # iterate through activities (saved in key) test_log = filter_activity_use_idx(l, key, activity_key, idx) #test_log = filter_activity_from_log(l, key, activity_key) # unsure about this one: contains_empty_trace = False for trace in test_log: if len(trace) == 0: contains_empty_trace = True if contains_empty_trace: continue # more efficient deepcopy self_copy = deepcopy(self) cut = subtree.SubtreePlain.check_for_cut( self_copy, test_log, key, parameters=parameters ) # check if leaving out act, leads to finding cut if cut: # save act to small_trace, so that it can be appended as leaf later on for trace in l: small_trace = log.Trace() contains_activity = False for element in trace: if element[activity_key] == key: contains_activity = True small_trace.append(element) small_log.append(small_trace) if not contains_activity: small_log.append(empty_trace) logging_output = "activity concurrent: " + str(key) logging.debug(logging_output) return True, test_log, small_log, key # if so, return new log return False, test_log, small_log, key # if, after iterating through all act's still no cut is found, return false
def cut_trace_between_two_points(trace, point_a, point_b): cutted_trace = log.Trace() # we have to use <= although in the paper the intervall is [) because our index starts at 0 while point_a < point_b: cutted_trace.append(trace[point_a]) point_a += 1 return cutted_trace
def get_best_worst_cost(petri_net, initial_marking, final_marking, parameters=None): trace = log_implementation.Trace() best_worst, cf = align(trace, petri_net, initial_marking, final_marking, parameters=parameters) best_worst_cost = sum(cf[x] for x in best_worst['alignment']) // utils.STD_MODEL_LOG_MOVE_COST if best_worst else 0 return best_worst_cost
def transform_event_stream_to_event_log( log, case_glue=pmutil.constants.CASE_ATTRIBUTE_GLUE, include_case_attributes=True, case_attribute_prefix=pmutil.constants.CASE_ATTRIBUTE_PREFIX, enable_deepcopy=False): """ Converts the event stream to an event log Parameters ---------- log: :class:`pm4py.log.log.EventLog` An event stream case_glue: Case identifier. Default is 'case:concept:name' include_case_attributes: Default is True case_attribute_prefix: Default is 'case:' enable_deepcopy Enables deepcopy (avoid references between input and output objects) Returns ------- log : :class:`pm4py.log.log.EventLog` An event log """ if enable_deepcopy: log = deepcopy(log) traces = {} for orig_event in log: event = copy(orig_event) glue = event[case_glue] if glue not in traces: trace_attr = {} if include_case_attributes: for k in event.keys(): if k.startswith(case_attribute_prefix): trace_attr[k.replace(case_attribute_prefix, '')] = event[k] if xes.DEFAULT_TRACEID_KEY not in trace_attr: trace_attr[xes.DEFAULT_TRACEID_KEY] = glue traces[glue] = log_instance.Trace(attributes=trace_attr) if include_case_attributes: for k in list(event.keys()): if k.startswith(case_attribute_prefix): del event[k] traces[glue].append(event) return log_instance.EventLog(traces.values(), attributes=log.attributes, classifiers=log.classifiers, omni_present=log.omni_present, extensions=log.extensions)
def split_before_start(trace, start_activities, activity_key): # if there is only one activity, there is nothing to split if len(trace) == 1: return trace, trace, False # if none of the above cases apply, we split at the occurence of a start activity found_split = False new_trace_1 = log.Trace() new_trace_2 = log.Trace() i = 1 while not found_split and i < len(trace): # for all events in trace if trace[i][activity_key] in start_activities and len(trace) > 1: found_split = True for j in range(0, i): new_trace_1.append(trace[j]) for k in range(i, len(trace)): new_trace_2.append(trace[k]) i += 1 return new_trace_1, new_trace_2, found_split
def split_parallel(cut, l, activity_key): new_logs = [] for c in cut: lo = log.EventLog() for trace in l: new_trace = log.Trace() for event in trace: if event[activity_key] in c: new_trace.append(event) lo.append(new_trace) new_logs.append(lo) return new_logs
def apply_from_variants_list(var_list, petri_net, initial_marking, final_marking, parameters=None): """ Apply the alignments from the specification of a list of variants in the log Parameters ------------- var_list List of variants (for each item, the first entry is the variant itself, the second entry may be the number of cases) petri_net Petri net initial_marking Initial marking final_marking Final marking parameters Parameters of the algorithm (same as 'apply' method, plus 'variant_delimiter' that is , by default) Returns -------------- dictio_alignments Dictionary that assigns to each variant its alignment """ if parameters is None: parameters = {} activity_key = DEFAULT_NAME_KEY if parameters is None or PARAMETER_CONSTANT_ACTIVITY_KEY not in parameters else \ parameters[ pm4pyutil.constants.PARAMETER_CONSTANT_ACTIVITY_KEY] variant_delimiter = exec_utils.get_param_value( Parameters.PARAMETER_VARIANT_DELIMITER, parameters, pm4pyutil.constants.DEFAULT_VARIANT_SEP) log = log_implementation.EventLog() dictio_alignments = {} for varitem in var_list: variant = varitem[0] trace = log_implementation.Trace() variant_split = variant.split( variant_delimiter) if type(variant) is str else variant for el in variant_split: trace.append(log_implementation.Event({activity_key: el})) log.append(trace) alignment = apply(log, petri_net, initial_marking, final_marking) for index, varitem in enumerate(var_list): variant = varitem[0] dictio_alignments[variant] = alignment[index] return dictio_alignments
def apply_from_variant(variant, petri_net, initial_marking, final_marking, parameters=None): if parameters is None: parameters = {} activity_key = DEFAULT_NAME_KEY if parameters is None or PARAMETER_CONSTANT_ACTIVITY_KEY not in parameters else \ parameters[ pm4pyutil.constants.PARAMETER_CONSTANT_ACTIVITY_KEY] trace = log_implementation.Trace() variant_delimiter = parameters[ PARAMETER_VARIANT_DELIMITER] if PARAMETER_VARIANT_DELIMITER in parameters else DEFAULT_VARIANT_DELIMITER variant_split = variant.split(variant_delimiter) if type(variant) is str else variant for i in range(len(variant_split)): trace.append(log_implementation.Event({activity_key: variant_split[i]})) return apply(trace, petri_net, initial_marking, final_marking, parameters=parameters)
def filter_activity_from_log(l, act, activity_key): # remove the activity from every trace in the log # as trace doesnt have remove function, we just create new traces without chosen_activity act_str = str(act) new_log = log.EventLog() for trace in l: new_trace = log.Trace() for event in trace: if not event[activity_key] == act_str: new_trace.append(event) new_log.append(new_trace) return new_log
def split_between_end_and_start(trace, start_activities, end_activities, activity_key): # splits a trace between the first occurrence of an end activity following a start activity found_split = False new_trace_1 = log.Trace() new_trace_2 = log.Trace() i = 0 while not found_split and i < len(trace) - 1: if trace[i][activity_key] in end_activities and trace[i + 1][activity_key] in start_activities: found_split = True j = 0 while j <= i: new_trace_1.append(trace[j]) j += 1 for k in range(i + 1, len(trace)): new_trace_2.append(trace[k]) break else: i += 1 if not found_split: new_trace_1 = trace return new_trace_1, new_trace_2, found_split
def act_once_per_trace(l, activities, activity_key): small_log = log.EventLog() small_trace = log.Trace() new_log = log.EventLog() number_of_traces = len(l) possible_activities = list() # transform dict of activities to list activities_dict = activities for key, value in activities_dict.items(): # if activity appears as often as there are traces, add to list of possible activities: if value == number_of_traces: possible_activities.append(key) chosen_activity = None # find an activity that appears exactly once per trace and save it in chose_activity for act in possible_activities: fits_log = True for trace in l: fits_trace = False for element in trace: # enough to check if element occurs once per trace as number of occurrences equals the number of traces if act == element[activity_key]: fits_trace = True if not fits_trace: fits_log = False if fits_log: chosen_activity = act break # save the chosen activity in a new trace, so that it can later be appended as leaf to our subtree for trace in l: if len(small_trace) > 0: break for element in trace: if element[activity_key] == chosen_activity: small_trace.append(element) small_log.append(small_trace) break if chosen_activity is not None: new_log = filter_activity_from_log(l, chosen_activity, activity_key) logging_output = "activity once per trace: " + str(chosen_activity) logging.debug(logging_output) return True, new_log, small_log else: return False, new_log, chosen_activity
def transform_event_log_to_trace_log( log, case_glue=log_util.CASE_ATTRIBUTE_GLUE, includes_case_attributes=True, case_attribute_prefix=log_util.CASE_ATTRIBUTE_PREFIX): """ Converts the event log to a trace log Parameters ---------- log: :class:`pm4py.log.log.EventLog` An event Log case_glue: Case identifier. Default is 'case:concept:name' includes_case_attributes: Default is True case_attribute_prefix: Default is 'case:' Returns ------- log : :class:`pm4py.log.log.TraceLog` A trace log """ traces = {} for event in log: glue = event[case_glue] if glue not in traces: trace_attr = {} if includes_case_attributes: for k in event.keys(): if k.startswith(case_attribute_prefix): trace_attr[k.replace(case_attribute_prefix, '')] = event[k] traces[glue] = log_instance.Trace(attributes=trace_attr) if includes_case_attributes: for k in list(event.keys()): if k.startswith(case_attribute_prefix): del event[k] traces[glue].append(event) return log_instance.TraceLog(traces.values(), attributes=log.attributes, classifiers=log.classifiers, omni_present=log.omni_present, extensions=log.extensions)
def generate_pm4py_log(trace_frequencies): log = event_log.EventLog() trace_count = 0 for variant in trace_frequencies.items(): frequency=variant[1] activities=variant[0].split(EVENT_DELIMETER) for i in range (0,frequency): trace = event_log.Trace() trace.attributes["concept:name"] = trace_count trace_count = trace_count + 1 for activity in activities: if not TRACE_END in activity: event = event_log.Event() event["concept:name"] = str(activity) event["time:timestamp"] = datetime.datetime(1970, 1, 1, 0, 0, 0, tzinfo=tzutc()) trace.append(event) log.append(trace) return log
def filter_activity_use_idx(l, act, activity_key, idx): act_str = str(act) i_act = idx[act] new_log = log.EventLog() i = 0 j = 0 while i < len(l): if j < len(i_act) and i == i_act[j]: new_trace = log.Trace() for event in l[i]: if not event[activity_key] == act_str: new_trace.append(event) new_log.append(new_trace) j = j + 1 else: new_log.append(l[i]) i = i + 1 return new_log
def apply_playout(net, initial_marking, no_traces=100, max_trace_length=100): """ Do the playout of a Petrinet generating a log Parameters ---------- net Petri net to play-out initial_marking Initial marking of the Petri net no_traces Number of traces to generate max_trace_length Maximum number of events per trace (do break) """ # assigns to each event an increased timestamp from 1970 curr_timestamp = 10000000 log = log_instance.EventLog() for i in range(no_traces): trace = log_instance.Trace() trace.attributes["concept:name"] = str(i) marking = copy(initial_marking) for j in range(100000): if not semantics.enabled_transitions(net, marking): break all_enabled_trans = semantics.enabled_transitions(net, marking) all_enabled_trans = list(all_enabled_trans) shuffle(all_enabled_trans) trans = all_enabled_trans[0] if trans.label is not None: event = log_instance.Event() event["concept:name"] = trans.label event["time:timestamp"] = datetime.datetime.fromtimestamp( curr_timestamp) trace.append(event) # increases by 1 second curr_timestamp = curr_timestamp + 1 marking = semantics.execute(trans, net, marking) if len(trace) > max_trace_length: break if len(trace) > 0: log.append(trace) return log
def filter_trace(f: Callable[[Any], bool], trace: log_inst.Trace) -> log_inst.Trace: """ Filters the trace according to a given (lambda) function. Parameters ---------- f function that specifies the filter criterion, may be a lambda trace trace; PM4Py trace object Returns ------- trace filtered trace if object provided is correct; original log if not correct """ if isinstance(trace, log_inst.Trace): return log_inst.Trace(list(filter(f, trace)), attributes=trace.attributes) else: warnings.warn('input trace object is not of the appropriate type, filter() not applied')
def sort_trace(trace: log_inst.Trace, key, reverse: bool = False) -> log_inst.Trace: """ Parameters ---------- trace input trace key sorting key reverse indicate whether sorting should be reversed (default False) Returns ------- sorted trace if object provided is correct; original log if not correct """ if isinstance(trace, log_inst.Trace): return log_inst.Trace(sorted(trace, key=key, reverse=reverse)) else: warnings.warn('input trace object not of appropriate type, sorted() not applied') return trace
def get_best_worst_cost(petri_net, initial_marking, final_marking, parameters=None): trace = log_implementation.Trace() new_parameters = copy(parameters) new_parameters[Parameters.PARAM_TRACE_COST_FUNCTION] = list( map(lambda e: utils.STD_MODEL_LOG_MOVE_COST, trace)) best_worst, cf = align(trace, petri_net, initial_marking, final_marking, parameters=new_parameters) cf_new = {} for el in cf: cf_new[(el.name, el.label)] = cf[el] best_worst_cost = sum( cf_new[x] for x in best_worst['alignment'] ) // utils.STD_MODEL_LOG_MOVE_COST if best_worst['alignment'] else 0 return best_worst_cost
def generate_pm4py_log(df_relations, event_int_mapping): int_event_mapping = {value:key for key, value in event_int_mapping.items()} log = event_log.EventLog() size = df_relations.shape[0]-1 #print(np.sum(df_relations[0]),np.sum(df_relations,axis=0)[size]) trace_amount = min(np.sum(df_relations[0]),np.sum(df_relations,axis=0)[size]) possible_elements = list(range(0,size+1)) counter = 0 while(counter < trace_amount): empty_list=[0] next_trace = find_path(df_relations,possible_elements ,empty_list,0) #print("trace nr.: ",counter,next_trace) if len(next_trace) <= 1: print("All traces attached to log.") break trace = event_log.Trace() trace.attributes["concept:name"] = counter counter += 1 for i in range(len(next_trace)-1): #print(df_relations[next_trace[i],next_trace[i+1]]) #if df_relations[next_trace[i],next_trace[i+1]] > 0: # df_relations[next_trace[i],next_trace[i+1]] -= 1 if str(int_event_mapping[next_trace[i]]) == TRACE_START: continue event = event_log.Event() event["concept:name"] = str(int_event_mapping[next_trace[i]]) event["time:timestamp"] = datetime.datetime(1970, 1, 1, 0, 0, 0, tzinfo=tzutc()) trace.append(event) log.append(trace) return log
def apply(net, initial_marking, final_marking=None, parameters=None): """ Do the playout of a Petrinet generating a log (extensive search; stop at the maximum trace length specified Parameters ----------- net Petri net to play-out initial_marking Initial marking of the Petri net final_marking If provided, the final marking of the Petri net parameters Parameters of the algorithm: Parameters.MAX_TRACE_LENGTH -> Maximum trace length """ if parameters is None: parameters = {} case_id_key = exec_utils.get_param_value(Parameters.CASE_ID_KEY, parameters, xes_constants.DEFAULT_TRACEID_KEY) activity_key = exec_utils.get_param_value(Parameters.ACTIVITY_KEY, parameters, xes_constants.DEFAULT_NAME_KEY) timestamp_key = exec_utils.get_param_value( Parameters.TIMESTAMP_KEY, parameters, xes_constants.DEFAULT_TIMESTAMP_KEY) max_trace_length = exec_utils.get_param_value(Parameters.MAX_TRACE_LENGTH, parameters, 10) return_elements = exec_utils.get_param_value(Parameters.RETURN_ELEMENTS, parameters, False) max_marking_occ = exec_utils.get_param_value(Parameters.MAX_MARKING_OCC, parameters, sys.maxsize) # assigns to each event an increased timestamp from 1970 curr_timestamp = 10000000 feasible_elements = [] to_visit = [(initial_marking, (), ())] visited = set() while len(to_visit) > 0: state = to_visit.pop(0) m = state[POSITION_MARKING] trace = state[POSITION_TRACE] elements = state[POSITION_ELEMENTS] if (m, trace) in visited: continue visited.add((m, trace)) en_t = semantics.enabled_transitions(net, m) if (final_marking is not None and m == final_marking) or (final_marking is None and len(en_t) == 0): if len(trace) <= max_trace_length: feasible_elements.append(elements) for t in en_t: new_elements = elements + (m, ) new_elements = new_elements + (t, ) counter_elements = Counter(new_elements) if counter_elements[m] > max_marking_occ: continue new_m = semantics.weak_execute(t, m) if t.label is not None: new_trace = trace + (t.label, ) else: new_trace = trace new_state = (new_m, new_trace, new_elements) if new_state in visited or len(new_trace) > max_trace_length: continue to_visit.append(new_state) if return_elements: return feasible_elements log = log_instance.EventLog() for elements in feasible_elements: log_trace = log_instance.Trace() log_trace.attributes[case_id_key] = str(len(log)) activities = [ x.label for x in elements if type(x) is PetriNet.Transition and x.label is not None ] for act in activities: curr_timestamp = curr_timestamp + 1 log_trace.append( log_instance.Event({ activity_key: act, timestamp_key: datetime.datetime.fromtimestamp(curr_timestamp) })) log.append(log_trace) return log
def apply_playout(net, initial_marking, no_traces=100, max_trace_length=100, case_id_key=xes_constants.DEFAULT_TRACEID_KEY, activity_key=xes_constants.DEFAULT_NAME_KEY, timestamp_key=xes_constants.DEFAULT_TIMESTAMP_KEY, final_marking=None, smap=None, log=None, return_visited_elements=False): """ Do the playout of a Petrinet generating a log Parameters ---------- net Petri net to play-out initial_marking Initial marking of the Petri net no_traces Number of traces to generate max_trace_length Maximum number of events per trace (do break) case_id_key Trace attribute that is the case ID activity_key Event attribute that corresponds to the activity timestamp_key Event attribute that corresponds to the timestamp final_marking If provided, the final marking of the Petri net smap Stochastic map log Log """ if final_marking is None: # infer the final marking from the net final_marking = final_marking_discovery.discover_final_marking(net) if smap is None: if log is None: raise Exception("please provide at least one between stochastic map and log") smap = replay.get_map_from_log_and_net(log, net, initial_marking, final_marking, parameters={Parameters.ACTIVITY_KEY: activity_key, Parameters.TIMESTAMP_KEY: timestamp_key}) # assigns to each event an increased timestamp from 1970 curr_timestamp = 10000000 all_visited_elements = [] for i in range(no_traces): visited_elements = [] visible_transitions_visited = [] marking = copy(initial_marking) while len(visible_transitions_visited) < max_trace_length: visited_elements.append(marking) if not semantics.enabled_transitions(net, marking): # supports nets with possible deadlocks break all_enabled_trans = semantics.enabled_transitions(net, marking) if final_marking is not None and marking == final_marking: en_t_list = list(all_enabled_trans.union({None})) else: en_t_list = list(all_enabled_trans) trans = stochastic_utils.pick_transition(en_t_list, smap) if trans is None: break visited_elements.append(trans) if trans.label is not None: visible_transitions_visited.append(trans) marking = semantics.execute(trans, net, marking) all_visited_elements.append(tuple(visited_elements)) if return_visited_elements: return all_visited_elements log = log_instance.EventLog() for index, visited_elements in enumerate(all_visited_elements): trace = log_instance.Trace() trace.attributes[case_id_key] = str(index) for element in visited_elements: if type(element) is PetriNet.Transition and element.label is not None: event = log_instance.Event() event[activity_key] = element.label event[timestamp_key] = datetime.datetime.fromtimestamp(curr_timestamp) trace.append(event) # increases by 1 second curr_timestamp += 1 log.append(trace) return log
def apply(net, initial_marking, final_marking=None, parameters=None): """ Do the playout of a Petrinet generating a log (extensive search; stop at the maximum trace length specified Parameters ----------- net Petri net to play-out initial_marking Initial marking of the Petri net final_marking If provided, the final marking of the Petri net parameters Parameters of the algorithm: Parameters.MAX_TRACE_LENGTH -> Maximum trace length """ if parameters is None: parameters = {} case_id_key = exec_utils.get_param_value(Parameters.CASE_ID_KEY, parameters, xes_constants.DEFAULT_TRACEID_KEY) activity_key = exec_utils.get_param_value(Parameters.ACTIVITY_KEY, parameters, xes_constants.DEFAULT_NAME_KEY) timestamp_key = exec_utils.get_param_value( Parameters.TIMESTAMP_KEY, parameters, xes_constants.DEFAULT_TIMESTAMP_KEY) max_trace_length = exec_utils.get_param_value(Parameters.MAX_TRACE_LENGTH, parameters, 10) # assigns to each event an increased timestamp from 1970 curr_timestamp = 10000000 log = log_instance.EventLog() to_visit = [(initial_marking, ())] visited = set() while len(to_visit) > 0: state = to_visit.pop(0) if state in visited: continue visited.add(state) m = state[POSITION_MARKING] trace = state[POSITION_TRACE] en_t = semantics.enabled_transitions(net, m) if (final_marking is not None and m == final_marking) or len(en_t) == 0: if len(trace) <= max_trace_length: log_trace = log_instance.Trace() log_trace.attributes[case_id_key] = str(len(log)) for act in trace: curr_timestamp = curr_timestamp + 1 log_trace.append( log_instance.Event({ activity_key: act, timestamp_key: datetime.datetime.fromtimestamp(curr_timestamp) })) log.append(log_trace) for t in en_t: new_m = semantics.weak_execute(t, m) if t.label is not None: new_trace = trace + (t.label, ) else: new_trace = trace new_state = (new_m, new_trace) if new_state in visited or len(new_trace) > max_trace_length: continue to_visit.append(new_state) return log