Skip to main content

pmcore/estimation/nonparametric/
weights.rs

1use faer::Col;
2use serde::{Deserialize, Serialize};
3use std::ops::{Index, IndexMut};
4
5/// The weight (probabilities) for each support point in the model.
6///
7/// This struct is used to hold the weights for each support point in the model.
8/// It is a thin wrapper around `faer::Col<f64>` to provide additional functionality and context
9#[derive(Debug, Clone)]
10pub struct Weights {
11    weights: Col<f64>,
12}
13
14impl Default for Weights {
15    fn default() -> Self {
16        Self {
17            weights: Col::from_fn(0, |_| 0.0),
18        }
19    }
20}
21
22impl Weights {
23    pub fn new(weights: Col<f64>) -> Self {
24        Self { weights }
25    }
26
27    pub fn from_vec(weights: Vec<f64>) -> Self {
28        Self {
29            weights: Col::from_fn(weights.len(), |i| weights[i]),
30        }
31    }
32
33    pub fn uniform(n: usize) -> Self {
34        if n == 0 {
35            return Self::default();
36        }
37        let uniform_weight = 1.0 / n as f64;
38        Self {
39            weights: Col::from_fn(n, |_| uniform_weight),
40        }
41    }
42
43    pub fn weights(&self) -> &Col<f64> {
44        &self.weights
45    }
46
47    pub fn weights_mut(&mut self) -> &mut Col<f64> {
48        &mut self.weights
49    }
50
51    pub fn len(&self) -> usize {
52        self.weights.nrows()
53    }
54
55    pub fn is_empty(&self) -> bool {
56        self.len() == 0
57    }
58
59    pub fn to_vec(&self) -> Vec<f64> {
60        self.weights.iter().cloned().collect()
61    }
62
63    pub fn iter(&self) -> impl Iterator<Item = f64> + '_ {
64        self.weights.iter().cloned()
65    }
66
67    /// Normalizes the weights so that they sum to 1.
68    ///
69    /// If the sum is zero, it does nothing to avoid division by zero.
70    pub fn normalize(&mut self) {
71        let sum: f64 = self.weights.iter().sum();
72        if sum != 0.0 {
73            for weight in self.weights.iter_mut() {
74                *weight /= sum;
75            }
76        }
77    }
78}
79
80impl Serialize for Weights {
81    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
82    where
83        S: serde::Serializer,
84    {
85        self.to_vec().serialize(serializer)
86    }
87}
88
89impl<'de> Deserialize<'de> for Weights {
90    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
91    where
92        D: serde::Deserializer<'de>,
93    {
94        let weights_vec = Vec::<f64>::deserialize(deserializer)?;
95        Ok(Self::from_vec(weights_vec))
96    }
97}
98
99impl From<Vec<f64>> for Weights {
100    fn from(weights: Vec<f64>) -> Self {
101        Self::from_vec(weights)
102    }
103}
104
105impl From<Col<f64>> for Weights {
106    fn from(weights: Col<f64>) -> Self {
107        Self { weights }
108    }
109}
110
111impl Index<usize> for Weights {
112    type Output = f64;
113
114    fn index(&self, index: usize) -> &Self::Output {
115        &self.weights[index]
116    }
117}
118
119impl IndexMut<usize> for Weights {
120    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
121        &mut self.weights[index]
122    }
123}