1use std::collections::{HashMap, HashSet};
4
5#[derive(Debug, Clone)]
11pub struct ProcessEvent {
12 pub id: u64,
14 pub case_id: String,
16 pub activity: String,
18 pub timestamp: u64,
20 pub resource: Option<String>,
22 pub attributes: HashMap<String, String>,
24}
25
26#[derive(Debug, Clone)]
28pub struct Trace {
29 pub case_id: String,
31 pub events: Vec<ProcessEvent>,
33 pub attributes: HashMap<String, String>,
35}
36
37impl Trace {
38 pub fn new(case_id: String) -> Self {
40 Self {
41 case_id,
42 events: Vec::new(),
43 attributes: HashMap::new(),
44 }
45 }
46
47 pub fn add_event(&mut self, event: ProcessEvent) {
49 self.events.push(event);
50 }
51
52 pub fn activity_sequence(&self) -> Vec<&str> {
54 self.events.iter().map(|e| e.activity.as_str()).collect()
55 }
56
57 pub fn sort_by_timestamp(&mut self) {
59 self.events.sort_by_key(|e| e.timestamp);
60 }
61}
62
63#[derive(Debug, Clone)]
65pub struct EventLog {
66 pub name: String,
68 pub traces: HashMap<String, Trace>,
70 pub attributes: HashMap<String, String>,
72}
73
74impl EventLog {
75 pub fn new(name: String) -> Self {
77 Self {
78 name,
79 traces: HashMap::new(),
80 attributes: HashMap::new(),
81 }
82 }
83
84 pub fn add_event(&mut self, event: ProcessEvent) {
86 let trace = self
87 .traces
88 .entry(event.case_id.clone())
89 .or_insert_with(|| Trace::new(event.case_id.clone()));
90 trace.add_event(event);
91 }
92
93 pub fn activities(&self) -> HashSet<&str> {
95 self.traces
96 .values()
97 .flat_map(|t| t.events.iter().map(|e| e.activity.as_str()))
98 .collect()
99 }
100
101 pub fn trace_count(&self) -> usize {
103 self.traces.len()
104 }
105
106 pub fn event_count(&self) -> usize {
108 self.traces.values().map(|t| t.events.len()).sum()
109 }
110}
111
112#[derive(Debug, Clone)]
118pub struct DirectlyFollowsGraph {
119 pub activities: Vec<String>,
121 pub edges: Vec<DFGEdge>,
123 pub start_activities: HashMap<String, u64>,
125 pub end_activities: HashMap<String, u64>,
127 pub activity_counts: HashMap<String, u64>,
129}
130
131#[derive(Debug, Clone)]
133pub struct DFGEdge {
134 pub source: String,
136 pub target: String,
138 pub count: u64,
140 pub avg_duration_ms: f64,
142}
143
144impl DirectlyFollowsGraph {
145 pub fn new() -> Self {
147 Self {
148 activities: Vec::new(),
149 edges: Vec::new(),
150 start_activities: HashMap::new(),
151 end_activities: HashMap::new(),
152 activity_counts: HashMap::new(),
153 }
154 }
155
156 pub fn outgoing(&self, activity: &str) -> Vec<&DFGEdge> {
158 self.edges.iter().filter(|e| e.source == activity).collect()
159 }
160
161 pub fn incoming(&self, activity: &str) -> Vec<&DFGEdge> {
163 self.edges.iter().filter(|e| e.target == activity).collect()
164 }
165
166 pub fn edge(&self, source: &str, target: &str) -> Option<&DFGEdge> {
168 self.edges
169 .iter()
170 .find(|e| e.source == source && e.target == target)
171 }
172}
173
174impl Default for DirectlyFollowsGraph {
175 fn default() -> Self {
176 Self::new()
177 }
178}
179
180#[derive(Debug, Clone)]
182pub struct DFGResult {
183 pub dfg: DirectlyFollowsGraph,
185 pub trace_count: u64,
187 pub event_count: u64,
189 pub unique_pairs: u64,
191}
192
193#[derive(Debug, Clone)]
199pub struct Place {
200 pub id: String,
202 pub name: String,
204 pub tokens: u32,
206}
207
208#[derive(Debug, Clone)]
210pub struct Transition {
211 pub id: String,
213 pub label: Option<String>,
215 pub visible: bool,
217}
218
219#[derive(Debug, Clone)]
221pub struct Arc {
222 pub source: String,
224 pub target: String,
226 pub weight: u32,
228}
229
230#[derive(Debug, Clone)]
232pub struct PetriNet {
233 pub name: String,
235 pub places: Vec<Place>,
237 pub transitions: Vec<Transition>,
239 pub arcs: Vec<Arc>,
241 pub initial_marking: HashMap<String, u32>,
243 pub final_marking: HashMap<String, u32>,
245}
246
247impl PetriNet {
248 pub fn new(name: String) -> Self {
250 Self {
251 name,
252 places: Vec::new(),
253 transitions: Vec::new(),
254 arcs: Vec::new(),
255 initial_marking: HashMap::new(),
256 final_marking: HashMap::new(),
257 }
258 }
259
260 pub fn add_place(&mut self, id: String, name: String) {
262 self.places.push(Place {
263 id,
264 name,
265 tokens: 0,
266 });
267 }
268
269 pub fn add_transition(&mut self, id: String, label: Option<String>) {
271 self.transitions.push(Transition {
272 id,
273 label: label.clone(),
274 visible: label.is_some(),
275 });
276 }
277
278 pub fn add_arc(&mut self, source: String, target: String, weight: u32) {
280 self.arcs.push(Arc {
281 source,
282 target,
283 weight,
284 });
285 }
286
287 pub fn enabled_transitions(&self, marking: &HashMap<String, u32>) -> Vec<&Transition> {
289 self.transitions
290 .iter()
291 .filter(|t| {
292 self.arcs
294 .iter()
295 .filter(|a| a.target == t.id)
296 .all(|a| marking.get(&a.source).copied().unwrap_or(0) >= a.weight)
297 })
298 .collect()
299 }
300}
301
302#[derive(Debug, Clone)]
308pub struct ConformanceResult {
309 pub case_id: String,
311 pub is_conformant: bool,
313 pub fitness: f64,
315 pub precision: f64,
317 pub deviations: Vec<Deviation>,
319 pub alignment: Option<Vec<AlignmentStep>>,
321}
322
323#[derive(Debug, Clone)]
325pub struct Deviation {
326 pub event_index: usize,
328 pub activity: String,
330 pub deviation_type: DeviationType,
332 pub description: String,
334}
335
336#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
338pub enum DeviationType {
339 UnexpectedActivity,
341 MissingActivity,
343 WrongOrder,
345 UnexpectedRepetition,
347}
348
349#[derive(Debug, Clone)]
351pub struct AlignmentStep {
352 pub log_move: Option<String>,
354 pub model_move: Option<String>,
356 pub sync: bool,
358 pub cost: u32,
360}
361
362#[derive(Debug, Clone)]
364pub struct ConformanceStats {
365 pub trace_count: u64,
367 pub conformant_count: u64,
369 pub avg_fitness: f64,
371 pub avg_precision: f64,
373 pub deviation_counts: HashMap<DeviationType, u64>,
375}
376
377#[derive(Debug, Clone)]
383pub struct PartialOrderResult {
384 pub concurrent_pairs: Vec<(String, String)>,
386 pub sequential_pairs: Vec<(String, String)>,
388 pub exclusive_pairs: Vec<(String, String)>,
390 pub parallelism_score: f64,
392}
393
394#[derive(Debug, Clone)]
400pub struct OCPMObject {
401 pub id: String,
403 pub object_type: String,
405 pub attributes: HashMap<String, String>,
407}
408
409#[derive(Debug, Clone)]
411pub struct OCPMEvent {
412 pub id: u64,
414 pub activity: String,
416 pub timestamp: u64,
418 pub objects: Vec<String>,
420 pub attributes: HashMap<String, String>,
422}
423
424#[derive(Debug, Clone)]
426pub struct OCPMEventLog {
427 pub events: Vec<OCPMEvent>,
429 pub objects: HashMap<String, OCPMObject>,
431 pub object_types: HashSet<String>,
433}
434
435impl OCPMEventLog {
436 pub fn new() -> Self {
438 Self {
439 events: Vec::new(),
440 objects: HashMap::new(),
441 object_types: HashSet::new(),
442 }
443 }
444
445 pub fn add_object(&mut self, object: OCPMObject) {
447 self.object_types.insert(object.object_type.clone());
448 self.objects.insert(object.id.clone(), object);
449 }
450
451 pub fn add_event(&mut self, event: OCPMEvent) {
453 self.events.push(event);
454 }
455
456 pub fn events_for_object(&self, object_id: &str) -> Vec<&OCPMEvent> {
458 self.events
459 .iter()
460 .filter(|e| e.objects.contains(&object_id.to_string()))
461 .collect()
462 }
463}
464
465impl Default for OCPMEventLog {
466 fn default() -> Self {
467 Self::new()
468 }
469}
470
471#[derive(Debug, Clone)]
473pub struct OCPMPatternResult {
474 pub pattern_name: String,
476 pub matched_objects: Vec<String>,
478 pub matched_events: Vec<u64>,
480 pub score: f64,
482 pub description: String,
484}