Skip to main content

fdars_core/depth/
modal.rs

1//! Modal depth measures.
2
3use crate::dim::Dim;
4use crate::iter_maybe_parallel;
5use crate::matrix::FdMatrix;
6#[cfg(feature = "parallel")]
7use rayon::iter::ParallelIterator;
8
9/// Compute modal depth for 1D functional data.
10///
11/// Uses a Gaussian kernel to measure density around each curve.
12///
13/// # Arguments
14/// * `data_obj` - Data to compute depth for
15/// * `data_ori` - Reference data
16/// * `h` - Bandwidth parameter
17#[must_use = "expensive computation whose result should not be discarded"]
18pub fn modal_1d(data_obj: &FdMatrix, data_ori: &FdMatrix, h: f64) -> Vec<f64> {
19    let nobj = data_obj.nrows();
20    let nori = data_ori.nrows();
21    let n_points = data_obj.ncols();
22
23    if nobj == 0 || nori == 0 || n_points == 0 {
24        return Vec::new();
25    }
26
27    iter_maybe_parallel!(0..nobj)
28        .map(|i| {
29            let mut depth = 0.0;
30
31            for j in 0..nori {
32                let dist_sq = data_obj.row_l2_sq(i, data_ori, j);
33                let dist = (dist_sq / n_points as f64).sqrt();
34                let kernel_val = (-0.5 * (dist / h).powi(2)).exp();
35                depth += kernel_val;
36            }
37
38            depth / nori as f64
39        })
40        .collect()
41}
42
43/// Compute modal depth for 1D or 2D functional data via a unified [`Dim`] dispatch.
44///
45/// The 2D path never diverged from the 1D one, so both [`Dim`] arms forward to
46/// [`modal_1d`]. The `dim` argument makes caller intent explicit and provides a
47/// single future seam should a real 2D specialization ever be needed.
48///
49/// # Arguments
50/// * `data_obj` - Data to compute depth for
51/// * `data_ori` - Reference data
52/// * `h` - Bandwidth parameter
53/// * `dim` - Dimensionality selector ([`Dim::One`] or [`Dim::Two`])
54#[must_use = "expensive computation whose result should not be discarded"]
55pub fn modal(data_obj: &FdMatrix, data_ori: &FdMatrix, h: f64, dim: Dim) -> Vec<f64> {
56    match dim {
57        Dim::One | Dim::Two => modal_1d(data_obj, data_ori, h),
58    }
59}
60
61/// Compute modal depth for 2D functional data.
62#[deprecated(
63    since = "0.30.0",
64    note = "redundant with `modal(…, Dim::Two)`; body just forwards to `modal_1d`"
65)]
66#[must_use = "expensive computation whose result should not be discarded"]
67pub fn modal_2d(data_obj: &FdMatrix, data_ori: &FdMatrix, h: f64) -> Vec<f64> {
68    modal_1d(data_obj, data_ori, h)
69}