sva-samples 0.5.0

Buffers, frames, the f64 machine, the collapse of a law onto a grid, and the measured observations over one
Documentation
// Concern: the sample spans a lane's own windows leave it nonzero over | Non-concern: reading one (reading.rs), pricing them (plan.rs) | IO: (&Lane, rate, Horizon) -> spans

use sva_formula::Lane;

use super::Horizon;

/// Where every atom is windowed, the lane is zero outside their union.
pub(super) fn nonzero(lane: &Lane, horizon: Horizon, rate: u32, len: usize) -> Vec<(usize, usize)> {
    windows(lane, horizon.start_secs, rate, len as f64).unwrap_or_else(|| vec![(0, len)])
}

pub(super) fn windows(
    lane: &Lane,
    start_secs: f64,
    rate: u32,
    cap: f64,
) -> Option<Vec<(usize, usize)>> {
    if !lane.is_finite_sum() || lane.atoms.iter().any(|a| a.ind.is_none()) {
        return None;
    }
    let edge =
        |secs: f64| (((secs - start_secs) * f64::from(rate)).ceil()).clamp(0.0, cap) as usize;
    let mut spans: Vec<(usize, usize)> = lane
        .atoms
        .iter()
        .filter_map(|a| {
            let window = a.ind?;
            let (from, to) = (edge(window.l.value()), edge(window.r.value()));
            (from < to).then_some((from, to))
        })
        .collect();
    spans.sort_unstable();
    let mut merged: Vec<(usize, usize)> = Vec::with_capacity(spans.len());
    for (from, to) in spans {
        match merged.last_mut() {
            Some(held) if from <= held.1 => held.1 = held.1.max(to),
            _ => merged.push((from, to)),
        }
    }
    Some(merged)
}