use super::update::DEAD_DENOM;
use std::cmp::Ordering;
use std::collections::BinaryHeap;
pub(super) struct ResidRow {
pub(super) norm2: f64,
pub(super) global_index: u64,
pub(super) residual: Vec<f32>,
}
impl PartialEq for ResidRow {
fn eq(&self, other: &Self) -> bool {
self.norm2 == other.norm2 && self.global_index == other.global_index
}
}
impl Eq for ResidRow {}
impl Ord for ResidRow {
fn cmp(&self, other: &Self) -> Ordering {
match other.norm2.total_cmp(&self.norm2) {
Ordering::Equal => self.global_index.cmp(&other.global_index),
ord => ord,
}
}
}
impl PartialOrd for ResidRow {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
pub(super) struct ResidualReservoir {
cap: usize,
heap: BinaryHeap<ResidRow>,
}
impl ResidualReservoir {
pub(super) fn new(cap: usize) -> Self {
Self {
cap: cap.max(1),
heap: BinaryHeap::new(),
}
}
pub(super) fn offer(&mut self, norm2: f64, global_index: u64, residual: Vec<f32>) {
if norm2 <= DEAD_DENOM {
return;
}
let row = ResidRow {
norm2,
global_index,
residual,
};
if self.heap.len() < self.cap {
self.heap.push(row);
return;
}
if let Some(worst_kept) = self.heap.peek() {
if row.cmp(worst_kept) == Ordering::Less {
self.heap.pop();
self.heap.push(row);
}
}
}
pub(super) fn clear(&mut self) {
self.heap.clear();
}
pub(super) fn ranked(&self) -> Vec<&ResidRow> {
let mut rows: Vec<&ResidRow> = self.heap.iter().collect();
rows.sort_by(|a, b| {
b.norm2
.total_cmp(&a.norm2)
.then_with(|| a.global_index.cmp(&b.global_index))
});
rows
}
}