def test_variant_state_eq_a_star(self): import pm4py log = pm4py.read_xes("input_data/running-example.xes") net, im, fm = pm4py.discover_petri_net_inductive(log) align_alg.apply( log, net, im, fm, variant=align_alg.Variants.VERSION_STATE_EQUATION_A_STAR)
def test_variant_dijkstra_less_memory(self): import pm4py log = pm4py.read_xes("input_data/running-example.xes") net, im, fm = pm4py.discover_petri_net_inductive(log) align_alg.apply( log, net, im, fm, variant=align_alg.Variants.VERSION_DIJKSTRA_LESS_MEMORY)
def test_alignment(self): log = xes_importer.apply(os.path.join("input_data", "running-example.xes")) from pm4py.algo.discovery.alpha import algorithm as alpha_miner net, im, fm = alpha_miner.apply(log) from pm4py.algo.conformance.alignments.petri_net import algorithm as alignments aligned_traces = alignments.apply(log, net, im, fm, variant=alignments.Variants.VERSION_STATE_EQUATION_A_STAR) aligned_traces = alignments.apply(log, net, im, fm, variant=alignments.Variants.VERSION_DIJKSTRA_NO_HEURISTICS) from pm4py.algo.evaluation.replay_fitness import algorithm as rp_fitness_evaluator fitness = rp_fitness_evaluator.apply(log, net, im, fm, variant=rp_fitness_evaluator.Variants.ALIGNMENT_BASED) evaluation = rp_fitness_evaluator.evaluate(aligned_traces, variant=rp_fitness_evaluator.Variants.ALIGNMENT_BASED) from pm4py.algo.evaluation.precision import algorithm as precision_evaluator precision = precision_evaluator.apply(log, net, im, fm, variant=rp_fitness_evaluator.Variants.ALIGNMENT_BASED)
def conformance_diagnostics_alignments(log: EventLog, *args, multi_processing: bool = False) -> List[Dict[str, Any]]: """ Apply the alignments algorithm between a log and a process model. The methods return the full alignment diagnostics. Parameters ------------- log Event log args Specification of the process model multi_processing Boolean value that enables the multiprocessing (default: False) Returns ------------- aligned_traces A list of alignments for each trace of the log (in the same order as the traces in the event log) """ if type(log) not in [pd.DataFrame, EventLog, EventStream]: raise Exception("the method can be applied only to a traditional event log!") if len(args) == 3: if type(args[0]) is PetriNet: # Petri net alignments from pm4py.algo.conformance.alignments.petri_net import algorithm as alignments if multi_processing: return alignments.apply_multiprocessing(log, args[0], args[1], args[2], parameters=get_properties(log)) else: return alignments.apply(log, args[0], args[1], args[2], parameters=get_properties(log)) elif type(args[0]) is dict or type(args[0]) is Counter: # DFG alignments from pm4py.algo.conformance.alignments.dfg import algorithm as dfg_alignment return dfg_alignment.apply(log, args[0], args[1], args[2], parameters=get_properties(log)) elif len(args) == 1: if type(args[0]) is ProcessTree: # process tree alignments from pm4py.algo.conformance.alignments.process_tree.variants import search_graph_pt if multi_processing: return search_graph_pt.apply_multiprocessing(log, args[0], parameters=get_properties(log)) else: return search_graph_pt.apply(log, args[0], parameters=get_properties(log)) # try to convert to Petri net import pm4py from pm4py.algo.conformance.alignments.petri_net import algorithm as alignments net, im, fm = pm4py.convert_to_petri_net(*args) if multi_processing: return alignments.apply_multiprocessing(log, net, im, fm, parameters=get_properties(log)) else: return alignments.apply(log, net, im, fm, parameters=get_properties(log))
def conformance_alignments(log: EventLog, petri_net: PetriNet, initial_marking: Marking, final_marking: Marking) -> List[Dict[str, Any]]: warnings.warn('conformance_alignments is deprecated, use conformance_diagnostics_alignments', DeprecationWarning) """ Apply the alignments algorithm between a log and a Petri net The methods return the full alignment diagnostics. Parameters ------------- log Event log petri_net Petri net initial_marking Initial marking final_marking Final marking Returns ------------- aligned_traces A list of alignments for each trace of the log """ if type(log) not in [pd.DataFrame, EventLog, EventStream]: raise Exception("the method can be applied only to a traditional event log!") from pm4py.algo.conformance.alignments.petri_net import algorithm as alignments return alignments.apply(log, petri_net, initial_marking, final_marking, parameters=get_properties(log))
def conformance_alignments(log: EventLog, petri_net: PetriNet, initial_marking: Marking, final_marking: Marking) -> List[Dict[str, Any]]: warnings.warn('conformance_alignments is deprecated, use conformance_diagnostics_alignments', DeprecationWarning) """ Apply the alignments algorithm between a log and a Petri net The methods return the full alignment diagnostics. Parameters ------------- log Event log petri_net Petri net initial_marking Initial marking final_marking Final marking Returns ------------- aligned_traces A list of alignments for each trace of the log """ from pm4py.algo.conformance.alignments.petri_net import algorithm as alignments return alignments.apply(log, petri_net, initial_marking, final_marking)
def test_importingPetriLogAlignment(self): # to avoid static method warnings in tests, # that by construction of the unittest package have to be expressed in such way self.dummy_variable = "dummy_value" imported_petri1, marking1, fmarking1 = petri_importer.apply( os.path.join(INPUT_DATA_DIR, "running-example.pnml")) log = xes_importer.apply( os.path.join(INPUT_DATA_DIR, "running-example.xes")) final_marking = petri_net.obj.Marking() for p in imported_petri1.places: if not p.out_arcs: final_marking[p] = 1 for trace in log: cf_result = align_alg.apply( trace, imported_petri1, marking1, final_marking, variant=align_alg.VERSION_DIJKSTRA_NO_HEURISTICS)['alignment'] is_fit = True for couple in cf_result: if not (couple[0] == couple[1] or couple[0] == ">>" and couple[1] is None): is_fit = False if not is_fit: raise Exception("should be fit")
def test_alignment(self): log = xes_importer.apply( os.path.join("input_data", "running-example.xes")) from pm4py.algo.discovery.alpha import algorithm as alpha_miner net, im, fm = alpha_miner.apply(log) from pm4py.algo.conformance.alignments.petri_net import algorithm as alignments aligned_traces = alignments.apply( log, net, im, fm, variant=alignments.Variants.VERSION_STATE_EQUATION_A_STAR) aligned_traces = alignments.apply( log, net, im, fm, variant=alignments.Variants.VERSION_DIJKSTRA_NO_HEURISTICS)
def execute_script(): log = pm4py.read_xes( os.path.join("..", "tests", "input_data", "running-example.xes")) filtered_log = pm4py.filter_variants_top_k(log, 1) net, im, fm = pm4py.discover_petri_net_inductive(filtered_log) aligned_traces = alignments.apply( log, net, im, fm, parameters={"ret_tuple_as_trans_desc": True}) enriched_log = log_enrichment.apply(log, aligned_traces) print(enriched_log)
def test_inductiveminer_log(self): log = xes_importer.apply(os.path.join("input_data", "running-example.xes")) net, im, fm = inductive_miner.apply(log) aligned_traces_tr = tr_alg.apply(log, net, im, fm) aligned_traces_alignments = align_alg.apply(log, net, im, fm) evaluation = eval_alg.apply(log, net, im, fm) fitness = rp_fit.apply(log, net, im, fm) precision = precision_evaluator.apply(log, net, im, fm) gen = generalization.apply(log, net, im, fm) sim = simplicity.apply(net)
def test_inductiveminer_df(self): log = pd.read_csv(os.path.join("input_data", "running-example.csv")) log = dataframe_utils.convert_timestamp_columns_in_df(log) net, im, fm = inductive_miner.apply(log) aligned_traces_tr = tr_alg.apply(log, net, im, fm) aligned_traces_alignments = align_alg.apply(log, net, im, fm) evaluation = eval_alg.apply(log, net, im, fm) fitness = rp_fit.apply(log, net, im, fm) precision = precision_evaluator.apply(log, net, im, fm) gen = generalization.apply(log, net, im, fm) sim = simplicity.apply(net)
def test_inductiveminer_stream(self): df = pd.read_csv(os.path.join("input_data", "running-example.csv")) df = dataframe_utils.convert_timestamp_columns_in_df(df) stream = log_conversion.apply(df, variant=log_conversion.TO_EVENT_STREAM) net, im, fm = inductive_miner.apply(stream) aligned_traces_tr = tr_alg.apply(stream, net, im, fm) aligned_traces_alignments = align_alg.apply(stream, net, im, fm) evaluation = eval_alg.apply(stream, net, im, fm) fitness = rp_fit.apply(stream, net, im, fm) precision = precision_evaluator.apply(stream, net, im, fm) gen = generalization.apply(stream, net, im, fm) sim = simplicity.apply(net)
def execute_script(): log = importer.apply( os.path.join("..", "tests", "input_data", "running-example.xes")) net, im, fm = inductive_miner.apply(log) aligned_traces = alignments.apply(log, net, im, fm) gviz = visualizer.apply( log, aligned_traces, parameters={ visualizer.Variants.CLASSIC.value.Parameters.FORMAT: "svg" }) visualizer.view(gviz)
def execute_script(): log = pm4py.read_xes( os.path.join("..", "tests", "input_data", "receipt.xes")) print("number of cases", len(log)) print("number of events", sum(len(x) for x in log)) print("number of variants", len(pm4py.get_variants(log))) ac = get.get_attribute_values(log, "concept:name") dfg, sa, ea = pm4py.discover_dfg(log) perc = 0.5 dfg, sa, ea, ac = dfg_filtering.filter_dfg_on_activities_percentage( dfg, sa, ea, ac, perc) dfg, sa, ea, ac = dfg_filtering.filter_dfg_on_paths_percentage( dfg, sa, ea, ac, perc) aa = time.time() aligned_traces = dfg_alignment.apply(log, dfg, sa, ea) bb = time.time() net, im, fm = pm4py.convert_to_petri_net(dfg, sa, ea) for trace in aligned_traces: if trace["cost"] != trace["internal_cost"]: print(trace) pass print(bb - aa) print(sum(x["visited_states"] for x in aligned_traces)) print( sum(x["cost"] // align_utils.STD_MODEL_LOG_MOVE_COST for x in aligned_traces)) gviz = visualizer.apply(dfg, activities_count=ac, parameters={ "start_activities": sa, "end_activities": ea, "format": "svg" }) visualizer.view(gviz) cc = time.time() aligned_traces2 = petri_alignments.apply( log, net, im, fm, variant=petri_alignments.Variants.VERSION_DIJKSTRA_LESS_MEMORY) dd = time.time() print(dd - cc) print(sum(x["visited_states"] for x in aligned_traces2)) print( sum(x["cost"] // align_utils.STD_MODEL_LOG_MOVE_COST for x in aligned_traces2))
def testNoSynchronousDiscountedAlignment(): ''' This function runs an alignment based on the discounted edit distance By using the Petri net and petri_net.utils.align_utils.discountedEditDistance function ''' log_path = os.path.join("..", "tests", "input_data", "running-example.xes") pnml_path = os.path.join("..", "tests", "input_data", "running-example.pnml") log = xes_importer.apply(log_path) net, marking, fmarking = petri_importer.apply(pnml_path) start=time.time() alignments1 = ali.apply(log._list[0], net, marking, fmarking, variant=ali.VERSION_DISCOUNTED_A_STAR, parameters={ali.Parameters.SYNCHRONOUS:False,ali.Parameters.EXPONENT:1.1}) print(alignments1) print("Time:",(time.time()-start))
def test_alignment_pnml(self): # to avoid static method warnings in tests, # that by construction of the unittest package have to be expressed in such way self.dummy_variable = "dummy_value" log = xes_importer.apply( os.path.join(INPUT_DATA_DIR, "running-example.xes")) net, marking, final_marking = inductive_miner.apply(log) for trace in log: cf_result = \ align_alg.apply(trace, net, marking, final_marking, variant=align_alg.VERSION_DIJKSTRA_NO_HEURISTICS)[ 'alignment'] is_fit = True for couple in cf_result: if not (couple[0] == couple[1] or couple[0] == ">>" and couple[1] is None): is_fit = False if not is_fit: raise Exception("should be fit")
def apply(log, petri_net, initial_marking, final_marking, align_variant=alignments.DEFAULT_VARIANT, parameters=None): """ Evaluate fitness based on alignments Parameters ---------------- log Event log petri_net Petri net initial_marking Initial marking final_marking Final marking align_variant Variants of the alignments to apply parameters Parameters of the algorithm Returns --------------- dictionary Containing two keys (percFitTraces and averageFitness) """ if align_variant == decomp_alignments.Variants.RECOMPOS_MAXIMAL.value: alignment_result = decomp_alignments.apply(log, petri_net, initial_marking, final_marking, variant=align_variant, parameters=parameters) else: alignment_result = alignments.apply(log, petri_net, initial_marking, final_marking, variant=align_variant, parameters=parameters) return evaluate(alignment_result)
def execute_script(): log = pm4py.read_xes(os.path.join("..", "tests", "input_data", "roadtraffic100traces.xes")) net, im, fm = pm4py.read_pnml(os.path.join("..", "tests", "input_data", "data_petri_net.pnml")) pm4py.view_petri_net(net, im, fm, format="svg") aligned_traces = alignments.apply(log, net, im, fm, variant=alignments.Variants.VERSION_DIJKSTRA_LESS_MEMORY, parameters={"ret_tuple_as_trans_desc": True}) for index, trace in enumerate(log): aligned_trace = aligned_traces[index] al = [(x[0][0], get_trans_by_name(net, x[0][1])) for x in aligned_trace["alignment"]] m = DataMarking(im) idx = 0 for el in al: if el[1] is not None: en_t = semantics.enabled_transitions(net, m, trace[min(idx, len(trace) - 1)]) if el[1] in en_t: if "guard" in el[1].properties: print(el[1], "GUARD SATISFIED", el[1].properties["guard"], m) m = semantics.execute(el[1], net, m, trace[min(idx, len(trace) - 1)]) else: print("TRANSITION UNAVAILABLE! Guards are blocking") if el[0] != ">>": idx = idx + 1
def testSynchronousDiscountedAlignment(): ''' This function runs an alignment based on the discounted edit distance By using the synchronous product :return: ''' log_path = os.path.join("..", "tests", "input_data", "running-example.xes") pnml_path = os.path.join("..", "tests", "input_data", "running-example.pnml") log = xes_importer.apply(log_path) net, marking, fmarking = petri_importer.apply(pnml_path) # to see the net : #vizu(net,marking,fmarking).view() start=time.time() alignments1 = ali.apply(log._list[0], net, marking, fmarking, variant=ali.VERSION_DISCOUNTED_A_STAR, parameters={ali.Parameters.SYNCHRONOUS:True,ali.Parameters.EXPONENT:1.1}) print(alignments1) print("Time:",(time.time()-start))
def apply(log, petri_net, initial_marking, final_marking, align_variant=alignments.DEFAULT_VARIANT, parameters=None): """ Evaluate fitness based on alignments Parameters ---------------- log Event log petri_net Petri net initial_marking Initial marking final_marking Final marking align_variant Variants of the alignments to apply parameters Parameters of the algorithm Returns --------------- dictionary Containing two keys (percFitTraces and averageFitness) """ if parameters is None: parameters = {} multiprocessing = exec_utils.get_param_value(Parameters.MULTIPROCESSING, parameters, False) if align_variant == decomp_alignments.Variants.RECOMPOS_MAXIMAL.value: alignment_result = decomp_alignments.apply(log, petri_net, initial_marking, final_marking, variant=align_variant, parameters=parameters) else: if multiprocessing: alignment_result = alignments.apply_multiprocessing(log, petri_net, initial_marking, final_marking, variant=align_variant, parameters=parameters) else: alignment_result = alignments.apply(log, petri_net, initial_marking, final_marking, variant=align_variant, parameters=parameters) return evaluate(alignment_result)
def get_alignments_decoration(net, im, fm, log=None, aligned_traces=None, parameters=None): """ Get a decoration for the Petri net based on alignments Parameters ------------- net Petri net im Initial marking fm Final marking log Event log aligned_traces Aligned traces parameters Parameters of the algorithm Returns ------------- decorations Decorations to use """ if parameters is None: parameters = {} if aligned_traces is None and log is not None: from pm4py.algo.conformance.alignments.petri_net import algorithm as alignments aligned_traces = alignments.apply( log, net, im, fm, parameters={"ret_tuple_as_trans_desc": True}) decorations = {} net_transitions = {} for trans in net.transitions: net_transitions[trans.name] = trans for align_trace0 in aligned_traces: align_trace = align_trace0["alignment"] for move in align_trace: move_trans_name = move[0][1] activity_trace_name = move[0][0] if move_trans_name in net_transitions: trans = net_transitions[move_trans_name] if trans not in decorations: decorations[trans] = { "count_fit": 0, "count_move_on_model": 0 } if activity_trace_name == ">>": decorations[trans]["count_move_on_model"] = decorations[ trans]["count_move_on_model"] + 1 else: decorations[trans][ "count_fit"] = decorations[trans]["count_fit"] + 1 for trans in decorations: if trans.label is not None: decorations[trans]["label"] = trans.label + " (" + str( decorations[trans]["count_move_on_model"]) + "," + str( decorations[trans]["count_fit"]) + ")" decorations[trans]["color"] = get_transitions_color( decorations[trans]["count_move_on_model"], decorations[trans]["count_fit"]) return decorations
def f(): aa = time.time() aligned_traces = alignments.apply(Shared.log, Shared.net, Shared.im, Shared.fm, variant=alignments.Variants.VERSION_DIJKSTRA_LESS_MEMORY) bb = time.time() print(bb - aa)
def g(): aa = time.time() aligned_traces = alignments.apply(Shared.log, Shared.net, Shared.im, Shared.fm, variant=alignments.Variants.VERSION_DIJKSTRA_NO_HEURISTICS) bb = time.time() print(bb - aa)
def test_align(self): log = pm4py.read_xes("input_data/running-example.xes") net, im, fm = pm4py.discover_petri_net_inductive(log, noise_threshold=0.2) aligned_traces = alignments.apply(log, net, im, fm) diagn_df = alignments.get_diagnostics_dataframe(log, aligned_traces)
def get_attributes(log, decision_points, attributes, use_trace_attributes, trace_attributes, k, net, initial_marking, final_marking, decision_points_names, parameters=None): """ This method aims to construct for each decision place a table where for each decision place a list if given with the label of the later decision and as value the given attributes :param log: Log on which the method is applied :param alignments: Computed alignments for a log and a model :param decision_points: Places that have multiple outgoing arcs :param attributes: Attributes that are considered :param use_trace_attributes: If trace attributes have to be considered or not :param trace_attributes: List of trace attributes that are considered :param k: Taking k last activities into account :return: Dictionary that has as keys the decision places. The value for this key is a list. The content of these lists are tuples. The first element of these tuples is information regrading the attributes, the second element of these tuples is the transition which chosen in a decision. """ if parameters is None: parameters = {} I = {} for key in decision_points: I[key] = [] A = {} for attri in attributes: A[attri] = None i = 0 # first, take a look at the variants variants_idxs = variants_module.get_variants_from_log_trace_idx(log, parameters=parameters) one_variant = [] for variant in variants_idxs: one_variant.append(variant) # TODO: Token based replay code mit paramter für nur varianten einbeziehen ausstatten replay_result = token_replay.apply(log, net, initial_marking, final_marking, parameters=parameters) replay_result = simplify_token_replay(replay_result) count = 0 for variant in replay_result: if variant['trace_fitness'] == 1.0: for trace_index in variants_idxs[one_variant[count]]: last_k_list = [None] * k trace = log[trace_index] if use_trace_attributes: for attribute in trace_attributes: # can be done here since trace attributes does not change for whole trace A[attribute] = trace.attributes[attribute] j = 0 # j is a pointer which points to the current event inside a trace for transition in variant['activated_transitions']: for key, value in decision_points_names.items(): if transition.label in value: for element in last_k_list: if element != None: if transition.label != None: I[key].append((element.copy(), transition.label)) else: I[key].append((element.copy(), transition.name)) for attri in attributes: # print(variant, transition.label, j) if attri in trace[j]: # only add the attribute information if it is present in the event A[attri] = trace[j][attri] # add A to last_k_list. Using modulo to access correct entry last_k_list[j % k] = A.copy() if transition.label != None: if not j + 1 >= len(trace): # Problem otherwise: If there are tau-transition after the last event related transition, # the pointer j which points to the current event in a trace, gets out of range j += 1 else: example_trace = log[variants_idxs[one_variant[count]][0]] align_parameters = copy(parameters) align_parameters[star.Parameters.PARAM_ALIGNMENT_RESULT_IS_SYNC_PROD_AWARE] = True alignment = ali.apply(example_trace, net, initial_marking, final_marking, parameters=align_parameters)['alignment'] for trace_index in variants_idxs[one_variant[count]]: last_k_list = [None] * k trace = log[trace_index] if use_trace_attributes: for attribute in trace_attributes: # can be done here since trace attributes does not change for whole trace A[attribute] = trace.attributes[attribute] j = 0 for el in alignment: if el[1][1] != '>>': # If move in model for key, value in decision_points.items(): if el[0][1] in value: for element in last_k_list: if element != None: # only add those entries where information is provided if el[1][1] == None: # for some dt algorithms, the entry None might be a problem, since it is left out later I[key].append((element.copy(), el[0][1])) else: I[key].append((element.copy(), el[1][1])) if el[1][0] != '>>' and el[1][1] != '>>': # If there is a move in log and model for attri in attributes: if attri in trace[j]: # only add the attribute information if it is present in the event A[attri] = trace[j][attri] # add A to last_k_list. Using modulo to access correct entry last_k_list[j % k] = A.copy() if el[1][0] != '>>': # only go to next event in trace if the current event has been aligned # TODO: Discuss if this is correct or can lead to problems j += 1 count += 1 return I