Petri Net Management

Petri nets are one of the most common formalism to express a process model. A Petri net is a directed bipartite graph, in which the nodes represent transitions and places. Arcs are connecting places to transitions and transitions to places, and have an associated weight. A transition can fire if each of its input places contains a number of tokens that is at least equal to the weight of the arc connecting the place to the transition. When a transition is fired, then tokens are removed from the input places according to the weight of the input arc, and are added to the output places according to the weight of the output arc.

A marking is a state in the Petri net that associates each place to a number of tokens and is uniquely associated to a set of enabled transitions that could be fired according to the marking.

Process Discovery algorithms implemented in pm4py returns a Petri net along with an initial marking and a final marking. An initial marking is the initial state of execution of a process, a final marking is a state that should be reached at the end of the execution of the process.

Importing and exporting

Petri nets, along with their initial and final marking, can be imported/exported from the PNML file format. The following code can be used to import a Petri net along with the initial and final marking. In particular, the Petri net related to running-example process is loaded from the test folder:

import os
from pm4py.objects.petri.importer import pnml as pnml_importer

net, initial_marking, final_marking = pnml_importer.import_net(os.path.join("tests","input_data","running-example.pnml"))

The Petri net is visualized using the Petri net visualizer:

from pm4py.visualization.petrinet import factory as pn_vis_factory

gviz = pn_vis_factory.apply(net, initial_marking, final_marking)
pn_vis_factory.view(gviz)

A Petri net can be exported along with only its initial marking:

from pm4py.objects.petri.exporter import pnml as pnml_exporter

pnml_exporter.export_net(net, initial_marking, "petri.pnml")

And along with both its initial marking and final marking:

pnml_exporter.export_net(net, initial_marking, "petri_final.pnml", final_marking=final_marking)

Petri Net properties

The list of transitions enabled in a particular marking can be obtained using the following code:

from pm4py.objects.petri import semantics

transitions = semantics.enabled_transitions(net, initial_marking)

The function print(transitions) reports that only the transition register request is enabled in the initial marking in the given Petri net. To obtained all places, transitions, and arcs of the Petri net, the following code can be used:

places = net.places
transitions = net.transitions
arcs = net.arcs

Each place has a name and a set of input/output arcs (connected at source/target to a transition). Each transition has a name and a label and a set of input/output arcs (connected at source/target to a place). The following code prints for each place the name, and for each input arc of the place the name and the label of the corresponding transition:

for place in places:
    print("\nPLACE: "+place.name)

    for arc in place.in_arcs:
        print(arc.source.name, arc.source.label)

The output starts with the following:

PLACE: sink 47
n10 register request
n16 reinitiate request

PLACE: source 45
...

Similarly, the following code prints for each transition the name and the label, and for each output arc of the transition the name of the corresponding place:

for trans in transitions:
    print("\nTRANS: ",trans.name, trans.label)

    for arc in trans.out_arcs:
        print(arc.target.name)

For the running example the output starts with the following:

TRANS:  n14 examine thoroughly
sink 54

TRANS:  n15 decide
middle 49
...

Creating a new Petri net

In this section, an overview of the code necessary to create a new Petri net with places, transitions, and arcs is provided. A Petri net object in pm4py should be created with a name. For example, this creates a Petri net with name new_petri_net

# creating an empty Petri net
net = PetriNet("new_petri_net")

Also places need to be named upon their creation:

# creating source, p_1 and sink place
source = PetriNet.Place("source")
sink = PetriNet.Place("sink")
p_1 = PetriNet.Place("p_1")

To be part of the Petri net they are added to it:

net.places.add(source)
net.places.add(sink)
net.places.add(p_1)

Similar to the places, transitions can be created. However, they need to be assigned a name and a label:

t_1 = PetriNet.Transition("name_1", "label_1")
t_2 = PetriNet.Transition("name_2", "label_2")

They should also be added to the Petri net:

net.transitions.add(t_1)
net.transitions.add(t_2)

The following code is useful to add arcs in the Petri net. Arcs can go from place to transition or from transition to place. The first parameter specifies the starting point of the arc, the second parameter its target and the last parameter states the Petri net it belongs to.

from pm4py.objects.petri import utils

utils.add_arc_from_to(source, t_1, net)
utils.add_arc_from_to(t_1, p_1, net)
utils.add_arc_from_to(p_1, t_2, net)
utils.add_arc_from_to(t_2, sink, net)

To complete the Petri net an initial and possibly a final marking need to be defined. In the following, we define the initial marking to contain 1 token in the source place and the final marking to contain 1 token in the sink place:

from pm4py.objects.petri.petrinet import Marking

initial_marking = Marking()
initial_marking[source] = 1
final_marking = Marking()
final_marking[sink] = 1

The resulting Petri net along with the initial and final marking could be exported:

from pm4py.objects.petri.exporter import pnml as pnml_exporter

pnml_exporter.export_net(net, initial_marking, "createdPetriNet1.pnml", final_marking=final_marking)

Or visualized:

from pm4py.visualization.petrinet import factory as pn_vis_factory

gviz = pn_vis_factory.apply(net, initial_marking, final_marking)
pn_vis_factory.view(gviz)

To obtain a specific output format (e.g. svg or png) a format parameter should be provided to the algorithm. The following code explains how to obtain an SVG representation of the Petri net:

from pm4py.visualization.petrinet import factory as pn_vis_factory

parameters = {"format":"svg"}
gviz = pn_vis_factory.apply(net, initial_marking, final_marking, parameters=parameters)
pn_vis_factory.view(gviz)

Instead of opening visualization of the model directly it can also be saved using the following code:

from pm4py.visualization.petrinet import factory as pn_vis_factory

parameters = {"format":"svg"}
gviz = pn_vis_factory.apply(net, initial_marking, final_marking, parameters=parameters)
pn_vis_factory.save(gviz, "alpha.svg")