rustyml 0.17.0

Machine learning models, neural networks, metrics, and data utilities in Rust
Documentation
//! Index-mapping helpers that pick parallel or sequential execution based on a size threshold
//!
//! Provides [`map_collect`], the shared "parallelize only for large inputs" dispatch used
//! across the machine-learning models

use rayon::prelude::{IntoParallelIterator, ParallelIterator};

/// Maps `f` over `0..n`, choosing parallel or sequential execution by the caller's `parallel`
/// decision
///
/// Callers select the execution mode from the estimated work and the relevant parallel threshold.
/// Both execution modes preserve the input index order.
///
/// # Parameters
///
/// - `n` - Number of items to process (the iterator runs over `0..n`)
/// - `parallel` - Whether to fan the map out across rayon
/// - `f` - Mapping applied to each index
///
/// # Returns
///
/// - `Vec<R>` - Collected results in index order
#[inline]
pub(super) fn map_collect<R, F>(n: usize, parallel: bool, f: F) -> Vec<R>
where
    R: Send,
    F: Fn(usize) -> R + Sync + Send,
{
    if parallel {
        (0..n).into_par_iter().map(f).collect()
    } else {
        (0..n).map(f).collect()
    }
}

/// Tests for the module helpers and model behavior.
#[cfg(test)]
mod tests {
    use super::*;

    /// `map_collect` returns identical index-ordered output on both the sequential and
    /// parallel branches
    #[test]
    fn map_collect_seq_and_par_match_index_order() {
        let seq: Vec<usize> = map_collect(3, false, |i| i * i);
        assert_eq!(
            seq,
            vec![0, 1, 4],
            "sequential branch must be index-ordered"
        );

        let par: Vec<usize> = map_collect(8, true, |i| i * i);
        assert_eq!(
            par,
            vec![0, 1, 4, 9, 16, 25, 36, 49],
            "parallel branch must preserve index order"
        );

        // Both branches must agree on the shared prefix
        assert_eq!(
            &par[..3],
            &seq[..],
            "seq and par must agree on shared indices"
        );
    }

    /// `map_collect` on an empty range returns an empty Vec
    #[test]
    fn map_collect_empty() {
        let out: Vec<usize> = map_collect(0, false, |i| i * 2);
        assert!(out.is_empty(), "empty range must produce empty output");
    }
}