use crate::{
ebi_framework::{ebi_input::EbiInput, ebi_trait::FromEbiTraitObject},
ebi_traits::ebi_trait_event_log::EbiTraitEventLog,
};
use ebi_objects::{
Activity, EventLog, EventLogTraceAttributes, EventLogXes,
anyhow::{Result, anyhow},
ebi_derive::EbiInputEnum,
};
pub trait Filter {
fn remove_traces_length(&mut self, operator: Operator, value: usize);
fn remove_traces_empty(&mut self);
fn remove_traces_event_activity(&mut self, event_selector: EventSelector, activity: Activity);
}
macro_rules! filter {
($t:ident) => {
impl Filter for $t {
fn remove_traces_length(&mut self, operator: Operator, value: usize) {
self.retain_traces(Box::new(move |trace| !operator.apply(trace.len(), value)));
}
fn remove_traces_empty(&mut self) {
self.retain_traces(Box::new(|trace| trace.len() != 0));
}
fn remove_traces_event_activity(
&mut self,
event_selector: EventSelector,
activity: Activity,
) {
self.retain_traces(Box::new(move |trace| {
!event_selector.apply(trace, |act| act == &activity)
}));
}
}
};
}
filter!(EventLog);
filter!(EventLogTraceAttributes);
filter!(EventLogXes);
#[derive(EbiInputEnum)]
pub enum EventSelector {
Any,
All,
None,
Start,
End,
}
impl EventSelector {
pub fn apply<F>(&self, trace: &Vec<Activity>, f: F) -> bool
where
F: Fn(&Activity) -> bool,
{
match self {
EventSelector::Any => trace.iter().any(f),
EventSelector::All => trace.iter().all(f),
EventSelector::None => !trace.iter().any(f),
EventSelector::Start => match trace.iter().next() {
Some(act) => (f)(act),
None => false,
},
EventSelector::End => match trace.iter().last() {
Some(act) => (f)(act),
None => false,
},
}
}
}
#[derive(EbiInputEnum)]
pub enum Operator {
#[strum(serialize = "<")]
Smaller,
#[strum(serialize = "<=")]
SmallerEqual,
#[strum(serialize = ">")]
Larger,
#[strum(serialize = ">=")]
LargerEqual,
#[strum(serialize = "=")]
Equal,
#[strum(serialize = "<>")]
UnEqual,
}
impl Operator {
pub fn apply<T>(&self, a: T, b: T) -> bool
where
T: PartialOrd,
{
match self {
Operator::Smaller => a < b,
Operator::SmallerEqual => a <= b,
Operator::Larger => a > b,
Operator::LargerEqual => a >= b,
Operator::Equal => a == b,
Operator::UnEqual => a != b,
}
}
}
#[cfg(test)]
mod tests {
use std::fs;
use ebi_objects::{EventLog, EventLogTraceAttributes, HasActivityKey, NumberOfTraces};
use crate::techniques::filter::{EventSelector, Filter, Operator};
#[test]
fn filter_traces_length() {
let fin = fs::read_to_string("testfiles/a-b.xes").unwrap();
let mut log = Box::new(fin.parse::<EventLogTraceAttributes>().unwrap());
log.remove_traces_length(Operator::Larger, 10);
assert_eq!(log.number_of_traces(), 2);
log.remove_traces_length(Operator::SmallerEqual, 2);
assert_eq!(log.number_of_traces(), 0);
}
#[test]
fn filter_traces_empty() {
let fin = fs::read_to_string("testfiles/a-b.xes").unwrap();
let mut log = Box::new(fin.parse::<EventLog>().unwrap());
log.remove_traces_empty();
assert_eq!(log.number_of_traces(), 2);
}
#[test]
fn filter_traces_event_activity() {
let fin = fs::read_to_string("testfiles/a-b.xes").unwrap();
let mut log = Box::new(fin.parse::<EventLog>().unwrap());
let a = log.activity_key_mut().process_activity("a");
log.remove_traces_event_activity(EventSelector::All, a);
assert_eq!(log.number_of_traces(), 1);
let mut log = Box::new(fin.parse::<EventLog>().unwrap());
let a = log.activity_key_mut().process_activity("a");
log.remove_traces_event_activity(EventSelector::Any, a);
assert_eq!(log.number_of_traces(), 1);
let mut log = Box::new(fin.parse::<EventLog>().unwrap());
let a = log.activity_key_mut().process_activity("a");
log.remove_traces_event_activity(EventSelector::End, a);
assert_eq!(log.number_of_traces(), 1);
let mut log = Box::new(fin.parse::<EventLog>().unwrap());
let a = log.activity_key_mut().process_activity("a");
log.remove_traces_event_activity(EventSelector::Start, a);
assert_eq!(log.number_of_traces(), 1);
let mut log = Box::new(fin.parse::<EventLog>().unwrap());
let a = log.activity_key_mut().process_activity("a");
log.remove_traces_event_activity(EventSelector::None, a);
assert_eq!(log.number_of_traces(), 1);
}
}