process_mining/event_log/ocel/linked_ocel/
id_linked_ocel.rs

1use std::collections::HashMap;
2
3use crate::{
4    ocel::ocel_struct::{OCELEvent, OCELObject},
5    OCEL,
6};
7
8use super::LinkedOCELAccess;
9
10impl<'a> LinkedOCELAccess<'a, EventID<'a>, ObjectID<'a>, OCELEvent, OCELObject>
11    for IDLinkedOCEL<'a>
12{
13    fn get_evs_of_type(&'a self, ev_type: &'_ str) -> impl Iterator<Item = &'a OCELEvent> {
14        self.events_per_type
15            .get(ev_type)
16            .into_iter()
17            .flatten()
18            .copied()
19    }
20
21    fn get_obs_of_type(&'a self, ob_type: &'_ str) -> impl Iterator<Item = &'a OCELObject> {
22        self.objects_per_type
23            .get(ob_type)
24            .into_iter()
25            .flatten()
26            .copied()
27    }
28
29    fn get_ev(&'a self, ev_id: &EventID<'a>) -> &'a OCELEvent {
30        self.events.get(ev_id).unwrap()
31    }
32
33    fn get_ob(&'a self, ob_id: &ObjectID<'a>) -> &'a OCELObject {
34        self.objects.get(ob_id).unwrap()
35    }
36
37    fn get_e2o(&'a self, index: &EventID<'a>) -> impl Iterator<Item = (&'a str, &'a OCELObject)> {
38        self.e2o_rel.get(index).into_iter().flatten().copied()
39    }
40
41    fn get_e2o_rev(
42        &'a self,
43        index: &ObjectID<'a>,
44    ) -> impl Iterator<Item = (&'a str, &'a OCELEvent)> {
45        self.e2o_rel_rev.get(index).into_iter().flatten().copied()
46    }
47
48    fn get_o2o(&'a self, index: &ObjectID<'a>) -> impl Iterator<Item = (&'a str, &'a OCELObject)> {
49        self.o2o_rel.get(index).into_iter().flatten().copied()
50    }
51
52    fn get_o2o_rev(
53        &'a self,
54        index: &ObjectID<'a>,
55    ) -> impl Iterator<Item = (&'a str, &'a OCELObject)> {
56        self.o2o_rel_rev.get(index).into_iter().flatten().copied()
57    }
58
59    fn get_ev_types(&'a self) -> impl Iterator<Item = &'a str> {
60        self.events_per_type.keys().copied()
61    }
62
63    fn get_ob_types(&'a self) -> impl Iterator<Item = &'a str> {
64        self.objects_per_type.keys().copied()
65    }
66
67    fn get_all_evs(&'a self) -> impl Iterator<Item = &'a OCELEvent> {
68        self.ocel.events.iter()
69    }
70
71    fn get_all_obs(&'a self) -> impl Iterator<Item = &'a OCELObject> {
72        self.ocel.objects.iter()
73    }
74
75    fn get_all_evs_ref(&'a self) -> impl Iterator<Item = &'a EventID<'a>> {
76        self.events.iter().map(|e| e.0)
77    }
78
79    fn get_all_obs_ref(&'a self) -> impl Iterator<Item = &'a ObjectID<'a>> {
80        self.objects.iter().map(|o| o.0)
81    }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Hash)]
85/// Object identifier in an [`OCEL`]
86pub struct ObjectID<'a>(&'a str);
87
88impl<'a> From<&'a OCELObject> for ObjectID<'a> {
89    fn from(value: &'a OCELObject) -> Self {
90        Self(value.id.as_str())
91    }
92}
93
94#[derive(Debug, Clone, PartialEq, Eq, Hash)]
95/// Event identifier in an [`OCEL`]
96pub struct EventID<'a>(&'a str);
97
98impl<'a> From<&'a OCELEvent> for EventID<'a> {
99    fn from(value: &'a OCELEvent) -> Self {
100        Self(value.id.as_str())
101    }
102}
103
104#[derive(Debug, Clone)]
105/// A [`OCEL`] linked using event and object IDs (i.e., wrappers around [`String`]s)
106pub struct IDLinkedOCEL<'a> {
107    /// The reference to the inner [`OCEL`], which contains the actual event and object values
108    pub ocel: &'a OCEL,
109    events: HashMap<EventID<'a>, &'a OCELEvent>,
110    objects: HashMap<ObjectID<'a>, &'a OCELObject>,
111    events_per_type: HashMap<&'a str, Vec<&'a OCELEvent>>,
112    objects_per_type: HashMap<&'a str, Vec<&'a OCELObject>>,
113    e2o_rel: HashMap<EventID<'a>, Vec<(&'a str, &'a OCELObject)>>,
114    o2o_rel: HashMap<ObjectID<'a>, Vec<(&'a str, &'a OCELObject)>>,
115    e2o_rel_rev: HashMap<ObjectID<'a>, Vec<(&'a str, &'a OCELEvent)>>,
116    o2o_rel_rev: HashMap<ObjectID<'a>, Vec<(&'a str, &'a OCELObject)>>,
117}
118
119impl<'a> IDLinkedOCEL<'a> {
120    /// Create a ID-linked OCEL from a [`OCEL`] reference
121    pub fn from_ocel(ocel: &'a OCEL) -> Self {
122        Self::from(ocel)
123    }
124}
125
126impl<'a> From<&'a OCEL> for IDLinkedOCEL<'a> {
127    fn from(ocel: &'a OCEL) -> Self {
128        let events: HashMap<_, _> = ocel.events.iter().map(|e| (EventID(&e.id), e)).collect();
129        let objects: HashMap<_, _> = ocel.objects.iter().map(|o| (ObjectID(&o.id), o)).collect();
130        let mut e2o_rel_rev: HashMap<ObjectID<'a>, Vec<(&str, &OCELEvent)>> = HashMap::new();
131        let e2o_rel = events
132            .values()
133            .map(|e| {
134                let e_id: EventID<'_> = EventID(&e.id);
135                (
136                    e_id,
137                    e.relationships
138                        .iter()
139                        .flat_map(|rel| {
140                            let obj_id: ObjectID<'_> = ObjectID(&rel.object_id);
141                            let qualifier = rel.qualifier.as_str();
142                            e2o_rel_rev.entry(obj_id).or_default().push((qualifier, e));
143                            let ob = objects.get(&(ObjectID(&rel.object_id)))?;
144                            Some((qualifier, *ob))
145                        })
146                        .collect(),
147                )
148            })
149            .collect();
150
151        let mut o2o_rel_rev: HashMap<ObjectID<'_>, Vec<(&'a str, &OCELObject)>> = HashMap::new();
152
153        let o2o_rel = objects
154            .values()
155            .map(|o| {
156                (
157                    ObjectID(&o.id),
158                    o.relationships
159                        .iter()
160                        .flat_map(|rel| {
161                            let qualifier = rel.qualifier.as_str();
162                            let obj2_id: ObjectID<'_> = ObjectID(&rel.object_id);
163                            o2o_rel_rev.entry(obj2_id).or_default().push((qualifier, o));
164                            let ob = objects.get(&ObjectID(&rel.object_id))?;
165                            Some((qualifier, *ob))
166                        })
167                        .collect(),
168                )
169            })
170            .collect();
171        let events_per_type = ocel
172            .event_types
173            .iter()
174            .map(|et| {
175                (
176                    et.name.as_str(),
177                    ocel.events
178                        .iter()
179                        .filter(|e| e.event_type == et.name)
180                        .collect(),
181                )
182            })
183            .collect();
184
185        let objects_per_type = ocel
186            .object_types
187            .iter()
188            .map(|et| {
189                (
190                    et.name.as_str(),
191                    ocel.objects
192                        .iter()
193                        .filter(|e| e.object_type == et.name)
194                        .collect(),
195                )
196            })
197            .collect();
198        Self {
199            ocel,
200            events,
201            objects,
202            events_per_type,
203            objects_per_type,
204            e2o_rel,
205            o2o_rel,
206            e2o_rel_rev,
207            o2o_rel_rev,
208        }
209    }
210}
211
212/// A [`IDLinkedOCEL`] that also owns the underlying [`OCEL`]
213///
214/// This is a convenience helper for when the liftetime of the inner [`OCEL`] cannot be guaranteed outside.
215///
216/// If the caller can manage owning the (borrowed) [`OCEL`], a standard [`IDLinkedOCEL`] can be used instead.
217#[derive(Debug, Clone)]
218pub struct OwnedIDLinkedOCEL<'a> {
219    ocel: OCEL,
220    /// The inner id-linked OCEL
221    pub linked_ocel: IDLinkedOCEL<'a>,
222}
223
224impl<'a> OwnedIDLinkedOCEL<'a> {
225    /// Create an [`OwnedIDLinkedOCEL`] from an owned [`OCEL`]
226    pub fn from_ocel(ocel: OCEL) -> Self {
227        Self::from(ocel)
228    }
229    /// Get the inner owned [`OCEL`], consuming the [`OwnedIDLinkedOCEL`]
230    pub fn into_inner(self) -> OCEL {
231        self.ocel
232    }
233    /// Get a reference to the inner [`OCEL`]
234    pub fn ocel_ref(&'a self) -> &'a OCEL {
235        &self.ocel
236    }
237}
238
239impl From<OCEL> for OwnedIDLinkedOCEL<'_> {
240    fn from(ocel: OCEL) -> Self {
241        let ocel_ref = unsafe { &*(&ocel as *const OCEL) };
242        OwnedIDLinkedOCEL {
243            ocel,
244            linked_ocel: (ocel_ref).into(),
245        }
246    }
247}
248
249impl<'a> LinkedOCELAccess<'a, EventID<'a>, ObjectID<'a>, OCELEvent, OCELObject>
250    for OwnedIDLinkedOCEL<'a>
251{
252    fn get_evs_of_type(&'a self, ev_type: &'_ str) -> impl Iterator<Item = &'a OCELEvent> {
253        self.linked_ocel.get_evs_of_type(ev_type)
254    }
255
256    fn get_obs_of_type(&'a self, ob_type: &'_ str) -> impl Iterator<Item = &'a OCELObject> {
257        self.linked_ocel.get_obs_of_type(ob_type)
258    }
259
260    fn get_ev(&'a self, index: &EventID<'a>) -> &'a OCELEvent {
261        self.linked_ocel.get_ev(index)
262    }
263
264    fn get_ob(&'a self, index: &ObjectID<'a>) -> &'a OCELObject {
265        self.linked_ocel.get_ob(index)
266    }
267
268    fn get_e2o(&'a self, index: &EventID<'a>) -> impl Iterator<Item = (&'a str, &'a OCELObject)> {
269        self.linked_ocel.get_e2o(index)
270    }
271
272    fn get_e2o_rev(
273        &'a self,
274        index: &ObjectID<'a>,
275    ) -> impl Iterator<Item = (&'a str, &'a OCELEvent)> {
276        self.linked_ocel.get_e2o_rev(index)
277    }
278
279    fn get_o2o(&'a self, index: &ObjectID<'a>) -> impl Iterator<Item = (&'a str, &'a OCELObject)> {
280        self.linked_ocel.get_o2o(index)
281    }
282
283    fn get_o2o_rev(
284        &'a self,
285        index: &ObjectID<'a>,
286    ) -> impl Iterator<Item = (&'a str, &'a OCELObject)> {
287        self.linked_ocel.get_o2o_rev(index)
288    }
289
290    fn get_ev_types(&'a self) -> impl Iterator<Item = &'a str> {
291        self.linked_ocel.get_ev_types()
292    }
293
294    fn get_ob_types(&'a self) -> impl Iterator<Item = &'a str> {
295        self.linked_ocel.get_ob_types()
296    }
297
298    fn get_all_evs(&'a self) -> impl Iterator<Item = &'a OCELEvent> {
299        self.linked_ocel.get_all_evs()
300    }
301
302    fn get_all_obs(&'a self) -> impl Iterator<Item = &'a OCELObject> {
303        self.linked_ocel.get_all_obs()
304    }
305
306    fn get_all_evs_ref(&'a self) -> impl Iterator<Item = &'a EventID<'a>> {
307        self.linked_ocel.get_all_evs_ref()
308    }
309
310    fn get_all_obs_ref(&'a self) -> impl Iterator<Item = &'a ObjectID<'a>> {
311        self.linked_ocel.get_all_obs_ref()
312    }
313}