1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
use crate::matrix::Matrix;
use crate::vector::Vector;
use crate::{Kernel, Mean};
use rand::distributions::Distribution;
use rand::Rng;
use rand_distr;

pub use self::mvn::MultivariateNormal;
pub use self::posterior::GaussianProcessPosterior;
pub use self::prior::GaussianProcessPrior;

mod mvn;
mod posterior;
mod prior;

#[derive(Debug)]
pub struct Posterior {
    inner: rand_distr::Normal<f64>,
}
impl Posterior {
    pub fn new<X, F, M, K>(x: &X, xs: &[X], f: F, mean: M, kernel: K) -> Option<Self>
    where
        X: Clone,
        F: Fn(&X) -> f64,
        M: Mean<X>,
        K: Kernel<X>,
    {
        let cov0 = Matrix::covariance(&[x.clone()], xs, &kernel);
        let cov1_i = Matrix::covariance(xs, xs, &kernel).inverse()?;

        let m0 = mean.mean(x);
        let means0 = xs
            .iter()
            .map(|x| f(x) - mean.mean(x) + m0)
            .collect::<Vector>();
        let means =
            cov0.clone().into_inner() * (cov1_i.clone().into_inner() * means0.clone().into_inner());
        let mean = means.get((0, 0))?;

        let cov2 = kernel.kernel(x, x);
        let cov3 = Matrix::covariance(xs, &[x.clone()], &kernel);
        let cov4 = cov0.into_inner() * (cov1_i.into_inner() * cov3.into_inner());
        let variance = cov2 - cov4.get((0, 0))?;

        Some(Self {
            inner: rand_distr::Normal::new(*mean, variance.sqrt()).ok()?,
        })
    }
}
impl Distribution<f64> for Posterior {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
        self.inner.sample(rng)
    }
}