 ### Check workflow net soundness

A workflow net is a Petri net that satisfy three conditions:

• There is an unique source place (part of the initial marking)
• There is an unique sink place (part of the final marking)
• Each place and transition is on a path from the source place to the sink place

These conditions can be verified easily (last is checked using the networkx library transforming the Petri net into a graph and observing nodes ancestors/descendants).

To verify the soundness, we have to verify the following conditions:

• Liveness
• Boundness

These are less easy to verify directly, but can be verified by the approach described in the paper “Clempner, Julio. “An analytical method for well-formed workflow/Petri net verification of classical soundness.” International Journal of Applied Mathematics and Computer Science 24.4 (2014): 931-939.”. Indeed, a linear programming problem involving the incidence matrix can be solved to verify if the Petri net is sound.

Let’s propose some code snippets. The Receipt log could be loaded:

```from pm4py.objects.log.importer.xes import factory as xes_importer
import os

log = xes_importer.apply(os.path.join("tests","input_data","receipt.xes"))```

Then some models could be retrieved using the Alpha Miner and the Inductive Miner

```from pm4py.algo.discovery.alpha import factory as alpha_miner
from pm4py.algo.discovery.inductive import factory as inductive_miner

alpha_net, alpha_im, alpha_fm = alpha_miner.apply(log)
inductive_net, inductive_im, inductive_fm = inductive_miner.apply(log)```

It is possible to check if the Petri net is a workflow net through the following code:

```from pm4py.objects.petri.check_soundness import check_wfnet

is_wfnet_alpha = check_wfnet(alpha_net)
is_wfnet_inductive = check_wfnet(inductive_net)

print("is_wfnet_alpha=",is_wfnet_alpha)
print("is_wfnet_inductive=",is_wfnet_inductive)```

Obtaining the following output:

```is_wfnet_alpha= False
is_wfnet_inductive= True```

Then, a check on the fact that the Petri nets are sound workflow nets could be done using the following code (we already know that the model extracted by the Alpha Miner does not satisfy the workflow net):

```from pm4py.objects.petri.check_soundness import check_petri_wfnet_and_soundness

is_soundwfnet_alpha = check_petri_wfnet_and_soundness(alpha_net)
is_woundwfnet_inductive = check_petri_wfnet_and_soundness(inductive_net)

print("is_soundwfnet_alpha=",is_soundwfnet_alpha)
print("is_woundwfnet_inductive=",is_woundwfnet_inductive)```

Obtaining the following output:

```is_soundwfnet_alpha= False
is_woundwfnet_inductive= True```

So the Petri net extracted by the Inductive Miner is a sound workflow net.

### Find cycles inside a Petri net

A cycle in a Petri net is a set of places and transitions that could be repeated several times (during a process execution).

Cycles can be detected by converting the Petri net into a directed graph using the networkx library.

Let’s provide some code snippets. We load the running-example log:

```from pm4py.objects.log.importer.xes import factory as xes_importer
import os

log = xes_importer.apply(os.path.join("tests","input_data","running-example.xes"))```

Apply the Inductive Miner algorithm:

```from pm4py.algo.discovery.inductive import factory as inductive_miner

net, initial_marking, final_marking = inductive_miner.apply(log)```

Then we retrieve the cycles in the Petri net:

```from pm4py.objects.petri import utils

cycles = utils.get_cycles_petri_net_places(net)

print(cycles)```

Getting this output (each cycle is described as a set of places):

``[[p_7, p_6, p_4], [p_7, p_6, p_4], [p_7, p_6, p_4], [p_7, p_6, p_8, p_5, p_4], [p_7, p_6, p_8, p_5, p_4], [p_7, p_6, p_8, p_5, p_4], [p_7, p_6, p_8, p_5, p_4], [p_7, p_6, p_8, p_5, p_4], [p_7, p_6, p_8, p_5, p_4], [p_7, p_6, p_4], [p_7, p_6, p_4], [p_7, p_6, p_4], [p_7, p_6, p_8, p_5, p_4], [p_7, p_6, p_8, p_5, p_4], [p_7, p_6, p_8, p_5, p_4], [p_7, p_6, p_8, p_5, p_4], [p_7, p_6, p_8, p_5, p_4], [p_7, p_6, p_8, p_5, p_4]])``

### Find the strongly connected components in a Petri net

Strongly connected components are subnets in which a path in the graph exists between each element.

Strongly connected components can be detected by converting the Petri net into a directed graph using the networkx library.

Let’s provide some code snippets. We load the running-example log:

```from pm4py.objects.log.importer.xes import factory as xes_importer
import os

log = xes_importer.apply(os.path.join("tests","input_data","running-example.xes"))```

Apply the Inductive Miner algorithm:

```from pm4py.algo.discovery.inductive import factory as inductive_miner

net, initial_marking, final_marking = inductive_miner.apply(log)```

Then we retrieve the strongly connected components in the Petri net:

```from pm4py.objects.petri import utils

scc = utils.get_strongly_connected_subnets(net)

print(scc)```

Getting this output on the console:

`[[<pm4py.objects.petri.petrinet.PetriNet object at 0x000001ED784F1AC8>, [], []]]`

To represent and visualize on the screen the subnet, the following instructions could be provided:

```from pm4py.visualization.petrinet import factory as pn_vis_factory

gviz = pn_vis_factory.apply(scc, scc, scc)
pn_vis_factory.view(gviz)``` .