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 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 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 apply_fpt_rule(net): """ Apply the Fusion of Parallel Transitions (FPT) rule Parameters -------------- net Reset Inhibitor net """ cont = True while cont: cont = False for V in power_set([transition for transition in net.transitions if transition.label == None], 2): condition = True for x, y in itertools.product(V, V): if x != y: if not ((pre_set(x) == pre_set(y)) and \ (post_set(x) == post_set(y)) and \ (pre_set(x, properties.RESET_ARC) == pre_set(y, properties.RESET_ARC)) and \ (pre_set(x, properties.INHIBITOR_ARC) == pre_set(y, properties.INHIBITOR_ARC))): condition = False break # V is a valid candidate if condition: # remove transitions except the first one for t in V[1:]: remove_transition(net, t) cont = True break return net
def remove_initial_hidden_if_possible(net: PetriNet, im: Marking): """ Remove initial hidden transition if possible Parameters ------------ net Petri net im Initial marking Returns ------------ net Petri net im Possibly different initial marking """ source = list(im.keys())[0] first_hidden = list(source.out_arcs)[0].target target_places_first_hidden = [x.target for x in first_hidden.out_arcs] if len(target_places_first_hidden) == 1: target_place_first_hidden = target_places_first_hidden[0] if len(target_place_first_hidden.in_arcs) == 1: new_im = Marking() new_im[target_place_first_hidden] = 1 remove_place(net, source) remove_transition(net, first_hidden) return net, new_im return net, im
def petri_reduction_treplay(net, parameters=None): """ Apply petri_reduction on the Petrinet removing hidden transitions that are unused according to token-based replay Parameters ----------- net Petri net parameters Parameters of the algorithm, including: aligned_traces -> Result of alignment according to token-based replay Returns ----------- net Reduced Petri net """ if parameters is None: parameters = {} aligned_traces = parameters["aligned_traces"] enabled_trans_in_at_least_one_trace = set() for trace in aligned_traces: for trans in trace["activated_transitions"]: enabled_trans_in_at_least_one_trace.add(trans) transitions = list(net.transitions) for trans in transitions: if trans.label is None: if trans not in enabled_trans_in_at_least_one_trace: net = remove_transition(net, trans) return net
def clean_duplicate_transitions(net): """ Clean duplicate transitions in a Petri net Parameters ------------ net Petri net Returns ------------ net Cleaned Petri net """ transitions = list(net.transitions) already_visited_combo = set() for i in range(0, len(transitions)): trans = transitions[i] if trans.label is None: in_arcs = trans.in_arcs out_arcs = trans.out_arcs to_delete = False for in_arc in in_arcs: in_place = in_arc.source for out_arc in out_arcs: out_place = out_arc.target combo = in_place.name + " " + out_place.name if combo in already_visited_combo: to_delete = True break already_visited_combo.add(combo) if to_delete: net = remove_transition(net, trans) return net
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 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 apply_elt_rule(net): """ Apply the Elimination of Self-Loop Transitions (ELT) rule Parameters -------------- net Reset Inhibitor net """ cont = True while cont: cont = False for p, t in itertools.product(net.places, [t for t in net.transitions if t.label == None]): if (len(list(t.in_arcs)) == 1 and list(t.in_arcs)[0].source == p) and \ (len(list(t.out_arcs)) == 1 and list(t.out_arcs)[0].target == p) and \ (len(list(p.in_arcs)) >= 2) and \ (len(pre_set(t, properties.RESET_ARC)) == 0 and len(pre_set(t, properties.INHIBITOR_ARC)) == 0): remove_transition(net, t) cont = True break return net
def remove_unconnected_transitions(net: PetriNet): """ Remove unconnected transitions if any Parameters ------------- net Petri net Returns ------------- net Petri net without unconnected transitions """ transitions = list(net.transitions) i = 0 while i < len(transitions): if len(transitions[i].in_arcs) == 0 and len( transitions[i].out_arcs) == 0: remove_transition(net, transitions[i]) i = i + 1 return net
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 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 remove_rendundant_invisible_transitions(net): """ Remove redundant transitions from Petri net Parameters ----------- net Petri net Returns ----------- net Cleaned net """ trans = [x for x in list(net.transitions) if not x.label] i = 0 while i < len(trans): if trans[i] in net.transitions: preset_i = set(x.source for x in trans[i].in_arcs) postset_i = set(x.target for x in trans[i].out_arcs) j = 0 while j < len(trans): if not j == i: preset_j = set(x.source for x in trans[j].in_arcs) postset_j = set(x.target for x in trans[j].out_arcs) if len(preset_j) == len( preset_i) and len(postset_j) < len(postset_i): if len(preset_j.intersection(preset_i)) == len( preset_j) and len( postset_j.intersection(postset_i)) == len( postset_j): remove_transition(net, trans[j]) del trans[j] continue j = j + 1 i = i + 1 return net
def transform_net(self, net0, initial_marking0, final_marking0, s_map, avg_time_starts): """ Transform the source Petri net removing the initial and final marking, and connecting to each "initial" place a hidden timed transition mimicking the case start Parameters ------------- net0 Initial Petri net provided to the object initial_marking0 Initial marking of the Petri net provided to the object final_marking0 Final marking of the Petri net provided to the object s_map Stochastic map of transitions (EXPONENTIAL distribution since we assume a Markovian process) avg_time_starts Average time interlapsed between case starts Returns ------------- net Petri net that will be simulated initial_marking Initial marking of the Petri net that will be simulated (empty) final_marking Final marking of the Petri net that will be simulated (empty) s_map Stochastic map of transitions enriched by new hidden case-generator transitions """ # copy the Petri net object (assure that we do not change the original Petri net) [net1, initial_marking1, final_marking1] = copy([net0, initial_marking0, final_marking0]) # on the copied Petri net, add a sucking transition for the final marking for index, place in enumerate(final_marking1): suck_transition = PetriNet.Transition("SUCK_TRANSITION" + str(index), None) net1.transitions.add(suck_transition) add_arc_from_to(place, suck_transition, net1) hidden_generator_distr = Exponential() hidden_generator_distr.scale = avg_time_starts s_map[suck_transition] = hidden_generator_distr # on the copied Petri net, remove both the place(s) in the initial marking and # the immediate transitions that are connected to it. target_places = [] for place in initial_marking1: out_arcs = list(place.out_arcs) for target_arc in out_arcs: target_trans = target_arc.target if len(target_trans.in_arcs) == 1: out_arcs_lev2 = list(target_trans.out_arcs) for arc in out_arcs_lev2: target_place = arc.target target_places.append(target_place) net1 = remove_transition(net1, target_trans) net1 = remove_place(net1, place) # add hidden case-generation transitions to the model. # all places that are left orphan by the previous operation are targeted. for index, place in enumerate(target_places): hidden_generator_trans = PetriNet.Transition("HIDDEN_GENERATOR_TRANS" + str(index), None) net1.transitions.add(hidden_generator_trans) add_arc_from_to(hidden_generator_trans, place, net1) hidden_generator_distr = Exponential() hidden_generator_distr.scale = avg_time_starts s_map[hidden_generator_trans] = hidden_generator_distr # the simulated Petri net is assumed to start from an empty initial and final marking initial_marking = Marking() final_marking = Marking() return net1, initial_marking, final_marking, s_map
def repair_sound_Model(s_net, rules_dict, support, confidence, lift, sound=1): """ Repairing a bordered Petri net generated from Process tree to include long-term dependencies in it and create a precise Petri net. Soundness parameter is a given requirement. Parameter: net (PetriNet): Generated Petri net of the log rules (dict) : Discovered rules with the association rule metrics values support (str): Threshold value for support confidence (str) : Threshold value for confidence lift (str): Threshold value for confidence sound (str) : Yes Return: net (PetriNet): Repaired Sound Petri net of the log rules (dict) : Added rules to the net with their association rule metrics values """ rules = {} rules_dict = dict(sorted(rules_dict.items(), key=lambda item: item[1][2])) print("rules_dict", rules_dict) for pair, value in rules_dict.items(): trans = None if value[2] < 1.001 or str(value[2]) < lift or str( value[0]) < support or str(value[1]) < confidence: tau_t = f"tau_{pair[0]}{pair[1]}" for t in s_net.transitions: s_place_valid = 0 t_place_valid = 0 if str(t) == str(tau_t): trans = t source_places = set([x.source for x in t.in_arcs]) for p in source_places: s_place = f"ps_{pair[0]}" if str(p) == s_place: if sound == 'on' and len(p.out_arcs) > 1: s_place_valid = 1 elif sound == None: s_place_valid = -1 if len(p.out_arcs) == 1: p_utils.remove_place(s_net, p) if sound == 'on' and len(p.out_arcs) == 1: rules[pair] = value target_places = set([x.target for x in t.out_arcs]) for p in target_places: t_place = f"pt_{pair[1]}" if str(p) == t_place: if sound == 'on' and len(p.in_arcs) > 1: t_place_valid = 1 elif sound == None: t_place_valid = -1 if len(p.in_arcs) == 1: p_utils.remove_place(s_net, p) if sound == 'on' and len(p.in_arcs) == 1: rules[pair] = value if s_place_valid == 1 and t_place_valid == 1: s_net = p_utils.remove_transition(s_net, trans) break elif s_place_valid == -1 and t_place_valid == -1: s_net = p_utils.remove_transition(s_net, trans) break else: rules[pair] = value return s_net, rules