[8]:
import warnings
warnings.filterwarnings("ignore", category=UserWarning)

Log Filtering with Linear Temporal Properties

The filtering of a log according to Linear Temporal Logic properties is implemented with an LTLf checker based on automata. First of all we create an D4PyEventLog object that wraps the log.

[9]:
import os

from Declare4Py.D4PyEventLog import D4PyEventLog

log_path = os.path.join("../../../", "tests", "test_logs","Sepsis Cases.xes.gz")
event_log = D4PyEventLog()
event_log.parse_xes_log(log_path)

The classes LTLTemplate and LTLModel are responsible for the LTLf template definitions and their instantiations into LTLf models given some activities and/or payload names:

[10]:
from Declare4Py.ProcessModels.LTLModel import LTLTemplate
from Declare4Py.ProcessModels.LTLModel import LTLModel

template : LTLTemplate = LTLTemplate('is_first_state_a')
model_1 : LTLModel= template.fill_template(['ER Registration'], attr_type=['concept:name'])

template: LTLTemplate = LTLTemplate('eventually_a')
model_2 : LTLModel = template.fill_template(['Leucocytes'], attr_type=['concept:name'])

The class LTLAnalyzer is therefore needed to analyze the log and filtering its traces according to multiple input LTLf models.

[11]:
from Declare4Py.ProcessMiningTasks.ConformanceChecking.LTLAnalyzer import LTLAnalyzer

analyzer = LTLAnalyzer(event_log, [model_1, model_2])
conf_check_res_df = analyzer.run_multiple_models(minimize_automaton=False)

The output is a Pandas DataFrame that can be easily queried.

[12]:
print(f"Accepted traces: {len(conf_check_res_df[conf_check_res_df['accepted'] == True])}")
conf_check_res_df
Accepted traces: 957
[12]:
case:concept:name accepted
0 A True
1 B True
2 C True
3 D True
4 E True
... ... ...
1045 HNA True
1046 INA False
1047 JNA False
1048 KNA True
1049 LNA False

1050 rows × 2 columns

The same easy coding holds also for Branched-DECLARE templates:

[13]:
template = LTLTemplate('alternate_response')
activities_a = ["Er Registration", "IV Liquid"]
activities_b = ["CRP", "IV Antibiotics"]
model_1 = template.fill_template(activities_a, activities_b)

template = LTLTemplate('not_precedence')
activities_a = ["ER Sepsis Triage", "CRP"]
activities_b = ["IV Antibiotics", "LacticAcid"]
model_2 = template.fill_template(activities_a, activities_b)

analyzer = LTLAnalyzer(event_log, [model_1, model_2])
conf_check_res_df = analyzer.run_multiple_models()

We therefore access the Pandas Dataframe

[14]:
print(f"Accepted traces: {len(conf_check_res_df[conf_check_res_df['accepted'] == True])}")
conf_check_res_df
Accepted traces: 117
[14]:
case:concept:name accepted
0 A False
1 B False
2 C False
3 D False
4 E False
... ... ...
1045 HNA False
1046 INA False
1047 JNA False
1048 KNA False
1049 LNA False

1050 rows × 2 columns

More information about managing process models and the LTLf or B-Declare templates can be found in tutorials 2 and 3.