def remove_initial_hidden_if_possible(net, im): """ 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
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 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 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 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 remove_final_hidden_if_possible(net, fm): """ 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 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 remove_unconnected_transitions(net): """ 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 reduce_petri_net(net): transes = set([x for x in net.transitions if x.label is None]) places = list(net.places) i = 0 while i < len(places): place = places[i] source_transes = set([x.source for x in place.in_arcs]) target_transes = set([x.target for x in place.out_arcs]) if len(source_transes) == 1 and len(target_transes) == 1: if source_transes.issubset(transes) and target_transes.issubset( transes): source_trans = list(source_transes)[0] target_trans = list(target_transes)[0] if len(target_trans.out_arcs) == 1: target_place = list(target_trans.out_arcs)[0].target add_arc_from_to(source_trans, target_place, net) remove_place(net, place) remove_transition(net, target_trans) places = list(net.places) continue # print(source_trans, target_trans, target_place) i = i + 1 return net
def reduce1(net): """ Reduction rule (1) to simplify the Petri net Parameters ------------ net Petri net Returns ------------ net Simplified Petri net """ something_changed = True while something_changed: something_changed = False transitions = list(net.transitions) for trans in transitions: source_places = [arc.source for arc in trans.in_arcs] target_places = [arc.target for arc in trans.out_arcs] target_transes = [ arc.target for place in target_places for arc in place.out_arcs ] if len(source_places) == 1 and len(target_places) == 1 and len( target_transes) == 1: source_place = source_places[0] target_place = target_places[0] target_trans = target_transes[0] #target_places2 = [arc.target for arc in target_trans.out_arcs] if len(target_place.in_arcs) == 1 and len( target_trans.in_arcs) == 1 and len( target_trans.out_arcs) == 1: if trans.label is None: net = remove_transition(net, trans) net = remove_place(net, target_place) add_arc_from_to(source_place, target_trans, net) something_changed = True continue 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 project(net0, im0, fm0, allowed_transitions): """ Project a Petri Net on a set of transitions provided by the user Parameters ------------- net0 Petri net im0 Initial marking fm0 Final marking allowed_transitions Sets of allowed transitions Returns ------------- net Projected net im Projected initial marking fm Projected final marking """ [net, im1, fm1] = deepcopy([net0, im0, fm0]) # keep only visible transitions that have a label in allowed_transitions trans_list = list(net.transitions) for trans in trans_list: if trans.label is not None and trans.name not in allowed_transitions: net = utils.remove_transition(net, trans) # create a fictious Petri net old_net = PetriNet("") # remove unconnected elements until a 'stable' platform is reached n_it = 0 while not (len(old_net.places) == len(net.places) and len(old_net.transitions) == len(net.transitions) and len( old_net.arcs) == len(net.arcs)): n_it = n_it + 1 old_net = deepcopy(net) trans_list = list(net.transitions) for trans in trans_list: # remove invisible transitions that have no input or output arcs if trans.label is None and ( len(trans.in_arcs) == 0 or len(trans.out_arcs) == 0) and trans.name not in allowed_transitions: net = utils.remove_transition(net, trans) continue places_list = list(net.places) for place in places_list: # remove places that have no input or output arcs if len(place.in_arcs) == 0 and (not place in im1 or len(place.out_arcs) == 0): net = utils.remove_place(net, place) continue # now the goal is to remove further places, but being carefully to not remove something structurally relevant for place in places_list: all_inputs = [arc.source for arc in place.in_arcs] hid_input = [trans for trans in all_inputs if trans.label is None and trans.name not in allowed_transitions] all_outputs = [arc.target for arc in place.out_arcs] hid_output = [trans for trans in all_outputs if trans.label is None and trans.name not in allowed_transitions] if len(hid_input) == len(all_inputs) and len(hid_output) == len(all_outputs): net = utils.remove_place(net, place) continue im = Marking() fm = Marking() for place in im1: if place in net.places: im[place] = im1[place] for place in fm1: if place in net.places: fm[place] = fm1[place] return net, im, fm