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 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 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_elp_rule(net, im=None): """ Apply the Elimination of Self-Loop Places (ELP) rule Parameters -------------- net Reset Inhibitor net """ if im is None: im = {} cont = True while cont: cont = False for p in [place for place in net.places]: if (set([arc.target for arc in p.out_arcs]).issubset(set([arc.source for arc in p.in_arcs]))) and \ (p in im and im[p] >= 1) and \ (post_set(p, properties.RESET_ARC).union(set([arc.target for arc in p.out_arcs])) == set( [arc.source for arc in p.in_arcs])) and \ (len(post_set(p, properties.INHIBITOR_ARC)) == 0): remove_place(net, p) cont = True break 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_fpp_rule(net, im=None): """ Apply the Fusion of Parallel Places (FPP) rule Parameters -------------- net Reset Inhibitor net """ if im is None: im = {} cont = True while cont: cont = False for Q in power_set(net.places, 2): condition = True for x, y in itertools.product(Q, Q): if x != y: if not ((pre_set(x) == pre_set(y)) and \ (post_set(x) == post_set(y)) and \ (post_set(x, properties.RESET_ARC) == post_set(y, properties.RESET_ARC)) and \ (post_set(x, properties.INHIBITOR_ARC) == post_set(y, properties.INHIBITOR_ARC))): condition = False break for x in Q: if x in im: for y in Q: if y in im and im[x] > im[y]: if not (len(post_set(x, properties.INHIBITOR_ARC)) == 0): condition = False break else: continue break # Q is a valid candidate if condition: # remove places except the first one for p in Q[1:]: remove_place(net, p) cont = True break 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 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 apply(tree, parameters=None): """ Apply from Process Tree to Petri net Parameters ----------- tree Process tree parameters Parameters of the algorithm Returns ----------- net Petri net initial_marking Initial marking final_marking Final marking """ if parameters is None: parameters = {} del parameters counts = Counts() net = PetriNet('imdf_net_' + str(time.time())) initial_marking = Marking() final_marking = Marking() source = get_new_place(counts) source.name = "source" sink = get_new_place(counts) sink.name = "sink" net.places.add(source) net.places.add(sink) initial_marking[source] = 1 final_marking[sink] = 1 initial_mandatory = check_tau_mandatory_at_initial_marking(tree) final_mandatory = check_tau_mandatory_at_final_marking(tree) if initial_mandatory: initial_place = get_new_place(counts) net.places.add(initial_place) tau_initial = get_new_hidden_trans(counts, type_trans="tau") net.transitions.add(tau_initial) add_arc_from_to(source, tau_initial, net) add_arc_from_to(tau_initial, initial_place, net) else: initial_place = source if final_mandatory: final_place = get_new_place(counts) net.places.add(final_place) tau_final = get_new_hidden_trans(counts, type_trans="tau") net.transitions.add(tau_final) add_arc_from_to(final_place, tau_final, net) add_arc_from_to(tau_final, sink, net) else: final_place = sink net, counts, last_added_place = recursively_add_tree( tree, tree, net, initial_place, final_place, counts, 0) reduction.apply_simple_reduction(net) places = list(net.places) for place in places: if len(place.out_arcs) == 0 and not place in final_marking: remove_place(net, place) if len(place.in_arcs) == 0 and not place in initial_marking: remove_place(net, place) return net, initial_marking, final_marking
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