use crate::observations::{triplets_iod::downsample_uniform_with_edges_indices, Observations};
pub struct TripletIndexGenerator {
reduced_to_original_index: Vec<usize>,
reduced_epochs_tt_mjd: Vec<f64>,
first_reduced_idx: usize,
middle_reduced_idx: usize,
last_reduced_idx: usize,
last_lower_bound_reduced_idx: usize,
last_upper_bound_reduced_idx: usize,
reduced_len: usize,
dt_min: f64,
dt_max: f64,
yielded_triplets_count: usize,
max_triplets_to_yield: usize,
}
impl TripletIndexGenerator {
pub fn from_observations(
observations: &mut Observations,
dt_min: f64,
dt_max: f64,
max_obs_for_triplets: usize,
max_triplets_to_yield: usize,
) -> Self {
observations.sort_by(|a, b| a.time.partial_cmp(&b.time).unwrap());
let reduced_to_original_index =
downsample_uniform_with_edges_indices(observations.len(), max_obs_for_triplets);
let reduced_epochs_tt_mjd: Vec<f64> = reduced_to_original_index
.iter()
.map(|&orig| observations[orig].time)
.collect();
let reduced_len = reduced_epochs_tt_mjd.len();
let mut gen = Self {
reduced_to_original_index,
reduced_epochs_tt_mjd,
first_reduced_idx: 0,
middle_reduced_idx: 1,
last_reduced_idx: 2,
last_lower_bound_reduced_idx: 2,
last_upper_bound_reduced_idx: 1, reduced_len,
dt_min,
dt_max,
yielded_triplets_count: 0,
max_triplets_to_yield,
};
if gen.reduced_len >= 3 {
gen.init_last_window_for_first();
}
gen
}
pub fn selected_original_indices(&self) -> &[usize] {
&self.reduced_to_original_index
}
pub fn reduced_times(&self) -> &[f64] {
&self.reduced_epochs_tt_mjd
}
fn init_last_window_for_first(&mut self) {
let first = self.first_reduced_idx;
let mut lower = first + 2;
while lower < self.reduced_len
&& (self.reduced_epochs_tt_mjd[lower] - self.reduced_epochs_tt_mjd[first]) < self.dt_min
{
lower += 1;
}
let mut upper = lower.saturating_sub(1).max(first + 1);
while (upper + 1) < self.reduced_len
&& (self.reduced_epochs_tt_mjd[upper + 1] - self.reduced_epochs_tt_mjd[first])
<= self.dt_max
{
upper += 1;
}
self.last_lower_bound_reduced_idx = lower;
self.last_upper_bound_reduced_idx = upper;
self.middle_reduced_idx = first + 1;
self.last_reduced_idx = self
.last_lower_bound_reduced_idx
.max(self.middle_reduced_idx + 1);
}
fn advance_first_anchor(&mut self) -> bool {
self.first_reduced_idx += 1;
if self.first_reduced_idx + 2 >= self.reduced_len {
return false;
}
self.init_last_window_for_first();
true
}
fn last_window_is_empty(&self) -> bool {
self.last_lower_bound_reduced_idx >= self.reduced_len
|| self.last_lower_bound_reduced_idx <= self.first_reduced_idx + 1
|| self.last_upper_bound_reduced_idx <= self.first_reduced_idx + 1
|| self.last_lower_bound_reduced_idx > self.last_upper_bound_reduced_idx
}
}
impl Iterator for TripletIndexGenerator {
type Item = (usize, usize, usize);
fn next(&mut self) -> Option<Self::Item> {
if self.yielded_triplets_count >= self.max_triplets_to_yield {
return None;
}
while self.first_reduced_idx + 2 < self.reduced_len {
if self.last_window_is_empty() {
if !self.advance_first_anchor() {
return None;
}
continue;
}
if self.middle_reduced_idx >= self.last_upper_bound_reduced_idx {
if !self.advance_first_anchor() {
return None;
}
continue;
}
if self.last_reduced_idx < self.last_lower_bound_reduced_idx
|| self.last_reduced_idx <= self.middle_reduced_idx
{
self.last_reduced_idx = self
.last_lower_bound_reduced_idx
.max(self.middle_reduced_idx + 1);
}
if self.last_reduced_idx > self.last_upper_bound_reduced_idx {
self.middle_reduced_idx += 1;
self.last_reduced_idx = self
.last_lower_bound_reduced_idx
.max(self.middle_reduced_idx + 1);
continue;
}
let i = self.first_reduced_idx;
let j = self.middle_reduced_idx;
let k = self.last_reduced_idx;
self.last_reduced_idx += 1;
self.yielded_triplets_count += 1;
return Some((i, j, k));
}
None
}
}