def apply( log: EventLog, parameters: Optional[Dict[Union[str, Parameters], Any]] = None ) -> Tuple[PetriNet, Marking, Marking]: """ This method calls the \"classic\" alpha miner [1]_. Parameters ---------- log: :class:`pm4py.log.log.EventLog` Event log to use in the alpha miner parameters: Parameters of the algorithm, including: activity_key : :class:`str`, optional Key to use within events to identify the underlying activity. By deafult, the value 'concept:name' is used. Returns ------- net: :class:`pm4py.entities.petri.petrinet.PetriNet` A Petri net describing the event log that is provided as an input initial marking: :class:`pm4py.models.net.Marking` marking object representing the initial marking final marking: :class:`pm4py.models.net.Marking` marking object representing the final marking, not guaranteed that it is actually reachable! References ---------- .. [1] Wil M. P. van der Aalst et al., "Workflow Mining: Discovering Process Models from Event Logs", IEEE Trans. Knowl. Data Eng., 16, 1128-1142, 2004. `DOI <https://doi.org/10.1109/TKDE.2004.47>`_. """ if parameters is None: parameters = {} activity_key = exec_utils.get_param_value( Parameters.ACTIVITY_KEY, parameters, pm_util.xes_constants.DEFAULT_NAME_KEY) dfg = { k: v for k, v in dfg_inst.apply(log, parameters=parameters).items() if v > 0 } start_activities = endpoints.derive_start_activities_from_log( log, activity_key) end_activities = endpoints.derive_end_activities_from_log( log, activity_key) return apply_dfg_sa_ea(dfg, start_activities, end_activities, parameters=parameters)
def trans_alpha(log, parameters=None): dfg = {k: v for k, v in dfg_inst.apply(log).items() if v > 0} if parameters is None: parameters = {} if pm_util.constants.PARAMETER_CONSTANT_ACTIVITY_KEY not in parameters: parameters[pm_util.constants. PARAMETER_CONSTANT_ACTIVITY_KEY] = xes_util.DEFAULT_NAME_KEY start_activities = endpoints.derive_start_activities_from_log( log, parameters[pm_util.constants.PARAMETER_CONSTANT_ACTIVITY_KEY]) end_activities = endpoints.derive_end_activities_from_log( log, parameters[pm_util.constants.PARAMETER_CONSTANT_ACTIVITY_KEY]) labels = set() for el in dfg: labels.add(el[0]) labels.add(el[1]) for a in start_activities: labels.add(a) for a in end_activities: labels.add(a) labels = list(labels) alpha_abstraction = alpha_classic_abstraction.ClassicAlphaAbstraction( start_activities, end_activities, dfg) new_parallel_set = set() loop_set = set() for par in alpha_abstraction.parallel_relation: for trace in log: for i in range(len(trace) - 1): if trace[i]['concept:name'] == par[0] and trace[ i + 1]['concept:name'] == par[1]: if trace[i + 1]['concept:name'] in trace[i].enabled: new_parallel_set.add(par) pairs = list( map( lambda p: ({p[0]}, {p[1]}), filter( lambda p: classic.__initial_filter( alpha_abstraction.parallel_relation, p), alpha_abstraction.causal_relation))) for par in alpha_abstraction.parallel_relation: if par not in new_parallel_set and ( par[1], par[0]) not in new_parallel_set and par[1] != par[0]: loop_set.add(par) pairs.append(({par[0]}, {par[1]})) else: new_parallel_set.add(par) for i in range(0, len(pairs)): t1 = pairs[i] for j in range(i, len(pairs)): t2 = pairs[j] if t1 != t2: if t1[0].issubset(t2[0]) or t1[1].issubset(t2[1]): if not (classic.__check_is_unrelated( (new_parallel_set.union(loop_set)), alpha_abstraction.causal_relation, t1[0], t2[0]) or classic.__check_is_unrelated( (new_parallel_set.union(loop_set)), alpha_abstraction.causal_relation, t1[1], t2[1])): new_alpha_pair = (t1[0] | t2[0], t1[1] | t2[1]) if new_alpha_pair not in pairs: pairs.append((t1[0] | t2[0], t1[1] | t2[1])) internal_places = filter(lambda p: classic.__pair_maximizer(pairs, p), pairs) net = petri.petrinet.PetriNet('alpha_classic_net_' + str(time.time())) label_transition_dict = {} for i in range(0, len(labels)): label_transition_dict[labels[i]] = petri.petrinet.PetriNet.Transition( labels[i], labels[i]) net.transitions.add(label_transition_dict[labels[i]]) src = classic.__add_source(net, alpha_abstraction.start_activities, label_transition_dict) sink = classic.__add_sink(net, alpha_abstraction.end_activities, label_transition_dict) for pair in internal_places: place = petri.petrinet.PetriNet.Place(str(pair)) net.places.add(place) for in_arc in pair[0]: petri.utils.add_arc_from_to(label_transition_dict[in_arc], place, net) for out_arc in pair[1]: petri.utils.add_arc_from_to(place, label_transition_dict[out_arc], net) return net, Marking({src: 1}), Marking({sink: 1})
def trans_alpha(log, parameters=None): dfg = {k: v for k, v in dfg_inst.apply(log).items() if v > 0} if parameters is None: parameters = {} if pm_util.constants.PARAMETER_CONSTANT_ACTIVITY_KEY not in parameters: parameters[pm_util.constants. PARAMETER_CONSTANT_ACTIVITY_KEY] = xes_util.DEFAULT_NAME_KEY start_activities = endpoints.derive_start_activities_from_log( log, parameters[pm_util.constants.PARAMETER_CONSTANT_ACTIVITY_KEY]) end_activities = endpoints.derive_end_activities_from_log( log, parameters[pm_util.constants.PARAMETER_CONSTANT_ACTIVITY_KEY]) labels = set() for el in dfg: labels.add(el[0]) labels.add(el[1]) for a in start_activities: labels.add(a) for a in end_activities: labels.add(a) labels = list(labels) alpha_abstraction = alpha_classic_abstraction.ClassicAlphaAbstraction( start_activities, end_activities, dfg) pairs = list( map( lambda p: ({p[0]}, {p[1]}), filter( lambda p: classic.__initial_filter( alpha_abstraction.parallel_relation, p), alpha_abstraction.causal_relation))) #this part added parallel_set = alpha_abstraction.parallel_relation loop_cand_set = set() for rel in parallel_set.copy(): not_loop_flag = False pre_act = rel[0] post_act = rel[1] for trace in log: for i in range(len(trace) - 1): if trace[i]['concept:name'] == pre_act and trace[ i + 1]['concept:name'] == post_act: pre_en = trace[i]['enabled'] if post_act in pre_en: #not loop not_loop_flag = True break else: #loop continue break if not not_loop_flag: loop_cand_set.add((pre_act, post_act)) loop_set = set() for loop_cand in loop_cand_set: if loop_cand[::-1] in loop_cand_set and loop_cand[0] != loop_cand[1]: loop_set.add(loop_cand) #find loops based on enabling information #this part added for i in range(0, len(pairs)): t1 = pairs[i] for j in range(i, len(pairs)): t2 = pairs[j] if t1 != t2: if t1[0].issubset(t2[0]) or t1[1].issubset(t2[1]): if not (classic.__check_is_unrelated( alpha_abstraction.parallel_relation, alpha_abstraction.causal_relation, t1[0], t2[0]) or classic.__check_is_unrelated( alpha_abstraction.parallel_relation, alpha_abstraction.causal_relation, t1[1], t2[1])): new_alpha_pair = (t1[0] | t2[0], t1[1] | t2[1]) if new_alpha_pair not in pairs: pairs.append((t1[0] | t2[0], t1[1] | t2[1])) internal_places = filter(lambda p: classic.__pair_maximizer(pairs, p), pairs) net = petri.petrinet.PetriNet('alpha_classic_net_' + str(time.time())) label_transition_dict = {} for i in range(0, len(labels)): label_transition_dict[labels[i]] = petri.petrinet.PetriNet.Transition( labels[i], labels[i]) net.transitions.add(label_transition_dict[labels[i]]) for pair in internal_places: place = petri.petrinet.PetriNet.Place(str(pair)) net.places.add(place) for in_arc in pair[0]: petri.utils.add_arc_from_to(label_transition_dict[in_arc], place, net) for out_arc in pair[1]: petri.utils.add_arc_from_to(place, label_transition_dict[out_arc], net) src = classic.__add_source(net, alpha_abstraction.start_activities, label_transition_dict) sink = classic.__add_sink(net, alpha_abstraction.end_activities, label_transition_dict) loop_tail_set = set() for t in label_transition_dict.values(): #check if two-length-loop if len(t.in_arcs) == 0 and len(t.out_arcs) == 0: loop_tail_set.add(t) for loop_tail in loop_tail_set: if loop_set is not None: loop_body = None for loop in loop_set: if loop[0] == loop_tail.name: loop_body = label_transition_dict[loop[1]] if loop_body is not None: for place in net.places: for in_arc in place.in_arcs: if in_arc.source == loop_body: petri.utils.add_arc_from_to( place, label_transition_dict[loop_tail.name], net) break for out_arc in place.out_arcs: if out_arc.target == loop_body: petri.utils.add_arc_from_to( label_transition_dict[loop_tail.name], place, net) return net, Marking({src: 1}), Marking({sink: 1})