use super::GaussianProcess;
use crate::conversion::Input;
use crate::parameters::kernel::Kernel;
use crate::parameters::prior::Prior;
use chrono::Duration;
use nalgebra::{DMatrix, DVector};
pub struct GaussianProcessBuilder<KernelType: Kernel, PriorType: Prior>
{
prior: PriorType,
kernel: KernelType,
noise: f64,
cholesky_epsilon: Option<f64>,
should_fit_kernel: bool,
should_fit_prior: bool,
max_iter: usize,
convergence_fraction: f64,
max_time: Duration,
training_inputs: DMatrix<f64>,
training_outputs: DVector<f64>
}
impl<KernelType: Kernel, PriorType: Prior> GaussianProcessBuilder<KernelType, PriorType>
{
pub fn new<T: Input>(training_inputs: T, training_outputs: T::InVector) -> Self
{
let training_inputs = T::into_dmatrix(training_inputs);
let training_outputs = T::into_dvector(training_outputs);
let prior = PriorType::default(training_inputs.ncols());
let kernel = KernelType::default();
let noise = 0.1 * training_outputs.row_variance()[0].sqrt(); let should_fit_kernel = false;
let should_fit_prior = false;
let max_iter = 100;
let convergence_fraction = 0.05;
let max_time = Duration::seconds(3600);
let cholesky_epsilon = None;
GaussianProcessBuilder { prior,
kernel,
noise,
cholesky_epsilon,
should_fit_kernel,
should_fit_prior,
max_iter,
convergence_fraction,
max_time,
training_inputs,
training_outputs }
}
pub fn set_prior<NewPriorType: Prior>(self,
prior: NewPriorType)
-> GaussianProcessBuilder<KernelType, NewPriorType>
{
GaussianProcessBuilder { prior,
kernel: self.kernel,
noise: self.noise,
cholesky_epsilon: self.cholesky_epsilon,
should_fit_kernel: self.should_fit_kernel,
should_fit_prior: self.should_fit_prior,
max_iter: self.max_iter,
convergence_fraction: self.convergence_fraction,
max_time: self.max_time,
training_inputs: self.training_inputs,
training_outputs: self.training_outputs }
}
pub fn set_noise(self, noise: f64) -> Self
{
assert!(noise >= 0., "The noise parameter should non-negative but we tried to set it to {}", noise);
GaussianProcessBuilder { noise, ..self }
}
pub fn set_kernel<NewKernelType: Kernel>(self,
kernel: NewKernelType)
-> GaussianProcessBuilder<NewKernelType, PriorType>
{
GaussianProcessBuilder { prior: self.prior,
kernel,
noise: self.noise,
cholesky_epsilon: self.cholesky_epsilon,
should_fit_kernel: self.should_fit_kernel,
should_fit_prior: self.should_fit_prior,
max_iter: self.max_iter,
convergence_fraction: self.convergence_fraction,
max_time: self.max_time,
training_inputs: self.training_inputs,
training_outputs: self.training_outputs }
}
pub fn set_cholesky_epsilon(self, cholesky_epsilon: Option<f64>) -> Self
{
GaussianProcessBuilder { cholesky_epsilon, ..self }
}
pub fn set_fit_parameters(self, max_iter: usize, convergence_fraction: f64) -> Self
{
GaussianProcessBuilder { max_iter, convergence_fraction, ..self }
}
pub fn fit_kernel(self) -> Self
{
GaussianProcessBuilder { should_fit_kernel: true, ..self }
}
pub fn fit_prior(self) -> Self
{
GaussianProcessBuilder { should_fit_prior: true, ..self }
}
pub fn train(mut self) -> GaussianProcess<KernelType, PriorType>
{
if self.should_fit_kernel
{
self.kernel.heuristic_fit(&self.training_inputs, &self.training_outputs);
}
let mut gp = GaussianProcess::<KernelType, PriorType>::new(self.prior,
self.kernel,
self.noise,
self.cholesky_epsilon,
self.training_inputs,
self.training_outputs);
gp.fit_parameters(self.should_fit_prior,
self.should_fit_kernel,
self.max_iter,
self.convergence_fraction,
self.max_time);
gp
}
}