use crate::corpus::TraceCorpus;
use crate::traits::PatternEvaluator;
use fabula::engine::evaluate_pattern;
use fabula::pattern::Pattern;
use fabula_memory::{MemGraph, MemValue};
#[derive(Debug, Clone, Copy, Default)]
pub struct MatchQualityEvaluator;
impl PatternEvaluator for MatchQualityEvaluator {
fn evaluate(&self, pattern: &Pattern<String, String>, corpus: &TraceCorpus) -> f64 {
let graph = corpus_to_memgraph(corpus);
let mem_pattern = pattern.map_types(|l| l.clone(), |v| MemValue::Node(v.clone()));
let matches = evaluate_pattern(&graph, &mem_pattern);
let match_count = matches.len();
if match_count == 0 {
return 0.0;
}
let total_clauses: usize = pattern.stages.iter().map(|s| s.clauses.len()).sum();
let specificity = (pattern.stages.len() as f64) + (total_clauses as f64 * 0.5);
let corpus_size = corpus.len() as f64;
let match_ratio = match_count as f64 / corpus_size;
let match_quality = if match_ratio > 0.5 {
0.5 / match_ratio
} else {
(match_count as f64).ln().max(0.0)
};
match_quality * specificity
}
fn name(&self) -> &str {
"match_quality"
}
}
fn corpus_to_memgraph(corpus: &TraceCorpus) -> MemGraph {
let mut graph = MemGraph::new();
let (_, max_t) = corpus.time_range();
graph.set_time(max_t + 1);
for edge in corpus.edges() {
let value = MemValue::Node(edge.target.clone());
graph.add_edge(&edge.source, &edge.label, value, edge.interval.start);
}
graph
}