diff --git a/src/eval.rs b/src/eval.rs index 4b0fd9d..3039f5d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1 +1,39 @@ -// implemented in a later task +use rand::rngs::StdRng; +use rand::{Rng, SeedableRng}; + +/// Inject realistic transcription errors deterministically (seeded): +/// char drop, adjacent swap, umlaut flattening, digit transposition. +pub fn inject_errors(text: &str, rate: f64, seed: u64) -> String { + let mut rng = StdRng::seed_from_u64(seed); + let mut chars: Vec = text.chars().collect(); + let n = chars.len(); + let mut i = 0; + while i < chars.len() { + if rng.gen::() < rate { + match rng.gen_range(0..4) { + 0 => { chars.remove(i); continue; } // drop + 1 => { if i + 1 < chars.len() { chars.swap(i, i + 1); } } // swap + 2 => { // flatten umlaut + chars[i] = match chars[i] { + 'ä' => 'a', 'ö' => 'o', 'ü' => 'u', 'ß' => 's', + other => other, + }; + } + _ => { // digit transpose + if chars[i].is_ascii_digit() && i + 1 < chars.len() + && chars[i + 1].is_ascii_digit() { + chars.swap(i, i + 1); + } + } + } + } + i += 1; + } + let _ = n; + chars.into_iter().collect() +} + +/// 1.0 if `expected` appears in the first k predictions, else 0.0. +pub fn recall_at_k(predicted: &[String], expected: &str, k: usize) -> f64 { + if predicted.iter().take(k).any(|p| p == expected) { 1.0 } else { 0.0 } +} diff --git a/tests/eval_tests.rs b/tests/eval_tests.rs new file mode 100644 index 0000000..69e289a --- /dev/null +++ b/tests/eval_tests.rs @@ -0,0 +1,17 @@ +use alpha_id::eval::{inject_errors, recall_at_k}; + +#[test] +fn injection_is_deterministic_for_seed() { + let a = inject_errors("Diabetes mellitus Typ 2", 0.3, 42); + let b = inject_errors("Diabetes mellitus Typ 2", 0.3, 42); + assert_eq!(a, b); + assert_ne!(a, "Diabetes mellitus Typ 2"); // some corruption at rate 0.3 +} + +#[test] +fn recall_counts_hit_within_k() { + let predicted = vec!["E11.9".to_string(), "I10.90".to_string(), "J45.0".to_string()]; + assert_eq!(recall_at_k(&predicted, "I10.90", 5), 1.0); + assert_eq!(recall_at_k(&predicted, "I10.90", 1), 0.0); + assert_eq!(recall_at_k(&predicted, "Z99.9", 5), 0.0); +}