Skip to main content

ebi_objects/attribute_key/
attribute_key.rs

1use crate::{Attribute, DataType, Infoable};
2use ebi_arithmetic::anyhow::Result;
3use process_mining::core::event_data::{
4    case_centric::AttributeValue, object_centric::OCELAttributeValue,
5};
6use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator};
7use std::{borrow::Borrow, collections::HashMap};
8
9#[derive(Clone, Debug)]
10pub struct AttributeKey {
11    pub(crate) name2attribute: HashMap<String, Attribute>,
12    pub(crate) attribute2name: Vec<String>,
13    pub(crate) attribute2type: Vec<DataType>,
14}
15
16impl<'a> AttributeKey {
17    pub fn new() -> Self {
18        Self {
19            name2attribute: HashMap::new(),
20            attribute2name: vec![],
21            attribute2type: vec![],
22        }
23    }
24
25    pub fn attribute_to_label(&self, attribute: impl Borrow<Attribute>) -> Option<&String> {
26        self.attribute2name.get(attribute.borrow().id)
27    }
28
29    pub fn label_to_attribute(&self, label: &str) -> Option<Attribute> {
30        self.name2attribute.get(label).copied()
31    }
32
33    pub fn id_to_attribute(&self, attribute_id: usize) -> Attribute {
34        Attribute { id: attribute_id }
35    }
36
37    pub fn attribute_to_id(&self, attribute: impl Borrow<Attribute>) -> usize {
38        attribute.borrow().id
39    }
40
41    pub fn attribute_to_data_type(&self, attribute: impl Borrow<Attribute>) -> Option<&DataType> {
42        self.attribute2type.get(attribute.borrow().id)
43    }
44
45    pub fn set_label(&mut self, attribute: impl Borrow<Attribute>, label: &str) {
46        if let Some(old_label) = self.attribute2name.get(attribute.borrow().id) {
47            let old_label = old_label.to_string();
48            self.attribute2name[attribute.borrow().id] = label.to_string();
49            self.name2attribute.remove(&old_label);
50            self.name2attribute
51                .insert(label.to_string(), attribute.borrow().clone());
52        }
53    }
54
55    #[cfg(test)]
56    pub fn add_categorical_attribute(&mut self, label: &str) -> Attribute {
57        let next_index = self.name2attribute.len();
58        match self.name2attribute.get(label) {
59            Some(attribute) => *attribute,
60            None => {
61                let result = Attribute { id: next_index };
62                self.attribute2name.push(label.to_string());
63                self.name2attribute.insert(label.to_string(), result);
64                self.attribute2type.push(DataType::Categorical);
65                return result;
66            }
67        }
68    }
69
70    ///Must be called consecutively for the first row.
71    pub fn process_attribute_column(
72        &mut self,
73        attribute_id: usize,
74        attribute_value: &str,
75    ) -> Attribute {
76        if attribute_id == self.name2attribute.len() {
77            let id = self.attribute2name.len();
78            self.attribute2name.push(id.to_string());
79            self.name2attribute.insert(id.to_string(), Attribute { id });
80            self.attribute2type
81                .push(DataType::init(&AttributeValue::String(
82                    attribute_value.to_string(),
83                )));
84            self.id_to_attribute(id)
85        } else {
86            self.attribute2type[attribute_id]
87                .update(&AttributeValue::String(attribute_value.to_string()));
88            self.id_to_attribute(attribute_id)
89        }
90    }
91
92    pub fn process_attribute_value(
93        &mut self,
94        attribute_name: &str,
95        attribute_value: &AttributeValue,
96    ) -> Attribute {
97        let next_index = self.name2attribute.len();
98        match self.name2attribute.get(attribute_name) {
99            Some(index) => {
100                self.attribute2type[index.id].update(attribute_value);
101                return *index;
102            }
103            None => {
104                let result = Attribute { id: next_index };
105                self.attribute2name.push(attribute_name.to_string());
106                self.name2attribute
107                    .insert(attribute_name.to_string(), result);
108                self.attribute2type.push(DataType::init(&attribute_value));
109                return result;
110            }
111        }
112    }
113
114    pub fn ocel_attribute_value2attribute_value(ocel_value: OCELAttributeValue) -> AttributeValue {
115        match ocel_value {
116            OCELAttributeValue::Time(d) => AttributeValue::Date(d),
117            OCELAttributeValue::Integer(i) => AttributeValue::Int(i),
118            OCELAttributeValue::Float(f) => AttributeValue::Float(f),
119            OCELAttributeValue::Boolean(b) => AttributeValue::Boolean(b),
120            OCELAttributeValue::String(s) => AttributeValue::String(s),
121            OCELAttributeValue::Null => AttributeValue::None(),
122        }
123    }
124
125    pub fn len(&self) -> usize {
126        self.attribute2name.len()
127    }
128}
129
130impl Infoable for AttributeKey {
131    fn info(&self, f: &mut impl std::io::Write) -> Result<()> {
132        //make tuples
133        let mut tuples = self
134            .attribute2name
135            .iter()
136            .zip(self.attribute2type.iter())
137            .collect::<Vec<_>>();
138        tuples.sort_by(|a, b| a.0.cmp(b.0));
139
140        for (label, typee) in tuples {
141            writeln!(f, "\t{}\t{}", label, typee)?;
142        }
143
144        Ok(write!(f, "")?)
145    }
146}
147
148impl<'a> IntoParallelIterator for &'a AttributeKey {
149    type Iter = rayon::iter::Zip<rayon::vec::IntoIter<Attribute>, rayon::slice::Iter<'a, DataType>>;
150    type Item = (Attribute, &'a DataType);
151
152    fn into_par_iter(self) -> Self::Iter {
153        let x = (0..self.len())
154            .map(|id| self.id_to_attribute(id))
155            .collect::<Vec<_>>();
156
157        x.into_par_iter().zip(self.attribute2type.par_iter())
158    }
159}