def construct_trace_net(trace, trace_name_key=xes_util.DEFAULT_NAME_KEY, activity_key=xes_util.DEFAULT_NAME_KEY): """ Creates a trace net, i.e. a trace in Petri net form. Parameters ---------- trace: :class:`list` input trace, assumed to be a list of events trace_name_key: :class:`str` key of the attribute that defines the name of the trace activity_key: :class:`str` key of the attribute of the events that defines the activity name Returns ------- tuple: :class:`tuple` of the net, initial marking and the final marking """ net = PetriNet('trace net of %s' % trace.attributes[trace_name_key] if trace_name_key in trace.attributes else ' ') place_map = {0: PetriNet.Place('p_0')} net.places.add(place_map[0]) for i in range(0, len(trace)): t = PetriNet.Transition('t_' + trace[i][activity_key] + '_' + str(i), trace[i][activity_key]) # 16/02/2021: set the trace index as property of the transition of the trace net t.properties[properties.TRACE_NET_TRANS_INDEX] = i net.transitions.add(t) place_map[i + 1] = PetriNet.Place('p_' + str(i + 1)) # 16/02/2021: set the place index as property of the place of the trace net place_map[i + 1].properties[properties.TRACE_NET_PLACE_INDEX] = i + 1 net.places.add(place_map[i + 1]) add_arc_from_to(place_map[i], t, net) add_arc_from_to(t, place_map[i + 1], net) return net, Marking({place_map[0]: 1}), Marking({place_map[len(trace)]: 1})
def execute_script(): net = PetriNet("") source = PetriNet.Place("source") sink = PetriNet.Place("sink") p1 = PetriNet.Place("p1") p2 = PetriNet.Place("p2") p_inhibitor = PetriNet.Place("p_inhibitor") p_reset = PetriNet.Place("p_reset") trans_A = PetriNet.Transition("A", "A") trans_B = PetriNet.Transition("B", "B") trans_C = PetriNet.Transition("C", "C") trans_inhibitor = PetriNet.Transition("inhibitor", None) trans_free = PetriNet.Transition("free", None) net.places.add(source) net.places.add(sink) net.places.add(p1) net.places.add(p2) net.places.add(p_inhibitor) net.places.add(p_reset) net.transitions.add(trans_A) net.transitions.add(trans_B) net.transitions.add(trans_C) net.transitions.add(trans_free) net.transitions.add(trans_inhibitor) add_arc_from_to(source, trans_A, net) add_arc_from_to(trans_A, p1, net) add_arc_from_to(p1, trans_B, net) add_arc_from_to(trans_B, p2, net) add_arc_from_to(p2, trans_C, net) add_arc_from_to(trans_C, sink, net) add_arc_from_to(trans_inhibitor, p_inhibitor, net) inhibitor_arc = add_arc_from_to(p_inhibitor, trans_B, net, type="inhibitor") add_arc_from_to(trans_free, p_reset, net) reset_arc = add_arc_from_to(p_reset, trans_C, net, type="reset") im = Marking({source: 1}) fm = Marking({sink: 1}) pm4py.view_petri_net(net, im, fm, format="svg") m = semantics.execute(trans_A, net, im) print(m) # B is enabled in m because no tokens in the "inhibitor" place print(semantics.enabled_transitions(net, m)) # if we put a token in the inhibitor place, B is not enabled anymore m2 = deepcopy(m) m2[p_inhibitor] = 1 print(semantics.enabled_transitions(net, m2)) # let's continue with m and fire B, and three times the "free" transition m = semantics.execute(trans_B, net, m) m = semantics.execute(trans_free, net, m) m = semantics.execute(trans_free, net, m) m = semantics.execute(trans_free, net, m) # we have three tokens in the 'reset' place. Firing C, all of them are removed because of the reset arc print(m) m = semantics.execute(trans_C, net, m) print(m) print(m == fm)
def test_figure415(self): net = PetriNet("figure_4_15") 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") 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) 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") 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) petri_utils.add_arc_from_to(p_1, t_1, net) petri_utils.add_arc_from_to(t_1, p_3, net) petri_utils.add_arc_from_to(t_1, p_2, net) petri_utils.add_arc_from_to(t_1, p_5, net) petri_utils.add_arc_from_to(p_5, t_2, net) petri_utils.add_arc_from_to(p_5, t_5, net) petri_utils.add_arc_from_to(p_3, t_2, net) petri_utils.add_arc_from_to(p_3, t_4, 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_5, p_5, net) petri_utils.add_arc_from_to(t_5, p_3, net) petri_utils.add_arc_from_to(p_2, t_2, net) petri_utils.add_arc_from_to(t_3, p_2, net) petri_utils.add_arc_from_to(t_3, p_3, net) petri_utils.add_arc_from_to(t_3, p_4, net) petri_utils.add_arc_from_to(p_6, t_5, net) petri_utils.add_arc_from_to(p_6, t_6, net) petri_utils.add_arc_from_to(p_6, t_3, net) petri_utils.add_arc_from_to(t_4, p_6, net) petri_utils.add_arc_from_to(t_4, p_5, net) petri_utils.add_arc_from_to(p_4, t_3, net) petri_utils.add_arc_from_to(p_4, t_6, net) petri_utils.add_arc_from_to(p_4, t_4, net) petri_utils.add_arc_from_to(t_6, p_7, net) initial_marking = Marking() initial_marking[p_1] = 1 final_marking = Marking() final_marking[p_7] = 1 self.assertTrue(woflan.apply(net, initial_marking, final_marking, parameters={"print_diagnostics": False}))
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 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 execute_script(): net = PetriNet("test") source = PetriNet.Place("source") sink = PetriNet.Place("sink") p1 = PetriNet.Place("p1") p2 = PetriNet.Place("p2") p3 = PetriNet.Place("p3") p4 = PetriNet.Place("p4") t1 = PetriNet.Transition("Confirmation of receipt", "Confirmation of receipt") t2 = PetriNet.Transition("T02 Check confirmation of receipt", "T02 Check confirmation of receipt") t3 = PetriNet.Transition("T04 Determine confirmation of receipt", "T04 Determine confirmation of receipt") t4 = PetriNet.Transition("T05 Print and send confirmation of receipt", "T05 Print and send confirmation of receipt") t5 = PetriNet.Transition("T06 Determine necessity of stop advice", "T06 Determine necessity of stop advice") net.places.add(source) net.places.add(sink) net.places.add(p1) net.places.add(p2) net.places.add(p3) net.places.add(p4) net.transitions.add(t1) net.transitions.add(t2) net.transitions.add(t3) net.transitions.add(t4) net.transitions.add(t5) petri_utils.add_arc_from_to(source, t1, net) petri_utils.add_arc_from_to(t1, p1, net) petri_utils.add_arc_from_to(p1, t2, net) petri_utils.add_arc_from_to(t2, p2, net) petri_utils.add_arc_from_to(p2, t3, net) petri_utils.add_arc_from_to(t3, p3, net) petri_utils.add_arc_from_to(p3, t4, net) petri_utils.add_arc_from_to(t4, p4, net) petri_utils.add_arc_from_to(p4, t5, net) petri_utils.add_arc_from_to(t5, sink, net) im = Marking() im[source] = 1 fm = Marking() fm[sink] = 1 pm4py.view_petri_net(net, im, fm, format="svg")
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 add_markings(curr, add): m = Marking() for p in curr.items(): m[p[0]] = p[1] for p in add.items(): m[p[0]] += p[1] if m[p[0]] == 0: del m[p[0]] return m
def get_strongly_connected_subnets(net): """ Get the strongly connected components subnets in the Petri net Parameters ------------- net Petri net Returns ------------- strongly_connected_transitions List of strongly connected transitions of the Petri net """ import networkx as nx graph, inv_dictionary = create_networkx_directed_graph(net) sccg = list(nx.strongly_connected_components(graph)) strongly_connected_subnets = [] for sg in list(sccg): if len(sg) > 1: subnet = PetriNet() imarking = Marking() fmarking = Marking() corr = {} for node in sg: if node in inv_dictionary: if type(inv_dictionary[node]) is PetriNet.Transition: prev_trans = inv_dictionary[node] new_trans = PetriNet.Transition( prev_trans.name, prev_trans.label) corr[node] = new_trans subnet.transitions.add(new_trans) if type(inv_dictionary[node]) is PetriNet.Place: prev_place = inv_dictionary[node] new_place = PetriNet.Place(prev_place.name) corr[node] = new_place subnet.places.add(new_place) for edge in graph.edges: if edge[0] in sg and edge[1] in sg: add_arc_from_to(corr[edge[0]], corr[edge[1]], subnet) strongly_connected_subnets.append([subnet, imarking, fmarking]) return strongly_connected_subnets
def decode_marking(self, ems): """ Decodes a marking from a generic dictionary to a Marking object """ em = eval(ems) mark = Marking() for p in em: mark[self.places_inv_dict[p]] = em[p] return mark
def __get_model_marking_and_index(marking): """ Transforms a marking on the synchronous product net to a marking in the model and an index in the trace """ mm = Marking() index = -1 for p in marking: if properties.TRACE_NET_PLACE_INDEX in p.properties: index = p.properties[properties.TRACE_NET_PLACE_INDEX] else: mm[p] = marking[p] return mm, index
def transform_markings_from_sync_to_original_net(markings0, net, parameters=None): """ Transform the markings of the sync net (in which alignment stops) into markings of the original net (in order to measure the precision) Parameters ------------- markings0 Markings on the sync net (expressed as place name with count) net Petri net parameters Parameters of the algorithm Returns ------------- markings Markings of the original model (expressed as place with count) """ if parameters is None: parameters = {} places_corr = {p.name: p for p in net.places} markings = [] for i in range(len(markings0)): res_list = markings0[i] # res_list shall be a list of markings. # If it is None, then there is no correspondence markings # in the original Petri net if res_list is not None: # saves all the markings reached by the optimal alignment # as markings of the original net markings.append([]) for j in range(len(res_list)): res = res_list[j] atm = Marking() for pl, count in res.items(): if pl[0] == utils.SKIP: atm[places_corr[pl[1]]] = count markings[-1].append(atm) else: markings.append(None) return markings
def decorate_transitions_prepostset(net: PetriNet): """ Decorate transitions with sub and addition markings Parameters ------------- net Petri net """ from pm4py.objects.petri_net.obj import Marking for trans in net.transitions: sub_marking = Marking() add_marking = Marking() for arc in trans.in_arcs: sub_marking[arc.source] = arc.weight add_marking[arc.source] = -arc.weight for arc in trans.out_arcs: if arc.target in add_marking: add_marking[arc.target] = arc.weight + add_marking[arc.target] else: add_marking[arc.target] = arc.weight trans.sub_marking = sub_marking trans.add_marking = add_marking
def __align_trace_stop_marking(trace, net, marking, final_marking, parameters=None): sync_net, sync_initial_marking, sync_final_marking = build_sync_net( trace, net, marking, final_marking, parameters=parameters) stop_marking = Marking() for pl, count in sync_final_marking.items(): if pl.name[1] == utils.SKIP: stop_marking[pl] = count cost_function = utils.construct_standard_cost_function( sync_net, utils.SKIP) # perform the alignment of the prefix res = precision_utils.__search(sync_net, sync_initial_marking, sync_final_marking, stop_marking, cost_function, utils.SKIP) return res
def discover_initial_marking(petri): """ Discovers initial marking from a Petri net Parameters ------------ petri Petri net Returns ------------ initial_marking Initial marking of the Petri net """ initial_marking = Marking() for place in petri.places: if len(place.in_arcs) == 0: initial_marking[place] = 1 return initial_marking
def discover_final_marking(petri): """ Discovers final marking from a Petri net Parameters ----------- petri Petri net Returns ----------- final_marking Final marking """ final_marking = Marking() for place in petri.places: if len(place.out_arcs) == 0: final_marking[place] = 1 return final_marking
def test_mcg(self): net = PetriNet("mcg") 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") 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) 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") 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) petri_utils.add_arc_from_to(p_1, t_1, net) petri_utils.add_arc_from_to(t_1, p_2, net) petri_utils.add_arc_from_to(p_2, t_3, net) petri_utils.add_arc_from_to(t_3, p_3, net, weight=2) petri_utils.add_arc_from_to(p_3, t_4, net) petri_utils.add_arc_from_to(t_4, p_2, net) petri_utils.add_arc_from_to(p_1, t_2, net) petri_utils.add_arc_from_to(t_2, p_4, net) petri_utils.add_arc_from_to(p_4, t_5, net) petri_utils.add_arc_from_to(t_5, p_5, net, weight=2) petri_utils.add_arc_from_to(p_5, t_6, net) petri_utils.add_arc_from_to(t_6, p_4, net) initial_marking = Marking() initial_marking[p_1] = 1 mcg = minimal_coverability_graph.apply(net, initial_marking)
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 align_fake_log_stop_marking(fake_log, net, marking, final_marking, parameters=None): """ Align the 'fake' log with all the prefixes in order to get the markings in which the alignment stops Parameters ------------- fake_log Fake log net Petri net marking Marking final_marking Final marking parameters Parameters of the algorithm Returns ------------- alignment For each trace in the log, return the marking in which the alignment stops (expressed as place name with count) """ if parameters is None: parameters = {} show_progress_bar = exec_utils.get_param_value(Parameters.SHOW_PROGRESS_BAR, parameters, True) align_result = [] progress = None if pkgutil.find_loader("tqdm") and show_progress_bar and len(fake_log) > 1: from tqdm.auto import tqdm progress = tqdm(total=len(fake_log), desc="computing precision with alignments, completed variants :: ") for i in range(len(fake_log)): trace = fake_log[i] sync_net, sync_initial_marking, sync_final_marking = build_sync_net(trace, net, marking, final_marking, parameters=parameters) stop_marking = Marking() for pl, count in sync_final_marking.items(): if pl.name[1] == utils.SKIP: stop_marking[pl] = count cost_function = utils.construct_standard_cost_function(sync_net, utils.SKIP) # perform the alignment of the prefix res = precision_utils.__search(sync_net, sync_initial_marking, sync_final_marking, stop_marking, cost_function, utils.SKIP) if res is not None: align_result.append([]) for mark in res: res2 = {} for pl in mark: # transforms the markings for easier correspondence at the end # (distributed engine friendly!) res2[(pl.name[0], pl.name[1])] = mark[pl] align_result[-1].append(res2) else: # if there is no path from the initial marking # replaying the given prefix, then add None align_result.append(None) if progress is not None: progress.update() # gracefully close progress bar if progress is not None: progress.close() del progress return align_result
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(log, net, initial_marking, final_marking, parameters=None): """ Method to apply token-based replay Parameters ----------- log Log net Petri net initial_marking Initial marking final_marking Final marking parameters Parameters of the algorithm """ if parameters is None: parameters = {} for t in net.transitions: ma = Marking() for a in t.out_arcs: p = a.target ma[p] = a.weight t.out_marking = ma for t in net.transitions: ma = Marking() for a in t.in_arcs: p = a.source ma[p] = a.weight t.in_marking = ma variants_idxs = variants_filter.get_variants_from_log_trace_idx( log, parameters=parameters) results = [] tmap = {} bmap = {} 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) for variant in variants_idxs: vlist = variants_util.get_activities_from_variant(variant) result = tr_vlist(vlist, net, initial_marking, final_marking, tmap, bmap, parameters=parameters) results.append(result) al_idx = {} for index_variant, variant in enumerate(variants_idxs): for trace_idx in variants_idxs[variant]: al_idx[trace_idx] = results[index_variant] ret = [] for i in range(len(log)): ret.append(al_idx[i]) return ret
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 apply(heu_net, parameters=None): """ Converts an Heuristics Net to a Petri net Parameters -------------- heu_net Heuristics net parameters Possible parameters of the algorithm Returns -------------- net Petri net im Initial marking fm Final marking """ if parameters is None: parameters = {} net = PetriNet("") im = Marking() fm = Marking() source_places = [] sink_places = [] hid_trans_count = 0 for index, sa_list in enumerate(heu_net.start_activities): source = PetriNet.Place("source" + str(index)) source_places.append(source) net.places.add(source) im[source] = 1 for index, ea_list in enumerate(heu_net.end_activities): sink = PetriNet.Place("sink" + str(index)) sink_places.append(sink) net.places.add(sink) fm[sink] = 1 act_trans = {} who_is_entering = {} who_is_exiting = {} for act1_name in heu_net.nodes: act1 = heu_net.nodes[act1_name] if act1_name not in act_trans: act_trans[act1_name] = PetriNet.Transition(act1_name, act1_name) net.transitions.add(act_trans[act1_name]) who_is_entering[act1_name] = set() who_is_exiting[act1_name] = set() for index, sa_list in enumerate(heu_net.start_activities): if act1_name in sa_list: who_is_entering[act1_name].add((None, index)) for index, ea_list in enumerate(heu_net.end_activities): if act1_name in ea_list: who_is_exiting[act1_name].add((None, index)) for act2 in act1.output_connections: act2_name = act2.node_name if act2_name not in act_trans: act_trans[act2_name] = PetriNet.Transition( act2_name, act2_name) net.transitions.add(act_trans[act2_name]) who_is_entering[act2_name] = set() who_is_exiting[act2_name] = set() for index, sa_list in enumerate(heu_net.start_activities): if act2_name in sa_list: who_is_entering[act2_name].add((None, index)) for index, ea_list in enumerate(heu_net.end_activities): if act2_name in ea_list: who_is_exiting[act2_name].add((None, index)) who_is_entering[act2_name].add((act1_name, None)) who_is_exiting[act1_name].add((act2_name, None)) places_entering = {} for act1 in who_is_entering: cliques = find_bindings(heu_net.nodes[act1].and_measures_in) places_entering[act1] = {} entering_activities = list(who_is_entering[act1]) entering_activities_wo_source = sorted( [x for x in entering_activities if x[0] is not None], key=lambda x: x[0]) entering_activities_only_source = [ x for x in entering_activities if x[0] is None ] if entering_activities_wo_source: master_place = PetriNet.Place("pre_" + act1) net.places.add(master_place) add_arc_from_to(master_place, act_trans[act1], net) if len(entering_activities) == 1: places_entering[act1][entering_activities[0]] = master_place else: for index, act in enumerate(entering_activities_wo_source): if act[0] in heu_net.nodes[act1].and_measures_in: z = 0 while z < len(cliques): if act[0] in cliques[z]: hid_trans_count = hid_trans_count + 1 hid_trans = PetriNet.Transition( "hid_" + str(hid_trans_count), None) net.transitions.add(hid_trans) add_arc_from_to(hid_trans, master_place, net) for act2 in cliques[z]: if (act2, None) not in places_entering[act1]: s_place = PetriNet.Place("splace_in_" + act1 + "_" + act2 + "_" + str(index)) net.places.add(s_place) places_entering[act1][(act2, None)] = s_place add_arc_from_to( places_entering[act1][(act2, None)], hid_trans, net) del cliques[z] continue z = z + 1 pass elif act not in places_entering[act1]: hid_trans_count = hid_trans_count + 1 hid_trans = PetriNet.Transition( "hid_" + str(hid_trans_count), None) net.transitions.add(hid_trans) add_arc_from_to(hid_trans, master_place, net) if act not in places_entering[act1]: s_place = PetriNet.Place("splace_in_" + act1 + "_" + str(index)) net.places.add(s_place) places_entering[act1][act] = s_place add_arc_from_to(places_entering[act1][act], hid_trans, net) for el in entering_activities_only_source: if len(entering_activities) == 1: add_arc_from_to(source_places[el[1]], act_trans[act1], net) else: hid_trans_count = hid_trans_count + 1 hid_trans = PetriNet.Transition("hid_" + str(hid_trans_count), None) net.transitions.add(hid_trans) add_arc_from_to(source_places[el[1]], hid_trans, net) add_arc_from_to(hid_trans, master_place, net) for act1 in who_is_exiting: cliques = find_bindings(heu_net.nodes[act1].and_measures_out) exiting_activities = list(who_is_exiting[act1]) exiting_activities_wo_sink = sorted( [x for x in exiting_activities if x[0] is not None], key=lambda x: x[0]) exiting_activities_only_sink = [ x for x in exiting_activities if x[0] is None ] if exiting_activities_wo_sink: if len(exiting_activities) == 1 and len( exiting_activities_wo_sink) == 1: ex_act = exiting_activities_wo_sink[0] if (act1, None) in places_entering[ex_act[0]]: add_arc_from_to(act_trans[act1], places_entering[ex_act[0]][(act1, None)], net) else: int_place = PetriNet.Place("intplace_" + str(act1)) net.places.add(int_place) add_arc_from_to(act_trans[act1], int_place, net) for ex_act in exiting_activities_wo_sink: if (act1, None) in places_entering[ex_act[0]]: if ex_act[0] in heu_net.nodes[act1].and_measures_out: z = 0 while z < len(cliques): if ex_act[0] in cliques[z]: hid_trans_count = hid_trans_count + 1 hid_trans = PetriNet.Transition( "hid_" + str(hid_trans_count), None) net.transitions.add(hid_trans) add_arc_from_to(int_place, hid_trans, net) for act in cliques[z]: add_arc_from_to( hid_trans, places_entering[act][(act1, None)], net) del cliques[z] continue z = z + 1 else: hid_trans_count = hid_trans_count + 1 hid_trans = PetriNet.Transition( "hid_" + str(hid_trans_count), None) net.transitions.add(hid_trans) add_arc_from_to(int_place, hid_trans, net) add_arc_from_to( hid_trans, places_entering[ex_act[0]][(act1, None)], net) for el in exiting_activities_only_sink: if len(exiting_activities) == 1: add_arc_from_to(act_trans[act1], sink_places[el[1]], net) else: hid_trans_count = hid_trans_count + 1 hid_trans = PetriNet.Transition("hid_" + str(hid_trans_count), None) net.transitions.add(hid_trans) add_arc_from_to(int_place, hid_trans, net) add_arc_from_to(hid_trans, sink_places[el[1]], net) net = remove_rendundant_invisible_transitions(net) from pm4py.objects.petri_net.utils import reduction reduction.apply_simple_reduction(net) return net, im, fm
def graphviz_visualization(net, image_format="png", initial_marking=None, final_marking=None, decorations=None, debug=False, set_rankdir=None, font_size="12", bgcolor="transparent"): """ Provides visualization for the petrinet Parameters ---------- net: :class:`pm4py.entities.petri.petrinet.PetriNet` Petri net image_format Format that should be associated to the image initial_marking Initial marking of the Petri net final_marking Final marking of the Petri net decorations Decorations of the Petri net (says how element must be presented) debug Enables debug mode set_rankdir Sets the rankdir to LR (horizontal layout) Returns ------- viz : Returns a graph object """ if initial_marking is None: initial_marking = Marking() if final_marking is None: final_marking = Marking() if decorations is None: decorations = {} font_size = str(font_size) filename = tempfile.NamedTemporaryFile(suffix='.gv') viz = Digraph(net.name, filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) if set_rankdir: viz.graph_attr['rankdir'] = set_rankdir else: viz.graph_attr['rankdir'] = 'LR' # transitions viz.attr('node', shape='box') for t in net.transitions: if t.label is not None: if t in decorations and "label" in decorations[ t] and "color" in decorations[t]: viz.node(str(id(t)), decorations[t]["label"], style='filled', fillcolor=decorations[t]["color"], border='1', fontsize=font_size) else: viz.node(str(id(t)), str(t.label), fontsize=font_size) else: if debug: viz.node(str(id(t)), str(t.name), fontsize=font_size) elif t in decorations and "color" in decorations[ t] and "label" in decorations[t]: viz.node(str(id(t)), decorations[t]["label"], style='filled', fillcolor=decorations[t]["color"], fontsize=font_size) else: viz.node(str(id(t)), "", style='filled', fillcolor="black", fontsize=font_size) # places viz.attr('node', shape='circle', fixedsize='true', width='0.75') # add places, in order by their (unique) name, to avoid undeterminism in the visualization places_sort_list_im = sorted( [x for x in list(net.places) if x in initial_marking], key=lambda x: x.name) places_sort_list_fm = sorted([ x for x in list(net.places) if x in final_marking and not x in initial_marking ], key=lambda x: x.name) places_sort_list_not_im_fm = sorted([ x for x in list(net.places) if x not in initial_marking and x not in final_marking ], key=lambda x: x.name) # making the addition happen in this order: # - first, the places belonging to the initial marking # - after, the places not belonging neither to the initial marking and the final marking # - at last, the places belonging to the final marking (but not to the initial marking) # in this way, is more probable that the initial marking is on the left and the final on the right places_sort_list = places_sort_list_im + places_sort_list_not_im_fm + places_sort_list_fm for p in places_sort_list: if p in initial_marking: viz.node(str(id(p)), str(initial_marking[p]), style='filled', fillcolor="green", fontsize=font_size) elif p in final_marking: viz.node(str(id(p)), "", style='filled', fillcolor="orange", fontsize=font_size) else: if debug: viz.node(str(id(p)), str(p.name), fontsize=font_size) else: if p in decorations and "color" in decorations[ p] and "label" in decorations[p]: viz.node(str(id(p)), decorations[p]["label"], style='filled', fillcolor=decorations[p]["color"], fontsize=font_size) else: viz.node(str(id(p)), "") # add arcs, in order by their source and target objects names, to avoid undeterminism in the visualization arcs_sort_list = sorted(list(net.arcs), key=lambda x: (x.source.name, x.target.name)) for a in arcs_sort_list: if a in decorations and "label" in decorations[ a] and "penwidth" in decorations[a]: viz.edge(str(id(a.source)), str(id(a.target)), label=decorations[a]["label"], penwidth=decorations[a]["penwidth"], fontsize=font_size) elif a in decorations and "color" in decorations[a]: viz.edge(str(id(a.source)), str(id(a.target)), color=decorations[a]["color"], fontsize=font_size) else: viz.edge(str(id(a.source)), str(id(a.target)), fontsize=font_size) viz.attr(overlap='false') viz.format = image_format return viz
def graphviz_visualization(net, image_format="png", initial_marking=None, final_marking=None, decorations=None, debug=False, set_rankdir=None, font_size="12", bgcolor="transparent"): """ Provides visualization for the petrinet Parameters ---------- net: :class:`pm4py.entities.petri.petrinet.PetriNet` Petri net image_format Format that should be associated to the image initial_marking Initial marking of the Petri net final_marking Final marking of the Petri net decorations Decorations of the Petri net (says how element must be presented) debug Enables debug mode set_rankdir Sets the rankdir to LR (horizontal layout) Returns ------- viz : Returns a graph object """ if initial_marking is None: initial_marking = Marking() if final_marking is None: final_marking = Marking() if decorations is None: decorations = {} font_size = str(font_size) filename = tempfile.NamedTemporaryFile(suffix='.gv') viz = Digraph(net.name, filename=filename.name, engine='dot', graph_attr={'bgcolor': bgcolor}) if set_rankdir: viz.graph_attr['rankdir'] = set_rankdir else: viz.graph_attr['rankdir'] = 'LR' # transitions viz.attr('node', shape='box') for t in net.transitions: if t.label is not None: if t in decorations and "label" in decorations[ t] and "color" in decorations[t]: viz.node(str(id(t)), decorations[t]["label"], style='filled', fillcolor=decorations[t]["color"], border='1', fontsize=font_size) else: viz.node(str(id(t)), str(t.label), fontsize=font_size) else: if debug: viz.node(str(id(t)), str(t.name), fontsize=font_size) elif t in decorations and "color" in decorations[ t] and "label" in decorations[t]: viz.node(str(id(t)), decorations[t]["label"], style='filled', fillcolor=decorations[t]["color"], fontsize=font_size) else: viz.node(str(id(t)), "", style='filled', fillcolor="black", fontsize=font_size) if petri_properties.TRANS_GUARD in t.properties: guard = t.properties[petri_properties.TRANS_GUARD] viz.node(str(id(t)) + "guard", style="dotted", label=guard) viz.edge(str(id(t)) + "guard", str(id(t)), arrowhead="none", style="dotted") # places # add places, in order by their (unique) name, to avoid undeterminism in the visualization places_sort_list_im = sorted( [x for x in list(net.places) if x in initial_marking], key=lambda x: x.name) places_sort_list_fm = sorted([ x for x in list(net.places) if x in final_marking and not x in initial_marking ], key=lambda x: x.name) places_sort_list_not_im_fm = sorted([ x for x in list(net.places) if x not in initial_marking and x not in final_marking ], key=lambda x: x.name) # making the addition happen in this order: # - first, the places belonging to the initial marking # - after, the places not belonging neither to the initial marking and the final marking # - at last, the places belonging to the final marking (but not to the initial marking) # in this way, is more probable that the initial marking is on the left and the final on the right places_sort_list = places_sort_list_im + places_sort_list_not_im_fm + places_sort_list_fm for p in places_sort_list: if p in initial_marking: if initial_marking[p] == 1: viz.node(str(id(p)), "<●>", fontsize="34", fixedsize='true', shape="circle", width='0.75') else: viz.node(str(id(p)), str(initial_marking[p]), fontsize="34", fixedsize='true', shape="circle", width='0.75') elif p in final_marking: # <■> viz.node(str(id(p)), "<■>", fontsize="32", shape='doublecircle', fixedsize='true', width='0.75') else: if debug: viz.node(str(id(p)), str(p.name), fontsize=font_size, shape="ellipse") else: if p in decorations and "color" in decorations[ p] and "label" in decorations[p]: viz.node(str(id(p)), decorations[p]["label"], style='filled', fillcolor=decorations[p]["color"], fontsize=font_size, shape="ellipse") else: viz.node(str(id(p)), "", shape='circle', fixedsize='true', width='0.75') # add arcs, in order by their source and target objects names, to avoid undeterminism in the visualization arcs_sort_list = sorted(list(net.arcs), key=lambda x: (x.source.name, x.target.name)) # check if there is an arc with weight different than 1. # in that case, all the arcs in the visualization should have the arc weight visible arc_weight_visible = False for arc in arcs_sort_list: if arc.weight != 1: arc_weight_visible = True break for a in arcs_sort_list: arrowhead = "normal" if petri_properties.ARCTYPE in a.properties: if a.properties[ petri_properties.ARCTYPE] == petri_properties.RESET_ARC: arrowhead = "vee" elif a.properties[petri_properties. ARCTYPE] == petri_properties.INHIBITOR_ARC: arrowhead = "dot" if a in decorations and "label" in decorations[ a] and "penwidth" in decorations[a]: viz.edge(str(id(a.source)), str(id(a.target)), label=decorations[a]["label"], penwidth=decorations[a]["penwidth"], fontsize=font_size, arrowhead=arrowhead) elif a in decorations and "color" in decorations[a]: viz.edge(str(id(a.source)), str(id(a.target)), color=decorations[a]["color"], fontsize=font_size, arrowhead=arrowhead) else: if arc_weight_visible: viz.edge(str(id(a.source)), str(id(a.target)), fontsize=font_size, arrowhead=arrowhead, label=str(a.weight)) else: viz.edge(str(id(a.source)), str(id(a.target)), fontsize=font_size, arrowhead=arrowhead) viz.attr(overlap='false') viz.format = image_format return viz
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 __transform_model_to_mem_efficient_structure(net, im, fm, trace, parameters=None): """ Transform the Petri net model to a memory efficient structure Parameters -------------- net Petri net im Initial marking fm Final marking trace Trace parameters Parameters Returns -------------- model_struct Model data structure, including: PLACES_DICT: associates each place to a number INV_TRANS_DICT: associates a number to each transition LABELS_DICT: labels dictionary (a label to a number) TRANS_LABELS_DICT: associates each transition to the number corresponding to its label TRANS_PRE_DICT: preset of a transition, expressed as in this data structure TRANS_POST_DICT: postset of a transition, expressed as in this data structure TRANSF_IM: transformed initial marking TRANSF_FM: transformed final marking TRANSF_MODEL_COST_FUNCTION: transformed model cost function """ if parameters is None: parameters = {} activity_key = exec_utils.get_param_value(Parameters.ACTIVITY_KEY, parameters, DEFAULT_NAME_KEY) labels = sorted(list(set(x[activity_key] for x in trace))) model_cost_function = exec_utils.get_param_value( Parameters.PARAM_MODEL_COST_FUNCTION, parameters, None) if model_cost_function is None: model_cost_function = {} for t in net.transitions: if t.label is not None: model_cost_function[t] = align_utils.STD_MODEL_LOG_MOVE_COST else: preset_t = Marking() for a in t.in_arcs: preset_t[a.source] = a.weight # optimization 12/08/2020 # # instead of giving undiscriminately weight 1 to # invisible transitions, assign weight 0 to the ones # for which no 'sync' transition is enabled in their # activation markings. # # this requires to modify the state of the alignment, keeping track # of the length of the alignment, to avoid loops. en_t = enabled_transitions(net, preset_t) vis_t_trace = [t for t in en_t if t.label in labels] if len(vis_t_trace) == 0: model_cost_function[t] = 0 else: model_cost_function[t] = align_utils.STD_TAU_COST places_dict = {place: index for index, place in enumerate(net.places)} trans_dict = {trans: index for index, trans in enumerate(net.transitions)} labels = sorted( list(set(t.label for t in net.transitions if t.label is not None))) labels_dict = {labels[i]: i for i in range(len(labels))} trans_labels_dict = {} for t in net.transitions: trans_labels_dict[trans_dict[t]] = labels_dict[ t.label] if t.label is not None else None trans_pre_dict = { trans_dict[t]: {places_dict[x.source]: x.weight for x in t.in_arcs} for t in net.transitions } trans_post_dict = { trans_dict[t]: {places_dict[x.target]: x.weight for x in t.out_arcs} for t in net.transitions } transf_im = {places_dict[p]: im[p] for p in im} transf_fm = {places_dict[p]: fm[p] for p in fm} transf_model_cost_function = { trans_dict[t]: model_cost_function[t] for t in net.transitions } inv_trans_dict = {y: x for x, y in trans_dict.items()} return { PLACES_DICT: places_dict, INV_TRANS_DICT: inv_trans_dict, LABELS_DICT: labels_dict, TRANS_LABELS_DICT: trans_labels_dict, TRANS_PRE_DICT: trans_pre_dict, TRANS_POST_DICT: trans_post_dict, TRANSF_IM: transf_im, TRANSF_FM: transf_fm, TRANSF_MODEL_COST_FUNCTION: transf_model_cost_function }
def export_petri_tree(petrinet, marking, final_marking=None, export_prom5=False, parameters=None): """ Export a Petrinet to a XML tree Parameters ---------- petrinet: :class:`pm4py.entities.petri.petrinet.PetriNet` Petri net marking: :class:`pm4py.entities.petri.petrinet.Marking` Marking final_marking: :class:`pm4py.entities.petri.petrinet.Marking` Final marking (optional) export_prom5 Enables exporting PNML files in a format that is ProM5-friendly parameters Other parameters of the algorithm Returns ---------- tree XML tree """ if parameters is None: parameters = {} if final_marking is None: final_marking = Marking() root = etree.Element("pnml") net = etree.SubElement(root, "net") net.set("id", "net1") net.set("type", "http://www.pnml.org/version-2009/grammar/pnmlcoremodel") if export_prom5 is True: page = net else: page = etree.SubElement(net, "page") page.set("id", "n0") places_map = {} for place in petrinet.places: places_map[place] = place.name pl = etree.SubElement(page, "place") pl.set("id", place.name) pl_name = etree.SubElement(pl, "name") pl_name_text = etree.SubElement(pl_name, "text") pl_name_text.text = place.properties[ constants. PLACE_NAME_TAG] if constants.PLACE_NAME_TAG in place.properties else place.name if place in marking: pl_initial_marking = etree.SubElement(pl, "initialMarking") pl_initial_marking_text = etree.SubElement(pl_initial_marking, "text") pl_initial_marking_text.text = str(marking[place]) if constants.LAYOUT_INFORMATION_PETRI in place.properties: graphics = etree.SubElement(pl, "graphics") position = etree.SubElement(graphics, "position") position.set( "x", str(place.properties[constants.LAYOUT_INFORMATION_PETRI][0] [0])) position.set( "y", str(place.properties[constants.LAYOUT_INFORMATION_PETRI][0] [1])) dimension = etree.SubElement(graphics, "dimension") dimension.set( "x", str(place.properties[constants.LAYOUT_INFORMATION_PETRI][1] [0])) dimension.set( "y", str(place.properties[constants.LAYOUT_INFORMATION_PETRI][1] [1])) transitions_map = {} for transition in petrinet.transitions: transitions_map[transition] = transition.name trans = etree.SubElement(page, "transition") trans.set("id", transition.name) trans_name = etree.SubElement(trans, "name") trans_text = etree.SubElement(trans_name, "text") if constants.LAYOUT_INFORMATION_PETRI in transition.properties: graphics = etree.SubElement(trans, "graphics") position = etree.SubElement(graphics, "position") position.set( "x", str(transition.properties[constants.LAYOUT_INFORMATION_PETRI] [0][0])) position.set( "y", str(transition.properties[constants.LAYOUT_INFORMATION_PETRI] [0][1])) dimension = etree.SubElement(graphics, "dimension") dimension.set( "x", str(transition.properties[constants.LAYOUT_INFORMATION_PETRI] [1][0])) dimension.set( "y", str(transition.properties[constants.LAYOUT_INFORMATION_PETRI] [1][1])) if constants.STOCHASTIC_DISTRIBUTION in transition.properties: random_variable = transition.properties[ constants.STOCHASTIC_DISTRIBUTION] stochastic_information = etree.SubElement(trans, "toolspecific") stochastic_information.set("tool", "StochasticPetriNet") stochastic_information.set("version", "0.2") distribution_type = etree.SubElement(stochastic_information, "property") distribution_type.set("key", "distributionType") distribution_type.text = random_variable.get_distribution_type() if not random_variable.get_distribution_type() == "IMMEDIATE": distribution_parameters = etree.SubElement( stochastic_information, "property") distribution_parameters.set("key", "distributionParameters") distribution_parameters.text = random_variable.get_distribution_parameters( ) distribution_priority = etree.SubElement(stochastic_information, "property") distribution_priority.set("key", "priority") distribution_priority.text = str(random_variable.get_priority()) distribution_invisible = etree.SubElement(stochastic_information, "property") distribution_invisible.set("key", "invisible") distribution_invisible.text = str( True if transition.label is None else False).lower() distribution_weight = etree.SubElement(stochastic_information, "property") distribution_weight.set("key", "weight") distribution_weight.text = str(random_variable.get_weight()) if transition.label is not None: trans_text.text = transition.label else: trans_text.text = transition.name tool_specific = etree.SubElement(trans, "toolspecific") tool_specific.set("tool", "ProM") tool_specific.set("version", "6.4") tool_specific.set("activity", "$invisible$") tool_specific.set("localNodeID", str(uuid.uuid4())) if export_prom5 is True: if transition.label is not None: prom5_specific = etree.SubElement(trans, "toolspecific") prom5_specific.set("tool", "ProM") prom5_specific.set("version", "5.2") log_event_prom5 = etree.SubElement(prom5_specific, "logevent") event_name = transition.label.split("+")[0] event_transition = transition.label.split("+")[1] if len( transition.label.split("+")) > 1 else "complete" log_event_prom5_name = etree.SubElement( log_event_prom5, "name") log_event_prom5_name.text = event_name log_event_prom5_type = etree.SubElement( log_event_prom5, "type") log_event_prom5_type.text = event_transition for arc in petrinet.arcs: arc_el = etree.SubElement(page, "arc") arc_el.set("id", str(hash(arc))) if type(arc.source) is PetriNet.Place: arc_el.set("source", str(places_map[arc.source])) arc_el.set("target", str(transitions_map[arc.target])) else: arc_el.set("source", str(transitions_map[arc.source])) arc_el.set("target", str(places_map[arc.target])) if arc.weight > 1: inscription = etree.SubElement(arc_el, "inscription") arc_weight = etree.SubElement(inscription, "text") arc_weight.text = str(arc.weight) if len(final_marking) > 0: finalmarkings = etree.SubElement(net, "finalmarkings") marking = etree.SubElement(finalmarkings, "marking") for place in final_marking: placem = etree.SubElement(marking, "place") placem.set("idref", place.name) placem_text = etree.SubElement(placem, "text") placem_text.text = str(final_marking[place]) tree = etree.ElementTree(root) return tree
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