Skip to main content
Rust4PM

Event data types

Rust4PM has five data types for event data. Which one a function needs depends on whether the data is case-centric or object-centric, and on how it is accessed.

Case-centric and object-centric data

A case-centric event log groups events into traces, one trace per case (a fine, a patient, an order). This is the classic XES model, and most process discovery and conformance techniques work on it.

An object-centric event log (OCEL 2.0) drops the single case notion. Events relate to any number of objects of different types, and objects relate to each other. In the Order Management log, a pick item event relates to an item, a product and an employee at the same time.

The five types

TypeWhat it isTypical useHow to get one
EventLogTraces of events with attributes, as in XESDirectly-follows graphs, exporting XESImport .xes, .xes.gz or .json; flatten an OCEL
EventLogActivityProjectionEach trace variant once (as activity indices) with its frequencyAlpha+++, alignments, fitness, variantslog_to_activity_projection / EventLogActivityProjection::from(&log)
OCELOCEL 2.0 data as stored in a file: events, objects, relationships, attribute valuesReading and writing OCEL files, DataFramesImport .xml, .json, .sqlite, .ocel.csv (and .gz variants)
SlimLinkedOCELA compact OCEL with indexed event-to-object and object-to-object relations in both directionsAlmost all object-centric functions: OC-DECLARE, flattening, statistics, building logs from scratchImport the same files as OCEL, or convert an OCEL
IndexLinkedOCELThe full OCEL plus index-based lookupsCustom Rust code that needs both the original data and fast lookupsImport the same files as OCEL, or index_link_ocel

For object-centric work, start with SlimLinkedOCEL. Every function page in the API reference shows the type each argument expects.

In code

import r4pm

# Case-centric: one trace per case, events ordered by time.
log = r4pm.import_item("EventLog", "data/road-traffic-fines.xes.gz")
projection = r4pm.bindings.log_to_activity_projection(log)
print(
    r4pm.bindings.get_num_cases(projection), "cases,",
    r4pm.bindings.get_num_variants(projection), "variants",
)

# Object-centric: the OCEL 2.0 data as it is stored in the file.
ocel = r4pm.import_item("OCEL", "data/order-management.xml.gz")
tables = r4pm.item_to_df(ocel)
print(tables["events"].height, "events,", tables["objects"].height, "objects")

# Most analysis functions take the linked form, which indexes all relationships.
locel = r4pm.convert_item(ocel, "SlimLinkedOCEL")
for event_type, object_type, count in r4pm.bindings.locel_event_object_type_counts(locel)[:3]:
    print(f"{event_type} -> {object_type}: {count}")

In Python, import_item builds any of these types directly from a file, so you rarely convert by hand. r4pm.convert_item(id, "SlimLinkedOCEL") turns one registry item into another when you need to.

In Rust, SlimLinkedOCEL::from_ocel(ocel) and IndexLinkedOCEL::from_ocel(ocel) build the linked forms, and both implement Importable themselves. The LinkedOCELAccess trait gives the same read access on both: all events and objects, their types, and relationships in both directions.

From object-centric to case-centric

Classic techniques need a single case notion. flatten_ocel_on(ocel, object_type) picks one object type and turns every object of that type into a trace with all events related to it. The filter and flatten how-to shows it on the Order Management log.