winsfs_core/em/
likelihood.rs

1//! Types describing likelihood of the data given an SFS.
2//!
3//! The types here exist largely as newtype-wrappers around `f64`.
4//! Getting likelihoods and log-likelihoods mixed up is an easy error to make; typing these
5//! helps avoid such bugs, and make method signatures clearer.
6
7use std::{
8    iter::Sum,
9    ops::{Add, AddAssign},
10};
11
12use super::to_f64;
13
14/// The likelihood of the data given an SFS.
15#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
16pub struct Likelihood(f64);
17
18impl Likelihood {
19    /// Returns the log-likelihood.
20    pub fn ln(self) -> LogLikelihood {
21        LogLikelihood(self.0.ln())
22    }
23}
24
25impl From<f64> for Likelihood {
26    #[inline]
27    fn from(v: f64) -> Self {
28        Self(v)
29    }
30}
31
32impl From<Likelihood> for f64 {
33    #[inline]
34    fn from(v: Likelihood) -> Self {
35        v.0
36    }
37}
38
39/// The log-likelihood of the data given an SFS.
40///
41/// This is always the natural logarithm.
42#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
43pub struct LogLikelihood(f64);
44
45impl From<f64> for LogLikelihood {
46    #[inline]
47    fn from(v: f64) -> Self {
48        Self(v)
49    }
50}
51
52impl From<LogLikelihood> for f64 {
53    #[inline]
54    fn from(v: LogLikelihood) -> Self {
55        v.0
56    }
57}
58
59impl Sum for LogLikelihood {
60    fn sum<I>(iter: I) -> Self
61    where
62        I: Iterator<Item = Self>,
63    {
64        iter.fold(LogLikelihood::from(0.0), |acc, x| acc + x)
65    }
66}
67
68impl Add for LogLikelihood {
69    type Output = Self;
70
71    #[inline]
72    fn add(self, rhs: Self) -> Self::Output {
73        Self(self.0 + rhs.0)
74    }
75}
76
77impl AddAssign for LogLikelihood {
78    #[inline]
79    fn add_assign(&mut self, rhs: Self) {
80        self.0 += rhs.0
81    }
82}
83
84/// A sum of items, and the number of items summed.
85#[derive(Clone, Copy, Debug, Eq, PartialEq)]
86pub struct SumOf<T> {
87    sum: T,
88    n: usize,
89}
90
91impl<T> SumOf<T> {
92    /// Returns the sum of items, consuming `self`.
93    pub fn into_sum(self) -> T {
94        self.sum
95    }
96
97    /// Returns the number of items summed.
98    pub fn n(&self) -> usize {
99        self.n
100    }
101
102    /// Creates a new sum.
103    pub fn new(sum: T, n: usize) -> Self {
104        Self { sum, n }
105    }
106
107    /// Returns the sum of items.
108    pub fn sum(&self) -> &T {
109        &self.sum
110    }
111}
112
113impl SumOf<LogLikelihood> {
114    /// Returns the log-likelihood normalised by the input size.
115    pub(super) fn normalise(&self) -> f64 {
116        f64::from(self.sum) / to_f64(self.n)
117    }
118}
119
120impl<T> From<SumOf<T>> for (T, usize) {
121    fn from(sum: SumOf<T>) -> Self {
122        (sum.sum, sum.n)
123    }
124}