Install
pip install "r4pm[polars]"r4pm needs Python 3.9 or newer. Where a prebuilt wheel exists for your platform, pip installs it and you need nothing else. Otherwise pip builds from source, which needs a Rust toolchain. The polars extra is only needed for DataFrames (item_to_df and the r4pm.df module). More on extras and platforms in installation.
Get the sample data
The quickstart uses the Road Traffic Fine Management log: 150,370 fines, 561,470 events, 11 activities.
The script
Save this as quickstart.py next to the data folder:
import r4pm
import r4pm.petri_net
# Load the event log into the item registry. Python only holds its ID.
log = r4pm.import_item("EventLog", "data/road-traffic-fines.xes.gz")
# Directly-follows graph: which activity follows which, and how often.
dfg = r4pm.bindings.discover_dfg(log)
print(len(dfg["activities"]), "activities")
# Alpha+++ works on the activity projection: every trace variant once, with its count.
projection = r4pm.bindings.log_to_activity_projection(log)
print(r4pm.bindings.get_num_variants(projection), "variants")
net = r4pm.bindings.discover_alphaplusplusplus(
projection,
{
"balance_thresh": 0.1,
"fitness_thresh": 0.8,
"replay_thresh": 0.0,
"log_repair_skip_df_thresh_rel": 4.0,
"log_repair_loop_df_thresh_rel": 4.0,
"absolute_df_clean_thresh": 1,
"relative_df_clean_thresh": 0.01,
},
)
print(len(net["places"]), "places,", len(net["transitions"]), "transitions")
# How well does the model explain the log? Align every variant, then aggregate.
alignments = r4pm.bindings.align_variants(net, projection)
fitness = r4pm.bindings.compute_fitness(alignments, net)
print(f"log fitness {fitness['log_fitness']:.3f}")
r4pm.petri_net.export_pnml(net, "model.pnml")
# The same log as a polars DataFrame, one row per event.
df = r4pm.item_to_df(log)
print(df.shape)Run it:
python quickstart.py11 activities
231 variants
10 places, 16 transitions
log fitness 0.886
(561470, 16)Alpha+++ also prints about 20 lines of progress information while it runs, which the output above leaves out.
The script step by step
Load the log
r4pm.import_item(kind, path) reads the file into Rust4PM's item registry and returns an ID string. The kind says which data structure to build (EventLog for a classic XES log), and the file extension selects the format, so .xes, .xes.gz and .json all work. Event logs stay in Rust, and Python only passes the ID around. The item registry page explains why and how.
Discover a directly-follows graph
discover_dfg(log) returns plain Python data: a dict where activities maps each activity to its frequency, directly_follows_relations holds ((from, to), frequency) pairs, and start_activities and end_activities are lists of activity names.
Discover a Petri net with Alpha+++
Alpha+++ works on an activity projection, a compact form of the log that keeps every trace variant once with its count. log_to_activity_projection creates it as a new registry item. The road traffic log has 231 variants, so everything after this step is fast even though the log has 150,370 traces.
The thresholds passed to discover_alphaplusplusplus filter rare behavior before and during discovery. The discovery how-to explains each of them. The resulting Petri net is plain data again (places, transitions, arcs, markings).
Check conformance
align_variants computes an optimal alignment between the model and each variant. compute_fitness combines them, weighted by how often each variant occurs. It returns log_fitness, average_fitness, perfectly_fitting_frac and total_costs. A log fitness of 0.886 means the model explains most of the observed behavior but not all of it.
Export and DataFrames
r4pm.petri_net.export_pnml writes the net as PNML, which ProM, PM4Py and Propel can open. r4pm.petri_net.to_pm4py converts it to PM4Py objects directly. r4pm.item_to_df(log) turns the log into a polars DataFrame with one row per event (an OCEL becomes a dict of DataFrames). Call .to_pandas() on it for pandas.
Next steps
- Event data types: EventLog, OCEL and the linked OCEL types, and when to use which.
- Discover a model and check conformance in more depth.
- Object-centric analysis with the Order Management OCEL.
- Use Rust4PM with PM4Py.
- Every function, with its Python call: API reference.