warden_vision/core/
classification.rs1#[derive(Debug, Clone, Copy, PartialEq)]
6pub struct ClassPrediction {
7 pub class_id: usize,
9 pub confidence: f32,
11}
12
13impl ClassPrediction {
14 pub fn new(class_id: usize, confidence: f32) -> Self {
16 Self {
17 class_id,
18 confidence,
19 }
20 }
21}
22
23#[derive(Debug, Clone, Default, PartialEq)]
26pub struct Classifications {
27 pub predictions: Vec<ClassPrediction>,
32}
33
34impl Classifications {
35 pub fn new(predictions: Vec<ClassPrediction>) -> Self {
37 Self { predictions }
38 }
39
40 pub fn from_scores(scores: &[f32]) -> Self {
44 Self::new(
45 scores
46 .iter()
47 .enumerate()
48 .map(|(class_id, &confidence)| ClassPrediction::new(class_id, confidence))
49 .collect(),
50 )
51 }
52
53 pub fn top_k(&self, k: usize) -> Vec<ClassPrediction> {
56 let mut sorted = self.predictions.clone();
57 sorted.sort_by(|a, b| b.confidence.total_cmp(&a.confidence));
58 sorted.truncate(k);
59 sorted
60 }
61
62 pub fn top1(&self) -> Option<ClassPrediction> {
64 self.predictions
65 .iter()
66 .copied()
67 .max_by(|a, b| a.confidence.total_cmp(&b.confidence))
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn from_scores_indexes_predictions_by_position() {
77 let classifications = Classifications::from_scores(&[0.1, 0.7, 0.2]);
78 assert_eq!(classifications.predictions.len(), 3);
79 assert_eq!(classifications.predictions[1], ClassPrediction::new(1, 0.7));
80 }
81
82 #[test]
83 fn top1_returns_the_highest_confidence_prediction() {
84 let classifications = Classifications::from_scores(&[0.1, 0.7, 0.2]);
85 assert_eq!(classifications.top1(), Some(ClassPrediction::new(1, 0.7)));
86 }
87
88 #[test]
89 fn top1_of_empty_is_none() {
90 assert_eq!(Classifications::default().top1(), None);
91 }
92
93 #[test]
94 fn top_k_sorts_descending_and_truncates() {
95 let classifications = Classifications::from_scores(&[0.1, 0.7, 0.5, 0.2]);
96 let top2 = classifications.top_k(2);
97 assert_eq!(
98 top2,
99 vec![ClassPrediction::new(1, 0.7), ClassPrediction::new(2, 0.5)]
100 );
101 }
102
103 #[test]
104 fn top_k_larger_than_predictions_returns_all() {
105 let classifications = Classifications::from_scores(&[0.1, 0.7]);
106 assert_eq!(classifications.top_k(10).len(), 2);
107 }
108}