use crate::models::OCEL;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct OCLanguageAbstraction {
pub start_ev_types: HashMap<String, HashSet<String>>,
pub end_ev_types: HashMap<String, HashSet<String>>,
pub directly_follows: HashMap<String, HashSet<(String, String)>>,
}
impl OCLanguageAbstraction {
pub fn create_from_ocel(ocel: &OCEL) -> Self {
let mut abstraction = Self::default();
let obj_to_type: HashMap<String, String> = ocel
.objects
.iter()
.map(|o| (o.id.clone(), o.object_type.clone()))
.collect();
let mut object_traces: HashMap<String, Vec<usize>> = HashMap::new();
for (idx, event) in ocel.events.iter().enumerate() {
for obj_id in event.all_object_ids() {
object_traces
.entry(obj_id.to_string())
.or_default()
.push(idx);
}
}
for (obj_id, event_indices) in object_traces {
if let Some(obj_type) = obj_to_type.get(&obj_id) {
if event_indices.is_empty() {
continue;
}
if event_indices.iter().any(|&idx| idx >= ocel.events.len()) {
continue; }
let mut sorted_indices = event_indices;
sorted_indices.sort_by_key(|&idx| &ocel.events[idx].timestamp);
let first_ev = &ocel.events[sorted_indices[0]].event_type;
let last_ev = &ocel.events[*sorted_indices.last().unwrap()].event_type;
abstraction
.start_ev_types
.entry(obj_type.clone())
.or_default()
.insert(first_ev.clone());
abstraction
.end_ev_types
.entry(obj_type.clone())
.or_default()
.insert(last_ev.clone());
let df_set = abstraction
.directly_follows
.entry(obj_type.clone())
.or_default();
for window in sorted_indices.windows(2) {
let e1 = &ocel.events[window[0]].event_type;
let e2 = &ocel.events[window[1]].event_type;
df_set.insert((e1.clone(), e2.clone()));
}
}
}
abstraction
}
}