use crate::track::ObservationMetric;
use crate::voting::Voting;
use itertools::Itertools;
pub struct TopNVoting {
topn: usize,
max_distance: f32,
min_votes: usize,
}
impl TopNVoting {
pub fn new(topn: usize, max_distance: f32, min_votes: usize) -> Self {
Self {
topn,
max_distance,
min_votes,
}
}
}
#[derive(Default, Debug, PartialEq, Eq)]
pub struct TopNVotingElt {
pub track_id: u64,
pub votes: usize,
}
impl TopNVotingElt {
pub fn new(track_id: u64, votes: usize) -> Self {
Self { track_id, votes }
}
}
impl Voting<TopNVotingElt, f32> for TopNVoting {
fn winners(&self, distances: &[ObservationMetric<f32>]) -> Vec<TopNVotingElt> {
let mut tracks: Vec<_> = distances
.iter()
.filter(
|ObservationMetric(_track, _f_attr_dist, feat_dist)| match feat_dist {
Some(e) => *e <= self.max_distance,
_ => false,
},
)
.map(|ObservationMetric(track, _f_attr_dist, _feat_dist)| track)
.collect();
tracks.sort_unstable();
let mut counts = tracks
.into_iter()
.counts()
.into_iter()
.filter(|(_, count)| *count >= self.min_votes)
.map(|(e, c)| TopNVotingElt {
track_id: *e,
votes: c,
})
.collect::<Vec<_>>();
counts.sort_by(|l, r| r.votes.partial_cmp(&l.votes).unwrap());
counts.truncate(self.topn);
counts
}
}
#[cfg(test)]
mod tests {
use crate::track::voting::topn::{TopNVoting, TopNVotingElt, Voting};
use crate::track::ObservationMetric;
#[test]
fn default_voting() {
let v = TopNVoting {
topn: 5,
max_distance: 0.32,
min_votes: 1,
};
let candidates = v.winners(&vec![ObservationMetric(1, Some(0.0), Some(0.2))]);
assert_eq!(candidates, vec![TopNVotingElt::new(1, 1)]);
let candidates = v.winners(&vec![
ObservationMetric(1, Some(0.0), Some(0.2)),
ObservationMetric(1, Some(0.0), Some(0.3)),
]);
assert_eq!(candidates, vec![TopNVotingElt::new(1, 2)]);
let candidates = v.winners(&vec![
ObservationMetric(1, Some(0.0), Some(0.2)),
ObservationMetric(1, Some(0.0), Some(0.4)),
]);
assert_eq!(candidates, vec![TopNVotingElt::new(1, 1)]);
let mut candidates = v.winners(&vec![
ObservationMetric(1, Some(0.0), Some(0.2)),
ObservationMetric(2, Some(0.0), Some(0.2)),
]);
candidates.sort_by(|l, r| l.track_id.partial_cmp(&r.track_id).unwrap());
assert_eq!(
candidates,
vec![TopNVotingElt::new(1, 1), TopNVotingElt::new(2, 1)]
);
let mut candidates = v.winners(&vec![
ObservationMetric(1, Some(0.0), Some(0.2)),
ObservationMetric(1, Some(0.0), Some(0.22)),
ObservationMetric(2, Some(0.0), Some(0.21)),
ObservationMetric(2, Some(0.0), Some(0.2)),
ObservationMetric(3, Some(0.0), Some(0.22)),
ObservationMetric(3, Some(0.0), Some(0.2)),
ObservationMetric(4, Some(0.0), Some(0.23)),
ObservationMetric(4, Some(0.0), Some(0.3)),
ObservationMetric(5, Some(0.0), Some(0.24)),
ObservationMetric(5, Some(0.0), Some(0.3)),
ObservationMetric(6, Some(0.0), Some(0.25)),
ObservationMetric(6, Some(0.0), Some(0.5)),
]);
candidates.sort_by(|l, r| l.track_id.partial_cmp(&r.track_id).unwrap());
assert_eq!(
candidates,
vec![
TopNVotingElt::new(1, 2),
TopNVotingElt::new(2, 2),
TopNVotingElt::new(3, 2),
TopNVotingElt::new(4, 2),
TopNVotingElt::new(5, 2)
]
);
}
}