def apply(net, im, fm, parameters=None): """ Transforms a WF-net to a process tree Parameters ------------- net Petri net im Initial marking fm Final marking Returns ------------- tree Process tree """ if parameters is None: parameters = {} debug = exec_utils.get_param_value(Parameters.DEBUG, parameters, False) fold = exec_utils.get_param_value(Parameters.FOLD, parameters, True) grouped_net = group_blocks_in_net(net, parameters=parameters) if len(grouped_net.transitions) == 1: pt_str = list(grouped_net.transitions)[0].label pt = pt_util.parse(pt_str) return pt_util.fold(pt) if fold else pt else: if debug: from pm4py.visualization.petrinet import visualizer as pn_viz pn_viz.view(pn_viz.apply(grouped_net, parameters={"format": "svg"})) raise ValueError('Parsing of WF-net Failed')
def apply_tree(event_log: Union[pd.DataFrame, EventLog, EventStream], parameters: Optional[Dict[str, Any]] = None) -> ProcessTree: if parameters is None: parameters = {} event_log = log_converter.apply(event_log, parameters=parameters) if type(event_log) is not EventLog: raise ValueError( 'input argument log should be of type pandas.DataFrame, Event Log or Event Stream' ) act_key = exec_utils.get_param_value(Parameters.ACTIVITY_KEY.value, parameters, xes_constants.DEFAULT_NAME_KEY) if exec_utils.get_param_value(Parameters.DFG_ONLY, parameters, False): event_log = None threshold = exec_utils.get_param_value(Parameters.NOISE_THRESHOLD, parameters, 0.0) if threshold == 0.0: # keep one trace per variant; more performant event_log = filtering_utils.keep_one_trace_per_variant( event_log, parameters=parameters) tree = inductive_miner( event_log, discover_dfg.apply( event_log, parameters={constants.PARAMETER_CONSTANT_ACTIVITY_KEY: act_key}), threshold, None, act_key, exec_utils.get_param_value(Parameters.USE_MSD_PARALLEL_CUT, parameters, True)) tree_consistency.fix_parent_pointers(tree) tree = util.fold(tree) util.tree_sort(tree) return tree
def reduce(bottomup_nodes: List[ProcessTree], fps: Dict[str, Any], activities: Set[str]) -> ProcessTree: """ Reduce a process tree replacing the skippable elements that have empty intersection with the trace. Parameters ----------------- bottomup_nodes List of nodes of the process tree (that are process trees by themselves) in a bottomup order fps Footprints of the process tree activities Set of activities in the trace Returns ------------------ tree Reduced process tree """ from pm4py.algo.discovery.footprints.outputs import Outputs i = 0 while i < len(bottomup_nodes) - 1: node = bottomup_nodes[i] parent = node.parent is_skippable = fps[id(node)][Outputs.SKIPPABLE.value] node_activities = fps[id(node)][Outputs.ACTIVITIES.value] if is_skippable and not node_activities.intersection(activities): pt = ProcessTree() pt.parent = parent parent.children[parent.children.index(node)] = pt i = i + 1 return fold(bottomup_nodes[-1])
def apply_tree(log, parameters): """ Apply the IM_FF algorithm to a log obtaining a process tree Parameters ---------- log Log parameters Parameters of the algorithm, including: Parameters.ACTIVITY_KEY -> attribute of the log to use as activity name (default concept:name) Returns ---------- process_tree Process tree """ if parameters is None: parameters = {} if pkgutil.find_loader("pandas"): import pandas as pd from pm4py.statistics.variants.pandas import get as variants_get if type(log) is pd.DataFrame: vars = variants_get.get_variants_count(log, parameters=parameters) return apply_tree_variants(vars, parameters=parameters) activity_key = exec_utils.get_param_value(Parameters.ACTIVITY_KEY, parameters, pmutil.xes_constants.DEFAULT_NAME_KEY) log = converter.apply(log, parameters=parameters) # keep only the activity attribute (since the others are not used) log = filtering_utils.keep_only_one_attribute_per_event(log, activity_key) noise_threshold = exec_utils.get_param_value(Parameters.NOISE_THRESHOLD, parameters, shared_constants.NOISE_THRESHOLD_IMF) dfg = [(k, v) for k, v in dfg_inst.apply(log, parameters=parameters).items() if v > 0] c = Counts() activities = attributes_get.get_attribute_values(log, activity_key) start_activities = list(start_activities_get.get_start_activities(log, parameters=parameters).keys()) end_activities = list(end_activities_get.get_end_activities(log, parameters=parameters).keys()) contains_empty_traces = False traces_length = [len(trace) for trace in log] if traces_length: contains_empty_traces = min([len(trace) for trace in log]) == 0 # set the threshold parameter based on f and the max value in the dfg: max_value = 0 for key, value in dfg: if value > max_value: max_value = value threshold = noise_threshold * max_value recursion_depth = 0 sub = subtree.make_tree(log, dfg, dfg, dfg, activities, c, recursion_depth, noise_threshold, threshold, start_activities, end_activities, start_activities, end_activities, parameters=parameters) process_tree = get_tree_repr_implain.get_repr(sub, 0, contains_empty_traces=contains_empty_traces) # Ensures consistency to the parent pointers in the process tree tree_consistency.fix_parent_pointers(process_tree) # Fixes a 1 child XOR that is added when single-activities flowers are found tree_consistency.fix_one_child_xor_flower(process_tree) # folds the process tree (to simplify it in case fallthroughs/filtering is applied) process_tree = util.fold(process_tree) return process_tree
def apply_tree_dfg(dfg, parameters=None, activities=None, contains_empty_traces=False, start_activities=None, end_activities=None): """ Apply the IMDF algorithm to a DFG graph obtaining a process tree Parameters ---------- dfg Directly-follows graph parameters Parameters of the algorithm, including: Parameters.ACTIVITY_KEY -> attribute of the log_skeleton to use as activity name (default concept:name) activities Activities of the process (default None) contains_empty_traces Boolean value that is True if the event log_skeleton from which the DFG has been extracted contains empty traces start_activities If provided, the start activities of the log_skeleton end_activities If provided, the end activities of the log_skeleton Returns ---------- tree Process tree """ if parameters is None: parameters = {} noise_threshold = exec_utils.get_param_value(Parameters.NOISE_THRESHOLD, parameters, 0.0) if type(dfg) is Counter or type(dfg) is dict: newdfg = [] for key in dfg: value = dfg[key] newdfg.append((key, value)) dfg = newdfg c = Counts() s = SubtreeDFGBased(dfg, dfg, dfg, activities, c, 0, noise_threshold=noise_threshold, initial_start_activities=start_activities, initial_end_activities=end_activities) tree_repr = get_tree_repr_dfg_based.get_repr( s, 0, contains_empty_traces=contains_empty_traces) # Ensures consistency to the parent pointers in the process tree tree_consistency.fix_parent_pointers(tree_repr) # Fixes a 1 child XOR that is added when single-activities flowers are found tree_consistency.fix_one_child_xor_flower(tree_repr) # folds the process tree (to simplify it in case fallthroughs/filtering is applied) tree_repr = util.fold(tree_repr) return tree_repr
from pm4py.visualization.process_tree import factory as pt_viz from pm4py.algo.simulation.tree_generator import factory as pt_gen from pm4py.objects.process_tree import util as pt_util from pm4py.objects.conversion.process_tree import factory as pt_conv from pm4py.visualization.petrinet import factory as pn_viz from pm4py.objects.petri import utils as pn_util import time if __name__ == "__main__": pt = pt_gen.apply() pt_viz.view(pt_viz.apply(pt, parameters={"format": "svg"})) time.sleep(1) pn, im, fm = pt_conv.apply(pt) pn_viz.view(pn_viz.apply(pn, parameters={'format': 'svg'})) time.sleep(1) pt = pt_util.fold(pt) pt_viz.view(pt_viz.apply(pt, parameters={"format": "svg"}))
def apply_tree(log, parameters=None): """ Apply the IM algorithm to a log obtaining a process tree Parameters ---------- log Log parameters Parameters of the algorithm, including: Parameters.ACTIVITY_KEY -> attribute of the log to use as activity name (default concept:name) Returns ---------- process_tree Process tree """ if parameters is None: parameters = {} if type(log) is pd.DataFrame: vars = variants_get.get_variants_count(log, parameters=parameters) return apply_tree_variants(vars, parameters=parameters) else: activity_key = exec_utils.get_param_value( Parameters.ACTIVITY_KEY, parameters, pmutil.xes_constants.DEFAULT_NAME_KEY) log = converter.apply(log, parameters=parameters) # since basic IM is influenced once per variant, it makes sense to keep one trace per variant log = filtering_utils.keep_one_trace_per_variant(log, parameters=parameters) # keep only the activity attribute (since the others are not used) log = filtering_utils.keep_only_one_attribute_per_event( log, activity_key) dfg = [(k, v) for k, v in dfg_inst.apply(log, parameters=parameters).items() if v > 0] c = Counts() activities = attributes_filter.get_attribute_values(log, activity_key) start_activities = list( start_activities_filter.get_start_activities( log, parameters=parameters).keys()) end_activities = list( end_activities_filter.get_end_activities( log, parameters=parameters).keys()) contains_empty_traces = False traces_length = [len(trace) for trace in log] if traces_length: contains_empty_traces = min([len(trace) for trace in log]) == 0 recursion_depth = 0 sub = subtree.make_tree(log, dfg, dfg, dfg, activities, c, recursion_depth, 0.0, start_activities, end_activities, start_activities, end_activities, parameters) process_tree = get_tree_repr_implain.get_repr( sub, 0, contains_empty_traces=contains_empty_traces) # Ensures consistency to the parent pointers in the process tree tree_consistency.fix_parent_pointers(process_tree) # Fixes a 1 child XOR that is added when single-activities flowers are found tree_consistency.fix_one_child_xor_flower(process_tree) # folds the process tree (to simplify it in case fallthroughs/filtering is applied) process_tree = util.fold(process_tree) return process_tree