use pictl_types::*;
use std::collections::HashMap;
pub fn discover_dfg(log: &EventLog, activity_key: &str) -> Result<DFG> {
let mut dfg = DFG::new();
let mut node_map: HashMap<String, usize> = HashMap::new();
let mut edge_counts: HashMap<(usize, usize), usize> = HashMap::new();
let mut start_activities: HashMap<String, usize> = HashMap::new();
let mut end_activities: HashMap<String, usize> = HashMap::new();
for trace in &log.traces {
let activities: Vec<String> = trace
.events
.iter()
.filter_map(|e| e.get_activity(activity_key))
.collect();
if activities.is_empty() {
continue;
}
for (i, activity) in activities.iter().enumerate() {
let node_id = *node_map.entry(activity.clone()).or_insert_with(|| {
let id = dfg.nodes.len();
dfg.nodes.push(DFGNode::new(activity.clone(), 0));
id
});
dfg.nodes[node_id].frequency += 1;
if i == 0 {
*start_activities.entry(activity.clone()).or_insert(0) += 1;
}
if i == activities.len() - 1 {
*end_activities.entry(activity.clone()).or_insert(0) += 1;
}
if i + 1 < activities.len() {
let from_id = node_id;
let to_activity = &activities[i + 1];
let to_id = *node_map.entry(to_activity.clone()).or_insert_with(|| {
let id = dfg.nodes.len();
dfg.nodes.push(DFGNode::new(to_activity.clone(), 0));
id
});
*edge_counts.entry((from_id, to_id)).or_insert(0) += 1;
}
}
}
for ((from_id, to_id), frequency) in edge_counts.iter() {
let from = &dfg.nodes[*from_id].activity;
let to = &dfg.nodes[*to_id].activity;
dfg.edges
.push(DFGEdge::new(from.clone(), to.clone(), *frequency));
}
dfg.start_activities = start_activities.keys().cloned().collect();
dfg.end_activities = end_activities.keys().cloned().collect();
Ok(dfg)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dfg_discovery() {
let mut attrs1 = std::collections::HashMap::new();
attrs1.insert(
"concept:name".to_string(),
AttributeValue::String("A".to_string()),
);
let mut attrs2 = std::collections::HashMap::new();
attrs2.insert(
"concept:name".to_string(),
AttributeValue::String("B".to_string()),
);
let log = EventLog::new(
vec![Trace::new(
"case1".to_string(),
vec![Event::new(attrs1), Event::new(attrs2)],
)],
std::collections::HashMap::new(),
);
let dfg = discover_dfg(&log, "concept:name").unwrap();
assert_eq!(dfg.nodes.len(), 2);
assert_eq!(dfg.edges.len(), 1);
assert_eq!(dfg.start_activities, vec!["A"]);
assert_eq!(dfg.end_activities, vec!["B"]);
}
}