def apply(tree, parameters=None): ''' Only supports loops with 2 children! :param tree: :return: ''' net = petrinet.PetriNet(name=str(tree)) if len(tree.children) == 0: pn_util.add_transition(net, label=tree.label) 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, petrinet.Marking({p_ini: 1}), petrinet.Marking({p_fin: 1}) return net, petrinet.Marking(), petrinet.Marking()
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, petrinet.Marking(), petrinet.Marking()
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, petrinet.Marking(), petrinet.Marking()
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, petrinet.Marking(), petrinet.Marking()
def check_easy_soundness_of_wfnet(net): """ Checks the easy soundness of a workflow net Parameters ------------- net Petri net Returns ------------- boolean Boolean value """ source = list(x for x in net.places if len(x.in_arcs) == 0)[0] sink = list(x for x in net.places if len(x.out_arcs) == 0)[0] ini = petrinet.Marking({source: 1}) fin = petrinet.Marking({sink: 1}) return check_easy_soundness_net_in_fin_marking(net, ini, fin)
def default_staterep_to_marking(staterep, place_map): place_groups = re.split(r'([a-zA-Z0-9]+_[0-9]+)', staterep) places = [] # print('Splitted groups: {}'.format(place_groups)) for grp in place_groups: if grp == '' or grp == '_': continue place_name, nb_tokens = grp.split('_') # print('Group: {}, place name: {}, no. of tokens: {}'.format(grp, place_name, nb_tokens)) place = place_map[place_name] places.extend([place for _ in range(int(nb_tokens))]) marking = petri.Marking(places) return marking
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, petrinet.Marking(), petrinet.Marking()
arcs = [ p0_a, p1_c, p2_inv0, p3_e, p4_f, p5_g, p6_inv1, p7_inv1, p8_inv1, p9_d, p10_h, p10_b, a_p1, c_p2, inv0_p3, inv0_p4, inv0_p5, e_p6, f_p7, g_p8, inv1_p9, d_p10, h_p1, b_p11 ] for arc in arcs: arc.source.out_arcs.add(arc) arc.target.in_arcs.add(arc) net.transitions.update(trans) net.places.update(places) net.arcs.update(arcs) init_marking = petri.Marking([p0]) final_marking = petri.Marking([p11]) out_fp = './net.dot' gviz = vis_factory.apply(net, init_marking, final_marking) gviz.save(out_fp) # out_fp = './test-net.pnml' # exporter.pnml.export_net(net, init_marking, out_fp, final_marking=final_marking) # build the reachability graph is_inv = lambda t: t.label is None rg, inv_states = build_reachability_graph(net, init_marking, is_inv) collapse_inv_trans(rg, inv_states)
def build_net1(): net = petri.PetriNet(name='net1') # transitions a = petri.PetriNet.Transition('a', label='a') b = petri.PetriNet.Transition('b', label='b') c = petri.PetriNet.Transition('c', label='c') d = petri.PetriNet.Transition('d', label='d') e = petri.PetriNet.Transition('e', label='e') f = petri.PetriNet.Transition('f', label='f') g = petri.PetriNet.Transition('g', label='g') trans = [a, b, c, d, e, f, g] # places p1 = petri.PetriNet.Place('p1') p2 = petri.PetriNet.Place('p2') p3 = petri.PetriNet.Place('p3') p4 = petri.PetriNet.Place('p4') p5 = petri.PetriNet.Place('p5') p6 = petri.PetriNet.Place('p6') p7 = petri.PetriNet.Place('p7') places = [p1, p2, p3, p4, p5, p6, p7] # arcs p1_a = petri.PetriNet.Arc(p1, a) p2_b = petri.PetriNet.Arc(p2, b) p2_c = petri.PetriNet.Arc(p2, c) p3_d = petri.PetriNet.Arc(p3, d) p4_e = petri.PetriNet.Arc(p4, e) p5_e = petri.PetriNet.Arc(p5, e) p6_f = petri.PetriNet.Arc(p6, f) p6_g = petri.PetriNet.Arc(p6, g) a_p2 = petri.PetriNet.Arc(a, p2) a_p3 = petri.PetriNet.Arc(a, p3) b_p4 = petri.PetriNet.Arc(b, p4) c_p4 = petri.PetriNet.Arc(c, p4) d_p5 = petri.PetriNet.Arc(d, p5) e_p6 = petri.PetriNet.Arc(e, p6) f_p2 = petri.PetriNet.Arc(f, p2) f_p3 = petri.PetriNet.Arc(f, p3) g_p7 = petri.PetriNet.Arc(g, p7) arcs = [ p1_a, p2_b, p2_c, p3_d, p4_e, p5_e, p6_f, p6_g, a_p2, a_p3, b_p4, c_p4, d_p5, e_p6, f_p2, f_p3, g_p7 ] for arc in arcs: arc.source.out_arcs.add(arc) arc.target.in_arcs.add(arc) net.transitions.update(trans) net.places.update(places) net.arcs.update(arcs) init_marking = petri.Marking([p1]) final_marking = petri.Marking([p7]) return net, init_marking, final_marking
def check_loops_generating_tokens(net0): """ Check if the Petri net contains loops generating tokens Parameters ------------ net0 Petri net Returns ------------ boolean Boolean value (True if the net has loops generating tokens) """ net = deepcopy(net0) petri_utils.decorate_transitions_prepostset(net) graph, inv_dictionary = petri_utils.create_networkx_directed_graph(net) dictionary = {y:x for x,y in inv_dictionary.items()} loops_trans = petri_utils.get_cycles_petri_net_transitions(net) for loop in loops_trans: m = petrinet.Marking() for index, trans in enumerate(loop): m = m + trans.add_marking visited_couples = set() while True: changed_something = False # if there are no places with positive marking replaying the loop, then we are fine neg_places = [p for p in m if m[p] < 0] pos_places = [p for p in m if m[p] > 0] for p1 in pos_places: # if there are no places with negative marking replaying the loop, then we are doomed for p2 in neg_places: if not ((p1, p2)) in visited_couples: visited_couples.add((p1, p2)) # otherwise, do a check if there is a path in the workflow net between the two places # this exploration is based on heuristics; indeed, since we can enter the cycle multiple times # it does not really matter if we reach suddenly the optimal path # # another option is to use the exploration provided in explore_path (that is based on alignments) spath = None try: spath = nx.algorithms.shortest_paths.generic.shortest_path(graph, dictionary[p1], dictionary[p2]) except: pass if spath is not None: trans = [inv_dictionary[x] for x in spath if type(inv_dictionary[x]) is petrinet.PetriNet.Transition] sec_m0 = petrinet.Marking() for t in trans: sec_m0 = sec_m0 + t.add_marking sec_m = petrinet.Marking() for place in m: if place in sec_m0: sec_m[place] = sec_m0[place] m1 = m + sec_m # the exploration is (in part) successful if m1[p1] == 0: m = m1 changed_something = True break if not changed_something: break if not changed_something: break # at this point, we have definitely created one token if sum(m[place] for place in m) > 0: return True return False