SlimLinkedOCEL is a compact representation of an object-centric event log. It is designed for efficient in-memory construction and usage. Events and objects are represented by integer IDs (i.e., their index in the event/object list), and relationships are stored separately, which allows quickly identifying all related events/objects without scanning through the whole dataset. The slim_ocel_bindings module exposes its core functionality to Python, so you can build a log and export it to OCEL 2.0.
The script below builds a small log (one event type place order with a tip attribute; two object types order and item, where item has a price attribute; then 100 events, each with a new order and four items wired up via E2O and O2O), reads a few values back, and exports the result. The ev, order, item variables returned by the locel_add_* calls are the integer refs themselves: Each is the index of that element in the log. Every locel_get_* and locel_delete_* function takes such a ref.
Script
"""
Build, query, and export a SlimLinkedOCEL log.
Run: python example.py
Install: pip install r4pm
"""
import r4pm
import r4pm.bindings as b
# --- Build ---
locel = b.locel_new()
# One event type with a `tip` attribute.
b.locel_add_event_type(locel, "place order", [{"name": "tip", "type": "float"}])
# Two object types. `item` has a `price` attribute.
# (Object attributes are always time-indexed in OCEL 2.0.)
b.locel_add_object_type(locel, "order")
b.locel_add_object_type(locel, "item", [{"name": "price", "type": "float"}])
# 100 events. Each event gets its own order plus four items.
# The ints returned by `locel_add_event` / `locel_add_object` are the refs:
# each is the index of that element in the log. All query functions take these.
for i in range(100):
ev = b.locel_add_event(
locel,
"place order",
"2026-03-02T10:30:00Z",
None,
[round(i * 0.5, 2)], # tip
)
order = b.locel_add_object(locel, "order")
b.locel_add_e2o(locel, ev, order, "of")
for j in range(4):
# Each object attribute takes a list of (timestamp, value) tuples.
# For initial or constant values, use UNIX epoch.
price_history = [[("1970-01-01T00:00:00Z", round(j * 4.3, 2))]]
item = b.locel_add_object(locel, "item", None, price_history)
b.locel_add_e2o(locel, ev, item, "with")
b.locel_add_o2o(locel, item, order, "is in")
# --- Export ---
# File extension picks the format (see "Export formats" below).
r4pm.export_item(locel, "export.xml")
# --- Read back / Use ---
# How many events of a given type?
events = b.locel_get_evs_of_type(locel, "place order")
print(f"{len(events)} 'place order' events")
# -> 100 'place order' events
# Read an attribute off the most recently added event.
tip = b.locel_get_ev_attr_val(locel, ev, "tip")
print(f"last event tip = {tip}")
# -> last event tip = 49.5
# Walk the E2O relations of that event and show what it's linked to.
for qualifier, ob_ref in b.locel_get_e2o(locel, ev):
ob_type = b.locel_get_ob_type_of(locel, ob_ref)
print(f" {qualifier} -> {ob_type} (ref {ob_ref})")
# -> of -> order (ref 495)
# -> with -> item (ref 496)
# -> with -> item (ref 497)
# -> with -> item (ref 498)
# -> with -> item (ref 499)
Export formats
r4pm.export_item picks the output format from the file extension:
.xmlOCEL 2.0 XML.sqliteOCEL 2.0 SQLite.jsonOCEL 2.0 JSON
To write a SQLite database instead of XML, change the corresponding line to r4pm.export_item(locel, "export.sqlite").