def apply(tree, parameters=None): ''' Only supports loops with 2 children! :param tree: :return: ''' net = obj.PetriNet(name=str(tree)) if len(tree.children) == 0: pn_util.add_transition(net, label=tree.label, name=str(id(tree))) else: sub_nets = list() for c in tree.children: sub_net, ini, fin = apply(c) sub_nets.append(sub_net) pn_util.merge(net, sub_nets) switch = { pt_opt.SEQUENCE: construct_sequence_pattern, pt_opt.XOR: construct_xor_pattern, pt_opt.PARALLEL: construct_and_pattern, pt_opt.LOOP: construct_loop_pattern } net, ini, fin = switch[tree.operator](net, sub_nets) if tree.parent is None: p_ini = pn_util.add_place(net) p_fin = pn_util.add_place(net) pn_util.add_arc_from_to(p_ini, _get_src_transition(net), net) pn_util.add_arc_from_to(_get_sink_transition(net), p_fin, net) return net, obj.Marking({p_ini: 1}), obj.Marking({p_fin: 1}) return net, obj.Marking(), obj.Marking()
def apply_fst_rule(net): """ Apply the Fusion of Series Transitions (FST) rule Parameters -------------- net Reset Inhibitor net """ cont = True while cont: cont = False for p, t, u in itertools.product(net.places, net.transitions, net.transitions): if (len(list(p.in_arcs)) == 1 and list(p.in_arcs)[0].source == t) and \ (len(list(p.out_arcs)) == 1 and list(p.out_arcs)[0].target == u) and \ (len(list(u.in_arcs)) == 1 and list(u.in_arcs)[0].source == p) and \ (len(post_set(t).intersection(post_set(u))) == 0) and \ (set().union(*[post_set(place, properties.INHIBITOR_ARC) for place in post_set(u)]) == post_set(p, properties.INHIBITOR_ARC)) and \ (set().union(*[post_set(place, properties.RESET_ARC) for place in post_set(u)]) == post_set(p, properties.RESET_ARC)) and \ (len(pre_set(u, properties.RESET_ARC)) == 0 and len(pre_set(u, properties.INHIBITOR_ARC)) == 0): if u.label == None: remove_place(net, p) for target in post_set(u): add_arc_from_to(t, target, net) remove_transition(net, u) cont = True break return net
def construct_xor_pattern(net, sub_nets): p_s = pn_util.add_place(net) p_o = pn_util.add_place(net) for n in sub_nets: pn_util.add_arc_from_to(p_s, _get_src_transition(n), net) pn_util.add_arc_from_to(_get_sink_transition(n), p_o, net) return _add_src_sink_transitions(net, p_s, p_o)
def reduce_single_exit_transitions(net): """ Reduces the number of the single exit transitions in the Petri net Parameters -------------- net Petri net """ cont = True while cont: cont = False single_exit_transitions = [t for t in net.transitions if t.label is None and len(t.out_arcs) == 1] for i in range(len(single_exit_transitions)): t = single_exit_transitions[i] target_place = list(t.out_arcs)[0].target source_places = [a.source for a in t.in_arcs] if len(target_place.in_arcs) == 1 and len(target_place.out_arcs) == 1: target_transition = list(target_place.out_arcs)[0].target remove_transition(net, t) remove_place(net, target_place) for p in source_places: add_arc_from_to(p, target_transition, net) cont = True break return net
def __copy_into(source_net, target_net, upper, skip): t_map = {} p_map = {} for t in source_net.transitions: name = (t.name, skip) if upper else (skip, t.name) label = (t.label, skip) if upper else (skip, t.label) t_map[t] = PetriNet.Transition(name, label) if properties.TRACE_NET_TRANS_INDEX in t.properties: # 16/02/2021: copy the index property from the transition of the trace net t_map[t].properties[ properties.TRACE_NET_TRANS_INDEX] = t.properties[ properties.TRACE_NET_TRANS_INDEX] target_net.transitions.add(t_map[t]) for p in source_net.places: name = (p.name, skip) if upper else (skip, p.name) p_map[p] = PetriNet.Place(name) if properties.TRACE_NET_PLACE_INDEX in p.properties: # 16/02/2021: copy the index property from the place of the trace net p_map[p].properties[ properties.TRACE_NET_PLACE_INDEX] = p.properties[ properties.TRACE_NET_PLACE_INDEX] target_net.places.add(p_map[p]) for t in source_net.transitions: for a in t.in_arcs: add_arc_from_to(p_map[a.source], t_map[t], target_net) for a in t.out_arcs: add_arc_from_to(t_map[t], p_map[a.target], target_net) return t_map, p_map
def add_sink(net, end_activities, label_transition_dict): """ Adding sink pe """ end = PetriNet.Place('end') net.places.add(end) for e in end_activities: add_arc_from_to(label_transition_dict[e], end, net) return end
def add_source(net, start_activities, label_transition_dict): """ Adding source pe """ source = PetriNet.Place('start') net.places.add(source) for s in start_activities: add_arc_from_to(source, label_transition_dict[s], net) return source
def construct_xor_pattern(net, sub_nets): p_s = pn_util.add_place(net) p_o = pn_util.add_place(net) for n in sub_nets: #settings.src_dict[tuple(n.transitions)] = _get_src_transition(n) #settings.sink_dict[tuple(n.transitions)] = _get_sink_transition(n) settings.src_dict[_get_src_transition(n)] = n.transitions settings.sink_dict[_get_sink_transition(n)] = n.transitions pn_util.add_arc_from_to(p_s, _get_src_transition(n), net) pn_util.add_arc_from_to(_get_sink_transition(n), p_o, net) return _add_src_sink_transitions(net, p_s, p_o)
def project_net_on_place(place): """ Project a Petri net on a place Parameters ------------- place Place Returns ------------- net (Place) net im Empty initial marking fm Empty final marking """ place_net = PetriNet() place_net_im = Marking() place_net_fm = Marking() input_trans = [arc.source for arc in place.in_arcs] output_trans = [arc.target for arc in place.out_arcs] if len(input_trans) == 0 or len(output_trans) == 0: raise Exception("place projection not available on source/sink places") input_trans_visible = [trans for trans in input_trans if trans.label] output_trans_visible = [trans for trans in output_trans if trans.label] if not len(input_trans) == len(input_trans_visible) or not len( output_trans) == len(output_trans_visible): raise Exception( "place projection not available on places that have invisible transitions as preset/postset" ) new_place = PetriNet.Place(place.name) place_net.places.add(new_place) for trans in input_trans: new_trans = PetriNet.Transition(trans.name, trans.label) place_net.transitions.add(new_trans) add_arc_from_to(new_trans, new_place, place_net) for trans in output_trans: new_trans = PetriNet.Transition(trans.name, trans.label) place_net.transitions.add(new_trans) add_arc_from_to(new_place, new_trans, place_net) return place_net, place_net_im, place_net_fm
def binary_concurrency_detection(net): c1 = None c2 = None for t1, t2 in itertools.product(net.transitions, net.transitions): if concurrent_requirement(t1, t2): c1 = t1 c2 = t2 break if c1 is not None and c2 is not None: t = generate_new_binary_transition(c1, c2, pt_operator.Operator.PARALLEL, net) net.transitions.add(t) # reduce for a in c1.in_arcs: pn_util.add_arc_from_to(a.source, t, net) for a in c1.out_arcs: pn_util.add_arc_from_to(t, a.target, net) for a in c2.in_arcs: pn_util.add_arc_from_to(a.source, t, net) for a in c2.out_arcs: pn_util.add_arc_from_to(t, a.target, net) pn_util.remove_transition(net, c1) pn_util.remove_transition(net, c2) return net return None
def postprocessing(net: PetriNet, initial_marking: Marking, final_marking: Marking, A, B, pairs, loop_one_list) -> Tuple[PetriNet, Marking, Marking]: """ Adding the filtered transitions to the Petri net Parameters ------------ loop_list List of looped activities classical_alpha_result Result after applying the classic alpha algorithm to the filtered log A See Paper for definition B See Paper for definition Returns ------------ net Petri net im Initial marking fm Final marking """ label_transition_dict = {} for label in loop_one_list: label_transition_dict[label] = PetriNet.Transition(label, label) net.transitions.add(label_transition_dict[label]) # F L1L # Key is specific loop element for key, value in A.items(): if key in B: A_without_B = value - B[key] B_without_A = B[key] - value pair = (A_without_B, B_without_A) for pair_try in pairs: in_part = pair_try[0] out_part = pair_try[1] if pair[0].issubset(in_part) and pair[1].issubset(out_part): pair_try_place = PetriNet.Place(str(pair_try)) net.places.add(pair_try_place) add_arc_from_to(label_transition_dict[key], pair_try_place, net) add_arc_from_to(pair_try_place, label_transition_dict[key], net) return net, initial_marking, final_marking
def short_circuit_petri_net(net, print_diagnostics=False): """ Fist, sink and source place are identified. Then, a transition from source to sink is added to short-circuited the given petri net. If there is no unique source and sink place, an error gets returned :param net: Petri net that is going to be short circuited :return: """ s_c_net = copy.deepcopy(net) no_source_places = 0 no_sink_places = 0 sink = None source = None for place in s_c_net.places: if len(place.in_arcs) == 0: source = place no_source_places += 1 if len(place.out_arcs) == 0: sink = place no_sink_places += 1 if (sink is not None) and ( source is not None) and no_source_places == 1 and no_sink_places == 1: # If there is one unique source and sink place, short circuit Petri Net is constructed t_1 = PetriNet.Transition("short_circuited_transition", "short_circuited_transition") s_c_net.transitions.add(t_1) # add arcs in short-circuited net petri_utils.add_arc_from_to(sink, t_1, s_c_net) petri_utils.add_arc_from_to(t_1, source, s_c_net) return s_c_net else: if sink is None: if print_diagnostics: print("There is no sink place.") return None elif source is None: if print_diagnostics: print("There is no source place.") return None elif no_source_places > 1: if print_diagnostics: print("There is more than one source place.") return None elif no_sink_places > 1: if print_diagnostics: print("There is more than one sink place.") return None
def construct(pn1, im1, fm1, pn2, im2, fm2, skip): """ Constructs the synchronous product net of two given Petri nets. :param pn1: Petri net 1 :param im1: Initial marking of Petri net 1 :param fm1: Final marking of Petri net 1 :param pn2: Petri net 2 :param im2: Initial marking of Petri net 2 :param fm2: Final marking of Petri net 2 :param skip: Symbol to be used as skip Returns ------- :return: Synchronous product net and associated marking labels are of the form (a,>>) """ sync_net = PetriNet('synchronous_product_net of %s and %s' % (pn1.name, pn2.name)) t1_map, p1_map = __copy_into(pn1, sync_net, True, skip) t2_map, p2_map = __copy_into(pn2, sync_net, False, skip) for t1 in pn1.transitions: for t2 in pn2.transitions: if t1.label == t2.label: sync = PetriNet.Transition((t1.name, t2.name), (t1.label, t2.label)) sync_net.transitions.add(sync) # copy the properties of the transitions inside the transition of the sync net for p1 in t1.properties: sync.properties[p1] = t1.properties[p1] for p2 in t2.properties: sync.properties[p2] = t2.properties[p2] for a in t1.in_arcs: add_arc_from_to(p1_map[a.source], sync, sync_net) for a in t2.in_arcs: add_arc_from_to(p2_map[a.source], sync, sync_net) for a in t1.out_arcs: add_arc_from_to(sync, p1_map[a.target], sync_net) for a in t2.out_arcs: add_arc_from_to(sync, p2_map[a.target], sync_net) sync_im = Marking() sync_fm = Marking() for p in im1: sync_im[p1_map[p]] = im1[p] for p in im2: sync_im[p2_map[p]] = im2[p] for p in fm1: sync_fm[p1_map[p]] = fm1[p] for p in fm2: sync_fm[p2_map[p]] = fm2[p] # update 06/02/2021: to distinguish the sync nets that are output of this method, put a property in the sync net sync_net.properties[properties.IS_SYNC_NET] = True return sync_net, sync_im, sync_fm
def construct_loop_pattern(net, sub_nets): assert (len(sub_nets) == 2) p_s = pn_util.add_place(net) p_t = pn_util.add_place(net) pn_util.add_arc_from_to(p_s, _get_src_transition(sub_nets[0]), net) pn_util.add_arc_from_to(p_t, _get_src_transition(sub_nets[1]), net) pn_util.add_arc_from_to(_get_sink_transition(sub_nets[0]), p_t, net) pn_util.add_arc_from_to(_get_sink_transition(sub_nets[1]), p_s, net) net, ini, fin = _add_src_sink_transitions(net, p_s, p_t) return net, obj.Marking(), obj.Marking()
def remove_final_hidden_if_possible(net: PetriNet, fm: Marking): """ Remove final hidden transition if possible Parameters ------------- net Petri net fm Final marking Returns ------------- net Petri net """ sink = list(fm.keys())[0] last_hidden = list(sink.in_arcs)[0].source source_places_last_hidden = [x.source for x in last_hidden.in_arcs] removal_possible = len(source_places_last_hidden) == 1 for place in source_places_last_hidden: if len(place.out_arcs) > 1: removal_possible = False break else: source_trans = set([x.source for x in place.in_arcs]) for trans in source_trans: if len(trans.out_arcs) > 1: removal_possible = False break if removal_possible: all_sources = set() remove_transition(net, last_hidden) i = 0 while i < len(source_places_last_hidden): place = source_places_last_hidden[i] source_trans = set([x.source for x in place.in_arcs]) for trans in source_trans: if trans not in all_sources: all_sources.add(trans) add_arc_from_to(trans, sink, net) remove_place(net, place) i = i + 1 return net
def construct_sequence_pattern(net, sub_nets): places = [None] * (len(sub_nets) + 1) for i in range(len(sub_nets) + 1): places[i] = pn_util.add_place(net) for i in range(len(sub_nets)): pn_util.add_arc_from_to(places[i], _get_src_transition(sub_nets[i]), net) pn_util.add_arc_from_to(_get_sink_transition(sub_nets[i]), places[i + 1], net) src = pn_util.add_transition(net) pn_util.add_arc_from_to(src, places[0], net) sink = pn_util.add_transition(net) pn_util.add_arc_from_to(places[len(places) - 1], sink, net) return net, obj.Marking(), obj.Marking()
def apply_a_rule(net): """ Apply the Abstraction (A) rule Parameters -------------- net Reset Inhibitor net """ cont = True while cont: cont = False for Q, U in itertools.product(power_set(net.places, 1), power_set(net.transitions, 1)): for s, t in itertools.product([s for s in net.places if s not in Q], [t for t in net.transitions if (t not in U) and (t.label == None)]): if ((pre_set(t) == {s}) and \ (post_set(s) == {t}) and \ (pre_set(s) == set(U)) and \ (post_set(t) == set(Q)) and \ (len(set(itertools.product(pre_set(s), post_set(t))).intersection( set([(arc.source, arc.target) for arc in net.arcs if get_arc_type(arc) is None])))) == 0) and \ (len(pre_set(t, properties.RESET_ARC)) == 0) and \ (len(pre_set(t, properties.INHIBITOR_ARC)) == 0): # check conditions on Q condition = True for q in Q: if not ((post_set(s, properties.RESET_ARC) == post_set(q, properties.RESET_ARC)) and \ (post_set(s, properties.INHIBITOR_ARC) == post_set(q, properties.INHIBITOR_ARC))): condition = False break # Q is a valid candidate if condition: for u in U: for q in Q: add_arc_from_to(u, q, net) remove_place(net, s) remove_transition(net, t) cont = True break return net
def _short_circuit_petri_net(net): """ Creates a short circuited Petri net, whether an unique source place and sink place are there, by connecting the sink with the source Parameters --------------- net Petri net Returns --------------- boolean Boolean value """ s_c_net = copy.deepcopy(net) no_source_places = 0 no_sink_places = 0 sink = None source = None for place in s_c_net.places: if len(place.in_arcs) == 0: source = place no_source_places += 1 if len(place.out_arcs) == 0: sink = place no_sink_places += 1 if (sink is not None) and ( source is not None) and no_source_places == 1 and no_sink_places == 1: # If there is one unique source and sink place, short circuit Petri Net is constructed t_1 = PetriNet.Transition("short_circuited_transition", "short_circuited_transition") s_c_net.transitions.add(t_1) # add arcs in short-circuited net pn_utils.add_arc_from_to(sink, t_1, s_c_net) pn_utils.add_arc_from_to(t_1, source, s_c_net) return s_c_net else: return None
def __deepcopy__(self, memodict={}): from pm4py.objects.petri_net.utils.petri_utils import add_arc_from_to this_copy = PetriNet(self.name) memodict[id(self)] = this_copy for place in self.places: place_copy = PetriNet.Place(place.name, properties=place.properties) this_copy.places.add(place_copy) memodict[id(place)] = place_copy for trans in self.transitions: trans_copy = PetriNet.Transition(trans.name, trans.label, properties=trans.properties) this_copy.transitions.add(trans_copy) memodict[id(trans)] = trans_copy for arc in self.arcs: add_arc_from_to(memodict[id(arc.source)], memodict[id(arc.target)], this_copy, weight=arc.weight) return this_copy
def binary_sequence_detection(net): c1 = None c2 = None for t1, t2 in itertools.product(net.transitions, net.transitions): if sequence_requirement(t1, t2): c1 = t1 c2 = t2 break if c1 is not None and c2 is not None: t = generate_new_binary_transition(c1, c2, pt_operator.Operator.SEQUENCE, net) net.transitions.add(t) for a in c1.in_arcs: pn_util.add_arc_from_to(a.source, t, net) for a in c2.out_arcs: pn_util.add_arc_from_to(t, a.target, net) for p in pn_util.post_set(c1): pn_util.remove_place(net, p) pn_util.remove_transition(net, c1) pn_util.remove_transition(net, c2) return net return None
def construct_and_pattern(net, sub_nets): p_s = [None] * len(sub_nets) p_t = [None] * len(sub_nets) for i in range(len(sub_nets)): p_s[i] = pn_util.add_place(net) p_t[i] = pn_util.add_place(net) pn_util.add_arc_from_to(p_s[i], _get_src_transition(sub_nets[i]), net) pn_util.add_arc_from_to(_get_sink_transition(sub_nets[i]), p_t[i], net) src = pn_util.add_transition(net) for p in p_s: pn_util.add_arc_from_to(src, p, net) sink = pn_util.add_transition(net) for p in p_t: pn_util.add_arc_from_to(p, sink, net) return net, obj.Marking(), obj.Marking()
def apply_fsp_rule(net, im=None, fm=None): """ Apply the Fusion of Series Places (FSP) rule Parameters -------------- net Reset Inhibitor net """ if im is None: im = {} if fm is None: fm = {} cont = True while cont: cont = False for p, q, t in itertools.product(net.places, net.places, net.transitions): if t.label == None: # only silent transitions may be removed either way if (len(t.in_arcs) == 1 and list(t.in_arcs)[0].source == p) and \ (len(t.out_arcs) == 1 and list(t.out_arcs)[0].target == q) and \ (len(post_set(p)) == 1 and list(post_set(p))[0] == t) and \ (len(pre_set(p).intersection(pre_set(q))) == 0) and \ (post_set(p, properties.RESET_ARC) == post_set(q, properties.RESET_ARC)) and \ (post_set(p, properties.INHIBITOR_ARC) == post_set(q, properties.INHIBITOR_ARC)) and \ (len(pre_set(t, properties.RESET_ARC)) == 0 and len( pre_set(t, properties.INHIBITOR_ARC)) == 0): # remove place p and transition t remove_transition(net, t) for source in pre_set(p): add_arc_from_to(source, q, net) remove_place(net, p) if p in im: del im[p] im[q] = 1 cont = True break return net, im, fm
def apply(dfg, parameters=None): """ Applies the DFG mining on a given object (if it is a Pandas dataframe or a log, the DFG is calculated) Parameters ------------- dfg Object (DFG) (if it is a Pandas dataframe or a log, the DFG is calculated) parameters Parameters """ if parameters is None: parameters = {} dfg = dfg start_activities = exec_utils.get_param_value( Parameters.START_ACTIVITIES, parameters, dfg_utils.infer_start_activities(dfg)) end_activities = exec_utils.get_param_value( Parameters.END_ACTIVITIES, parameters, dfg_utils.infer_end_activities(dfg)) activities = dfg_utils.get_activities_from_dfg(dfg) net = PetriNet("") im = Marking() fm = Marking() source = PetriNet.Place("source") net.places.add(source) im[source] = 1 sink = PetriNet.Place("sink") net.places.add(sink) fm[sink] = 1 places_corr = {} index = 0 for act in activities: places_corr[act] = PetriNet.Place(act) net.places.add(places_corr[act]) for act in start_activities: if act in places_corr: index = index + 1 trans = PetriNet.Transition(act + "_" + str(index), act) net.transitions.add(trans) pn_util.add_arc_from_to(source, trans, net) pn_util.add_arc_from_to(trans, places_corr[act], net) for act in end_activities: if act in places_corr: index = index + 1 inv_trans = PetriNet.Transition(act + "_" + str(index), None) net.transitions.add(inv_trans) pn_util.add_arc_from_to(places_corr[act], inv_trans, net) pn_util.add_arc_from_to(inv_trans, sink, net) for el in dfg.keys(): act1 = el[0] act2 = el[1] index = index + 1 trans = PetriNet.Transition(act2 + "_" + str(index), act2) net.transitions.add(trans) pn_util.add_arc_from_to(places_corr[act1], trans, net) pn_util.add_arc_from_to(trans, places_corr[act2], net) return net, im, fm
def decompose(net, im, fm): places = {x.name: x for x in net.places} inv_trans = {x.name: x for x in net.transitions if x.label is None} tmap = {} for t in net.transitions: if t.label is not None: if t.label not in tmap: tmap[t.label] = [] tmap[t.label].append(t) trans_dup_label = { x.label: x for x in net.transitions if x.label is not None and len(tmap[x.label]) > 1 } trans_labels = {x.name: x.label for x in net.transitions} conn_comp = get_graph_components(places, inv_trans, trans_dup_label, tmap) list_nets = [] for cmp in conn_comp: net_new = PetriNet("") im_new = Marking() fm_new = Marking() lmap = {} for el in cmp: if el in places: lmap[el] = PetriNet.Place(el) net_new.places.add(lmap[el]) elif el in inv_trans: lmap[el] = PetriNet.Transition(el, None) net_new.transitions.add(lmap[el]) elif el in trans_labels: lmap[el] = PetriNet.Transition(el, trans_labels[el]) net_new.transitions.add(lmap[el]) for el in cmp: if el in places: old_place = places[el] for arc in old_place.in_arcs: st = arc.source if st.name not in lmap: lmap[st.name] = PetriNet.Transition( st.name, trans_labels[st.name]) net_new.transitions.add(lmap[st.name]) add_arc_from_to(lmap[st.name], lmap[el], net_new) for arc in old_place.out_arcs: st = arc.target if st.name not in lmap: lmap[st.name] = PetriNet.Transition( st.name, trans_labels[st.name]) net_new.transitions.add(lmap[st.name]) add_arc_from_to(lmap[el], lmap[st.name], net_new) if old_place in im: im_new[lmap[el]] = im[old_place] if old_place in fm: fm_new[lmap[el]] = fm[old_place] lvis_labels = sorted( [t.label for t in net_new.transitions if t.label is not None]) t_tuple = tuple( sorted( list( int( hashlib.md5(t.name.encode( constants.DEFAULT_ENCODING)).hexdigest(), 16) for t in net_new.transitions))) net_new.lvis_labels = lvis_labels net_new.t_tuple = t_tuple if len(net_new.places) > 0 or len(net_new.transitions) > 0: list_nets.append((net_new, im_new, fm_new)) return list_nets
def merge_comp(comp1, comp2): net = PetriNet("") im = Marking() fm = Marking() places = {} trans = {} for pl in comp1[0].places: places[pl.name] = PetriNet.Place(pl.name) net.places.add(places[pl.name]) if pl in comp1[1]: im[places[pl.name]] = comp1[1][pl] if pl in comp1[2]: fm[places[pl.name]] = comp1[2][pl] for pl in comp2[0].places: places[pl.name] = PetriNet.Place(pl.name) net.places.add(places[pl.name]) if pl in comp2[1]: im[places[pl.name]] = comp2[1][pl] if pl in comp2[2]: fm[places[pl.name]] = comp2[2][pl] for tr in comp1[0].transitions: trans[tr.name] = PetriNet.Transition(tr.name, tr.label) net.transitions.add(trans[tr.name]) for tr in comp2[0].transitions: if not tr.name in trans: trans[tr.name] = PetriNet.Transition(tr.name, tr.label) net.transitions.add(trans[tr.name]) for arc in comp1[0].arcs: if type(arc.source) is PetriNet.Place: add_arc_from_to(places[arc.source.name], trans[arc.target.name], net) else: add_arc_from_to(trans[arc.source.name], places[arc.target.name], net) for arc in comp2[0].arcs: if type(arc.source) is PetriNet.Place: add_arc_from_to(places[arc.source.name], trans[arc.target.name], net) else: add_arc_from_to(trans[arc.source.name], places[arc.target.name], net) lvis_labels = sorted( [t.label for t in net.transitions if t.label is not None]) t_tuple = tuple( sorted( list( int( hashlib.md5(t.name.encode( constants.DEFAULT_ENCODING)).hexdigest(), 16) for t in net.transitions))) net.lvis_labels = lvis_labels net.t_tuple = t_tuple return (net, im, fm)
def apply_dfg_sa_ea( dfg: Dict[str, int], start_activities: Union[None, Dict[str, int]], end_activities: Union[None, Dict[str, int]], parameters: Optional[Dict[Union[str, Parameters], Any]] = None ) -> Tuple[PetriNet, Marking, Marking]: """ Applying Alpha Miner starting from the knowledge of the Directly Follows graph, and of the start activities and end activities in the log (possibly inferred from the DFG) Parameters ------------ dfg Directly-Follows graph start_activities Start activities end_activities End activities parameters Parameters of the algorithm including: activity key -> name of the attribute that contains the activity 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! """ if parameters is None: parameters = {} activity_key = exec_utils.get_param_value( Parameters.ACTIVITY_KEY, parameters, pm_util.xes_constants.DEFAULT_NAME_KEY) if start_activities is None: start_activities = dfg_utils.infer_start_activities(dfg) if end_activities is None: end_activities = dfg_utils.infer_end_activities(dfg) 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, activity_key=activity_key) pairs = list( map( lambda p: ({p[0]}, {p[1]}), filter( lambda p: __initial_filter(alpha_abstraction.parallel_relation, p), alpha_abstraction.causal_relation))) 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 (__check_is_unrelated( alpha_abstraction.parallel_relation, alpha_abstraction.causal_relation, t1[0], t2[0]) or __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: __pair_maximizer(pairs, p), pairs) net = PetriNet('alpha_classic_net_' + str(time.time())) label_transition_dict = {} for i in range(0, len(labels)): label_transition_dict[labels[i]] = PetriNet.Transition( labels[i], labels[i]) net.transitions.add(label_transition_dict[labels[i]]) src = __add_source(net, alpha_abstraction.start_activities, label_transition_dict) sink = __add_sink(net, alpha_abstraction.end_activities, label_transition_dict) for pair in internal_places: place = PetriNet.Place(str(pair)) net.places.add(place) for in_arc in pair[0]: add_arc_from_to(label_transition_dict[in_arc], place, net) for out_arc in pair[1]: add_arc_from_to(place, label_transition_dict[out_arc], net) return net, Marking({src: 1}), Marking({sink: 1})
def _add_src_sink_transitions(net, p_s, p_t): src = pn_util.add_transition(net) pn_util.add_arc_from_to(src, p_s, net) sink = pn_util.add_transition(net) pn_util.add_arc_from_to(p_t, sink, net) return net, obj.Marking(), obj.Marking()
def processing(log: EventLog, causal: Tuple[str, str], follows: Tuple[str, str]): """ Applying the Alpha Miner with the new relations Parameters ------------- log Filtered log causal Pairs that have a causal relation (->) follows Pairs that have a follow relation (>) Returns ------------- net Petri net im Initial marking fm Final marking """ # create list of all events labels = set() start_activities = set() end_activities = set() for trace in log: start_activities.add(trace.__getitem__(0)) end_activities.add(trace.__getitem__(len(trace) - 1)) for events in trace: labels.add(events) labels = list(labels) pairs = [] for key, element in causal.items(): for item in element: if get_sharp_relation(follows, key, key): if get_sharp_relation(follows, item, item): pairs.append(({key}, {item})) # combining pairs 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 get_sharp_relations_for_sets( follows, t1[0], t2[0]) and get_sharp_relations_for_sets( follows, 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])) # maximize pairs cleaned_pairs = list(filter(lambda p: __pair_maximizer(pairs, p), pairs)) # create transitions net = PetriNet('alpha_plus_net_' + str(time.time())) label_transition_dict = {} for label in labels: if label != 'artificial_start' and label != 'artificial_end': label_transition_dict[label] = PetriNet.Transition(label, label) net.transitions.add(label_transition_dict[label]) else: label_transition_dict[label] = PetriNet.Transition(label, None) net.transitions.add(label_transition_dict[label]) # and source and sink src = add_source(net, start_activities, label_transition_dict) sink = add_sink(net, end_activities, label_transition_dict) # create places for pair in cleaned_pairs: place = PetriNet.Place(str(pair)) net.places.add(place) for in_arc in pair[0]: add_arc_from_to(label_transition_dict[in_arc], place, net) for out_arc in pair[1]: add_arc_from_to(place, label_transition_dict[out_arc], net) return net, Marking({src: 1}), Marking({sink: 1}), cleaned_pairs
def import_net_from_xml_object(root, parameters=None): """ Import a Petri net from an etree XML object Parameters ---------- root Root object of the XML parameters Other parameters of the algorithm """ if parameters is None: parameters = {} net = PetriNet('imported_' + str(time.time())) marking = Marking() fmarking = Marking() nett = None page = None finalmarkings = None stochastic_information = {} for child in root: nett = child places_dict = {} trans_dict = {} if nett is not None: for child in nett: if "page" in child.tag: page = child if "finalmarkings" in child.tag: finalmarkings = child if page is None: page = nett if page is not None: for child in page: if "place" in child.tag: position_X = None position_Y = None dimension_X = None dimension_Y = None place_id = child.get("id") place_name = place_id number = 0 for child2 in child: if child2.tag.endswith('name'): for child3 in child2: if child3.text: place_name = child3.text if child2.tag.endswith('initialMarking'): for child3 in child2: if child3.tag.endswith("text"): number = int(child3.text) if child2.tag.endswith('graphics'): for child3 in child2: if child3.tag.endswith('position'): position_X = float(child3.get("x")) position_Y = float(child3.get("y")) elif child3.tag.endswith("dimension"): dimension_X = float(child3.get("x")) dimension_Y = float(child3.get("y")) places_dict[place_id] = PetriNet.Place(place_id) places_dict[place_id].properties[constants.PLACE_NAME_TAG] = place_name net.places.add(places_dict[place_id]) if position_X is not None and position_Y is not None and dimension_X is not None and dimension_Y is not None: places_dict[place_id].properties[constants.LAYOUT_INFORMATION_PETRI] = ( (position_X, position_Y), (dimension_X, dimension_Y)) if number > 0: marking[places_dict[place_id]] = number del place_name if page is not None: for child in page: if child.tag.endswith("transition"): position_X = None position_Y = None dimension_X = None dimension_Y = None trans_id = child.get("id") trans_name = trans_id trans_visible = True random_variable = None for child2 in child: if child2.tag.endswith("name"): for child3 in child2: if child3.text: if trans_name == trans_id: trans_name = child3.text if child2.tag.endswith("graphics"): for child3 in child2: if child3.tag.endswith("position"): position_X = float(child3.get("x")) position_Y = float(child3.get("y")) elif child3.tag.endswith("dimension"): dimension_X = float(child3.get("x")) dimension_Y = float(child3.get("y")) if child2.tag.endswith("toolspecific"): tool = child2.get("tool") if "ProM" in tool: activity = child2.get("activity") if "invisible" in activity: trans_visible = False elif "StochasticPetriNet" in tool: distribution_type = None distribution_parameters = None priority = None weight = None for child3 in child2: key = child3.get("key") value = child3.text if key == "distributionType": distribution_type = value elif key == "distributionParameters": distribution_parameters = value elif key == "priority": priority = int(value) elif key == "weight": weight = float(value) random_variable = RandomVariable() random_variable.read_from_string(distribution_type, distribution_parameters) random_variable.set_priority(priority) random_variable.set_weight(weight) # 15/02/2021: the name associated in the PNML to invisible transitions was lost. # at least save that as property. if trans_visible: trans_label = trans_name else: trans_label = None trans_dict[trans_id] = PetriNet.Transition(trans_id, trans_label) trans_dict[trans_id].properties[constants.TRANS_NAME_TAG] = trans_name net.transitions.add(trans_dict[trans_id]) if random_variable is not None: trans_dict[trans_id].properties[constants.STOCHASTIC_DISTRIBUTION] = random_variable if position_X is not None and position_Y is not None and dimension_X is not None and dimension_Y is not None: trans_dict[trans_id].properties[constants.LAYOUT_INFORMATION_PETRI] = ( (position_X, position_Y), (dimension_X, dimension_Y)) if page is not None: for child in page: if child.tag.endswith("arc"): arc_source = child.get("source") arc_target = child.get("target") arc_weight = 1 for arc_child in child: if arc_child.tag.endswith("inscription"): for text_arcweight in arc_child: if text_arcweight.tag.endswith("text"): arc_weight = int(text_arcweight.text) if arc_source in places_dict and arc_target in trans_dict: add_arc_from_to(places_dict[arc_source], trans_dict[arc_target], net, weight=arc_weight) elif arc_target in places_dict and arc_source in trans_dict: add_arc_from_to(trans_dict[arc_source], places_dict[arc_target], net, weight=arc_weight) if finalmarkings is not None: for child in finalmarkings: for child2 in child: place_id = child2.get("idref") for child3 in child2: if child3.tag.endswith("text"): number = int(child3.text) if number > 0: fmarking[places_dict[place_id]] = number # generate the final marking in the case has not been found if len(fmarking) == 0: fmarking = final_marking.discover_final_marking(net) return net, marking, fmarking
def test_figure42(self): net = PetriNet("figure_4_2") p_1 = PetriNet.Place("p_1") p_2 = PetriNet.Place("p_2") p_3 = PetriNet.Place("p_3") p_4 = PetriNet.Place("p_4") p_5 = PetriNet.Place("p_5") p_6 = PetriNet.Place("p_6") p_7 = PetriNet.Place("p_7") p_8 = PetriNet.Place("p_8") net.places.add(p_1) net.places.add(p_2) net.places.add(p_3) net.places.add(p_4) net.places.add(p_5) net.places.add(p_6) net.places.add(p_7) net.places.add(p_8) t_1 = PetriNet.Transition("t_1", "t_1") t_2 = PetriNet.Transition("t_2", "t_2") t_3 = PetriNet.Transition("t_3", "t_3") t_4 = PetriNet.Transition("t_4", "t_4") t_5 = PetriNet.Transition("t_5", "t_5") t_6 = PetriNet.Transition("t_6", "t_6") t_7 = PetriNet.Transition("t_7", "t_7") t_8 = PetriNet.Transition("t_8", "t_8") net.transitions.add(t_1) net.transitions.add(t_2) net.transitions.add(t_3) net.transitions.add(t_4) net.transitions.add(t_5) net.transitions.add(t_6) net.transitions.add(t_7) net.transitions.add(t_8) petri_utils.add_arc_from_to(p_1, t_1, net) petri_utils.add_arc_from_to(t_1, p_6, net) petri_utils.add_arc_from_to(t_1, p_4, net) petri_utils.add_arc_from_to(p_4, t_4, net) petri_utils.add_arc_from_to(p_4, t_5, net) petri_utils.add_arc_from_to(t_2, p_6, net) petri_utils.add_arc_from_to(t_2, p_4, net) petri_utils.add_arc_from_to(t_4, p_3, net) petri_utils.add_arc_from_to(t_4, p_5, net) petri_utils.add_arc_from_to(t_5, p_7, net) petri_utils.add_arc_from_to(t_7, p_4, net) petri_utils.add_arc_from_to(p_3, t_2, net) petri_utils.add_arc_from_to(p_3, t_3, net) petri_utils.add_arc_from_to(p_5, t_2, net) petri_utils.add_arc_from_to(p_5, t_3, net) petri_utils.add_arc_from_to(p_5, t_4, net) petri_utils.add_arc_from_to(p_7, t_6, net) petri_utils.add_arc_from_to(p_8, t_7, net) petri_utils.add_arc_from_to(p_8, t_8, net) petri_utils.add_arc_from_to(t_3, p_2, net) petri_utils.add_arc_from_to(p_6, t_6, net) petri_utils.add_arc_from_to(t_6, p_5, net) petri_utils.add_arc_from_to(t_8, p_8, net) initial_marking = Marking() initial_marking[p_1] = 1 final_marking = Marking() final_marking[p_2] = 1 self.assertFalse(woflan.apply(net, initial_marking, final_marking, parameters={"print_diagnostics": False}))