Implement more and more logic.
This commit is contained in:
@@ -1,3 +1,8 @@
|
|||||||
|
use std::mem;
|
||||||
|
|
||||||
|
use ndarray::prelude::*;
|
||||||
|
use ndarray::stack;
|
||||||
|
|
||||||
use crate::kernel::Kernel;
|
use crate::kernel::Kernel;
|
||||||
|
|
||||||
use super::Fitter;
|
use super::Fitter;
|
||||||
@@ -5,36 +10,144 @@ use super::Fitter;
|
|||||||
pub struct RecursiveFitter {
|
pub struct RecursiveFitter {
|
||||||
ts_new: Vec<f64>,
|
ts_new: Vec<f64>,
|
||||||
kernel: Box<dyn Kernel>,
|
kernel: Box<dyn Kernel>,
|
||||||
ts: Vec<usize>,
|
ts: Vec<f64>,
|
||||||
ms: Vec<usize>,
|
ms: ArrayD<f64>,
|
||||||
vs: Vec<usize>,
|
vs: Array1<f64>,
|
||||||
ns: Vec<usize>,
|
ns: ArrayD<f64>,
|
||||||
xs: Vec<usize>,
|
xs: ArrayD<f64>,
|
||||||
is_fitted: bool,
|
is_fitted: bool,
|
||||||
|
h: Array1<f64>,
|
||||||
|
i: ArrayD<f64>,
|
||||||
|
a: ArrayD<f64>,
|
||||||
|
q: ArrayD<f64>,
|
||||||
|
m_p: ArrayD<f64>,
|
||||||
|
p_p: ArrayD<f64>,
|
||||||
|
m_f: ArrayD<f64>,
|
||||||
|
p_f: ArrayD<f64>,
|
||||||
|
m_s: ArrayD<f64>,
|
||||||
|
p_s: ArrayD<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RecursiveFitter {
|
impl RecursiveFitter {
|
||||||
pub fn new(kernel: Box<dyn Kernel>) -> Self {
|
pub fn new(kernel: Box<dyn Kernel>) -> Self {
|
||||||
|
let m = kernel.order();
|
||||||
|
let h = kernel.measurement_vector();
|
||||||
|
|
||||||
RecursiveFitter {
|
RecursiveFitter {
|
||||||
ts_new: Vec::new(),
|
ts_new: Vec::new(),
|
||||||
kernel,
|
kernel,
|
||||||
ts: Vec::new(),
|
ts: Vec::new(),
|
||||||
ms: Vec::new(),
|
ms: Array::zeros(0).into_dyn(),
|
||||||
vs: Vec::new(),
|
vs: Array1::zeros(0),
|
||||||
ns: Vec::new(),
|
ns: Array::zeros(0).into_dyn(),
|
||||||
xs: Vec::new(),
|
xs: Array::zeros(0).into_dyn(),
|
||||||
is_fitted: true,
|
is_fitted: true,
|
||||||
|
h,
|
||||||
|
i: Array::eye(m).into_dyn(),
|
||||||
|
a: Array::zeros((0, m, m)).into_dyn(),
|
||||||
|
q: Array::zeros((0, m, m)).into_dyn(),
|
||||||
|
m_p: Array::zeros((0, m)).into_dyn(),
|
||||||
|
p_p: Array::zeros((0, m, m)).into_dyn(),
|
||||||
|
m_f: Array::zeros((0, m)).into_dyn(),
|
||||||
|
p_f: Array::zeros((0, m, m)).into_dyn(),
|
||||||
|
m_s: Array::zeros((0, m)).into_dyn(),
|
||||||
|
p_s: Array::zeros((0, m, m)).into_dyn(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fitter for RecursiveFitter {
|
impl Fitter for RecursiveFitter {
|
||||||
fn add_sample(&mut self, t: f64) -> usize {
|
fn add_sample(&mut self, t: f64) -> usize {
|
||||||
todo!();
|
let idx = self.ts.len() + self.ts_new.len();
|
||||||
|
|
||||||
|
self.ts_new.push(t);
|
||||||
|
self.is_fitted = false;
|
||||||
|
|
||||||
|
idx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate(&mut self) {
|
fn allocate(&mut self) {
|
||||||
|
let n_new = self.ts_new.len();
|
||||||
|
|
||||||
|
if n_new == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usual variables.
|
||||||
|
let zeros = Array::zeros(n_new).into_dyn();
|
||||||
|
|
||||||
|
self.ts.extend(self.ts_new.iter());
|
||||||
|
self.ms = stack![Axis(0), self.ms, zeros];
|
||||||
|
self.vs = stack![Axis(0), self.vs, self.kernel.k_diag(&self.ts_new)];
|
||||||
|
self.ns = stack![Axis(0), self.ns, zeros];
|
||||||
|
self.xs = stack![Axis(0), self.xs, zeros];
|
||||||
|
|
||||||
|
// Initialize the predictive, filtering and smoothing distributions.
|
||||||
|
let mean = self
|
||||||
|
.ts_new
|
||||||
|
.iter()
|
||||||
|
.flat_map(|t| self.kernel.state_mean(*t).to_vec().into_iter())
|
||||||
|
.collect::<Vec<f64>>();
|
||||||
|
|
||||||
|
let mean = Array::from_shape_vec((self.ts_new.len(), self.kernel.order()), mean)
|
||||||
|
.unwrap()
|
||||||
|
.into_dyn();
|
||||||
|
|
||||||
|
let cov = self
|
||||||
|
.ts_new
|
||||||
|
.iter()
|
||||||
|
.flat_map(|t| {
|
||||||
|
self.kernel
|
||||||
|
.state_cov(*t)
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<f64>>()
|
||||||
|
})
|
||||||
|
.collect::<Vec<f64>>();
|
||||||
|
|
||||||
|
let cov = Array3::from_shape_vec(
|
||||||
|
(self.ts_new.len(), self.kernel.order(), self.kernel.order()),
|
||||||
|
cov,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.into_dyn();
|
||||||
|
|
||||||
|
self.m_p = stack![Axis(0), self.m_p, mean];
|
||||||
|
self.p_p = stack![Axis(0), self.p_p, cov];
|
||||||
|
|
||||||
|
self.m_f = stack![Axis(0), self.m_f, mean];
|
||||||
|
self.p_f = stack![Axis(0), self.p_f, cov];
|
||||||
|
|
||||||
|
self.m_s = stack![Axis(0), self.m_s, mean];
|
||||||
|
self.p_s = stack![Axis(0), self.p_s, cov];
|
||||||
|
|
||||||
|
// Compute the new transition and noise covariance matrices.
|
||||||
|
let m = self.kernel.order();
|
||||||
|
|
||||||
|
self.a = stack![Axis(0), self.a, Array::zeros((n_new, m, m)).into_dyn()];
|
||||||
|
self.q = stack![Axis(0), self.q, Array::zeros((n_new, m, m)).into_dyn()];
|
||||||
|
|
||||||
|
for i in (self.ts.len() - n_new)..self.ts.len() {
|
||||||
|
if i == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.a[i - 1] = self.kernel.transition(self.ts[i - 1], self.ts[1]);
|
||||||
|
// self.q[i - 1] = self.kernel.noise_cov(self.ts[i - 1], self.ts[1]);
|
||||||
|
}
|
||||||
|
|
||||||
todo!();
|
todo!();
|
||||||
|
|
||||||
|
/*
|
||||||
|
for i in range(len(self.ts) - n_new, len(self.ts)):
|
||||||
|
if i == 0:
|
||||||
|
# Very first sample, no need to compute anything.
|
||||||
|
continue
|
||||||
|
self._A[i-1] = self.kernel.transition(self.ts[i-1], self.ts[i])
|
||||||
|
self._Q[i-1] = self.kernel.noise_cov(self.ts[i-1], self.ts[i])
|
||||||
|
# Clear the list of pending samples.
|
||||||
|
self.ts_new = list()
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fit(&mut self) {
|
fn fit(&mut self) {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use ndarray::prelude::*;
|
||||||
|
|
||||||
mod constant;
|
mod constant;
|
||||||
mod exponential;
|
mod exponential;
|
||||||
mod matern52;
|
mod matern52;
|
||||||
@@ -6,6 +8,73 @@ pub use constant::Constant;
|
|||||||
pub use exponential::Exponential;
|
pub use exponential::Exponential;
|
||||||
pub use matern52::Matern52;
|
pub use matern52::Matern52;
|
||||||
|
|
||||||
pub trait Kernel {}
|
pub trait Kernel {
|
||||||
|
fn k_diag(&self, ts: &[f64]) -> Array1<f64>;
|
||||||
|
fn order(&self) -> usize;
|
||||||
|
fn state_mean(&self, t: f64) -> Array1<f64>;
|
||||||
|
fn state_cov(&self, t: f64) -> Array2<f64>;
|
||||||
|
fn measurement_vector(&self) -> Array1<f64>;
|
||||||
|
fn transition(&self, t0: f64, t1: f64) -> Array2<f64>;
|
||||||
|
}
|
||||||
|
|
||||||
impl Kernel for Vec<Box<dyn Kernel>> {}
|
impl Kernel for Vec<Box<dyn Kernel>> {
|
||||||
|
fn k_diag(&self, ts: &[f64]) -> Array1<f64> {
|
||||||
|
self.iter()
|
||||||
|
.fold(Array1::zeros(ts.len()), |k_diag: Array1<f64>, kernel| {
|
||||||
|
k_diag + kernel.k_diag(ts)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn order(&self) -> usize {
|
||||||
|
self.iter().map(|kernel| kernel.order()).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_mean(&self, t: f64) -> Array1<f64> {
|
||||||
|
let data = self
|
||||||
|
.iter()
|
||||||
|
.flat_map(|kernel| kernel.state_mean(t).to_vec().into_iter())
|
||||||
|
.collect::<Vec<f64>>();
|
||||||
|
|
||||||
|
Array1::from(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_cov(&self, t: f64) -> Array2<f64> {
|
||||||
|
let data = self
|
||||||
|
.iter()
|
||||||
|
.map(|kernel| kernel.state_cov(t))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let dim = data
|
||||||
|
.iter()
|
||||||
|
.fold((0, 0), |(w, h), m| (w + m.ncols(), h + m.nrows()));
|
||||||
|
|
||||||
|
let mut cov = Array2::zeros(dim);
|
||||||
|
|
||||||
|
let mut r_d = 0;
|
||||||
|
let mut c_d = 0;
|
||||||
|
|
||||||
|
for m in data {
|
||||||
|
for ((r, c), v) in m.indexed_iter() {
|
||||||
|
cov[(r + r_d, c + c_d)] = *v;
|
||||||
|
}
|
||||||
|
|
||||||
|
r_d += m.nrows();
|
||||||
|
c_d += m.ncols();
|
||||||
|
}
|
||||||
|
|
||||||
|
cov
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measurement_vector(&self) -> Array1<f64> {
|
||||||
|
let data = self
|
||||||
|
.iter()
|
||||||
|
.flat_map(|kernel| kernel.measurement_vector().to_vec().into_iter())
|
||||||
|
.collect::<Vec<f64>>();
|
||||||
|
|
||||||
|
Array1::from(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transition(&self, t0: f64, t1: f64) -> Array2<f64> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use ndarray::prelude::*;
|
||||||
|
|
||||||
use super::Kernel;
|
use super::Kernel;
|
||||||
|
|
||||||
pub struct Constant {
|
pub struct Constant {
|
||||||
@@ -10,4 +12,28 @@ impl Constant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Kernel for Constant {}
|
impl Kernel for Constant {
|
||||||
|
fn k_diag(&self, ts: &[f64]) -> Array1<f64> {
|
||||||
|
Array1::ones(ts.len()) * self.var
|
||||||
|
}
|
||||||
|
|
||||||
|
fn order(&self) -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_mean(&self, t: f64) -> Array1<f64> {
|
||||||
|
Array1::zeros(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_cov(&self, t: f64) -> Array2<f64> {
|
||||||
|
array![[1.0]] * self.var
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measurement_vector(&self) -> Array1<f64> {
|
||||||
|
array![1.0]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transition(&self, t0: f64, t1: f64) -> Array2<f64> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use ndarray::prelude::*;
|
||||||
|
|
||||||
use super::Kernel;
|
use super::Kernel;
|
||||||
|
|
||||||
pub struct Exponential {
|
pub struct Exponential {
|
||||||
@@ -11,4 +13,28 @@ impl Exponential {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Kernel for Exponential {}
|
impl Kernel for Exponential {
|
||||||
|
fn k_diag(&self, ts: &[f64]) -> Array1<f64> {
|
||||||
|
Array1::ones(ts.len()) * self.var
|
||||||
|
}
|
||||||
|
|
||||||
|
fn order(&self) -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_mean(&self, t: f64) -> Array1<f64> {
|
||||||
|
Array1::zeros(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_cov(&self, t: f64) -> Array2<f64> {
|
||||||
|
array![[1.0]] * self.var
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measurement_vector(&self) -> Array1<f64> {
|
||||||
|
array![1.0]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transition(&self, t0: f64, t1: f64) -> Array2<f64> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,51 @@
|
|||||||
|
use ndarray::prelude::*;
|
||||||
|
|
||||||
use super::Kernel;
|
use super::Kernel;
|
||||||
|
|
||||||
pub struct Matern52 {
|
pub struct Matern52 {
|
||||||
var: f64,
|
var: f64,
|
||||||
l_scale: f64,
|
l_scale: f64,
|
||||||
|
lambda: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Matern52 {
|
impl Matern52 {
|
||||||
pub fn new(var: f64, l_scale: f64) -> Self {
|
pub fn new(var: f64, l_scale: f64) -> Self {
|
||||||
Matern52 { var, l_scale }
|
Matern52 {
|
||||||
|
var,
|
||||||
|
l_scale,
|
||||||
|
lambda: 5.0f64.sqrt() / l_scale,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Kernel for Matern52 {}
|
impl Kernel for Matern52 {
|
||||||
|
fn k_diag(&self, ts: &[f64]) -> Array1<f64> {
|
||||||
|
Array1::ones(ts.len()) * self.var
|
||||||
|
}
|
||||||
|
|
||||||
|
fn order(&self) -> usize {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_mean(&self, t: f64) -> Array1<f64> {
|
||||||
|
Array1::zeros(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_cov(&self, t: f64) -> Array2<f64> {
|
||||||
|
let a = self.lambda;
|
||||||
|
|
||||||
|
array![
|
||||||
|
[1.0, 0.0, -a * a / 3.0],
|
||||||
|
[0.0, a * a / 3.0, 0.0],
|
||||||
|
[-a * a / 3.0, 0.0, a.powi(4)]
|
||||||
|
] * self.var
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measurement_vector(&self) -> Array1<f64> {
|
||||||
|
array![1.0, 0.0, 0.0]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transition(&self, t0: f64, t1: f64) -> Array2<f64> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user