use std::ops::{Add, Mul};
use linalg::Vector;
use linalg::Metric;
use rulinalg::utils;
pub trait Kernel {
fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64;
}
#[derive(Debug)]
pub struct KernelSum<T, U>
where T: Kernel,
U: Kernel
{
k1: T,
k2: U,
}
impl<T, U> Kernel for KernelSum<T, U>
where T: Kernel,
U: Kernel
{
fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
self.k1.kernel(x1, x2) + self.k2.kernel(x1, x2)
}
}
#[derive(Debug)]
pub struct KernelProd<T, U>
where T: Kernel,
U: Kernel
{
k1: T,
k2: U,
}
impl<T, U> Kernel for KernelProd<T, U>
where T: Kernel,
U: Kernel
{
fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
self.k1.kernel(x1, x2) * self.k2.kernel(x1, x2)
}
}
#[derive(Debug)]
pub struct KernelArith<K: Kernel>(pub K);
impl<T: Kernel, U: Kernel> Add<KernelArith<T>> for KernelArith<U> {
type Output = KernelSum<U, T>;
fn add(self, ker: KernelArith<T>) -> KernelSum<U, T> {
KernelSum {
k1: self.0,
k2: ker.0,
}
}
}
impl<T: Kernel, U: Kernel> Mul<KernelArith<T>> for KernelArith<U> {
type Output = KernelProd<U, T>;
fn mul(self, ker: KernelArith<T>) -> KernelProd<U, T> {
KernelProd {
k1: self.0,
k2: ker.0,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Linear {
pub c: f64,
}
impl Linear {
pub fn new(c: f64) -> Linear {
Linear { c: c }
}
}
impl Default for Linear {
fn default() -> Linear {
Linear { c: 0f64 }
}
}
impl Kernel for Linear {
fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
utils::dot(x1, x2) + self.c
}
}
#[derive(Clone, Copy, Debug)]
pub struct Polynomial {
pub alpha: f64,
pub c: f64,
pub d: f64,
}
impl Polynomial {
pub fn new(alpha: f64, c: f64, d: f64) -> Polynomial {
Polynomial {
alpha: alpha,
c: c,
d: d,
}
}
}
impl Default for Polynomial {
fn default() -> Polynomial {
Polynomial {
alpha: 1f64,
c: 0f64,
d: 1f64,
}
}
}
impl Kernel for Polynomial {
fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
(self.alpha * utils::dot(x1, x2) + self.c).powf(self.d)
}
}
#[derive(Clone, Copy, Debug)]
pub struct SquaredExp {
pub ls: f64,
pub ampl: f64,
}
impl SquaredExp {
pub fn new(ls: f64, ampl: f64) -> SquaredExp {
SquaredExp {
ls: ls,
ampl: ampl,
}
}
}
impl Default for SquaredExp {
fn default() -> SquaredExp {
SquaredExp {
ls: 1f64,
ampl: 1f64,
}
}
}
impl Kernel for SquaredExp {
fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
assert_eq!(x1.len(), x2.len());
let diff = Vector::new(x1.to_vec()) - Vector::new(x2.to_vec());
let x = -diff.dot(&diff) / (2f64 * self.ls * self.ls);
(self.ampl * x.exp())
}
}
#[derive(Clone, Copy, Debug)]
pub struct Exponential {
pub ls: f64,
pub ampl: f64,
}
impl Exponential {
pub fn new(ls: f64, ampl: f64) -> Exponential {
Exponential {
ls: ls,
ampl: ampl,
}
}
}
impl Default for Exponential {
fn default() -> Exponential {
Exponential {
ls: 1f64,
ampl: 1f64,
}
}
}
impl Kernel for Exponential {
fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
assert_eq!(x1.len(), x2.len());
let diff = Vector::new(x1.to_vec()) - Vector::new(x2.to_vec());
let x = -diff.norm() / (2f64 * self.ls * self.ls);
(self.ampl * x.exp())
}
}
#[derive(Clone, Copy, Debug)]
pub struct HyperTan {
pub alpha: f64,
pub c: f64,
}
impl HyperTan {
pub fn new(alpha: f64, c: f64) -> HyperTan {
HyperTan {
alpha: alpha,
c: c,
}
}
}
impl Default for HyperTan {
fn default() -> HyperTan {
HyperTan {
alpha: 1f64,
c: 0f64,
}
}
}
impl Kernel for HyperTan {
fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
(self.alpha * utils::dot(x1, x2) + self.c).tanh()
}
}
#[derive(Clone, Copy, Debug)]
pub struct Multiquadric {
pub c: f64,
}
impl Multiquadric {
pub fn new(c: f64) -> Multiquadric {
Multiquadric { c: c }
}
}
impl Default for Multiquadric {
fn default() -> Multiquadric {
Multiquadric { c: 0f64 }
}
}
impl Kernel for Multiquadric {
fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
assert_eq!(x1.len(), x2.len());
let diff = Vector::new(x1.to_vec()) - Vector::new(x2.to_vec());
diff.norm().hypot(self.c)
}
}
#[derive(Clone, Copy, Debug)]
pub struct RationalQuadratic {
pub alpha: f64,
pub ls: f64,
}
impl RationalQuadratic {
pub fn new(alpha: f64, ls: f64) -> RationalQuadratic {
RationalQuadratic {
alpha: alpha,
ls: ls,
}
}
}
impl Default for RationalQuadratic {
fn default() -> RationalQuadratic {
RationalQuadratic {
alpha: 1f64,
ls: 1f64,
}
}
}
impl Kernel for RationalQuadratic {
fn kernel(&self, x1: &[f64], x2: &[f64]) -> f64 {
let diff = Vector::new(x1.to_vec()) - Vector::new(x2.to_vec());
(1f64 + diff.dot(&diff) / (2f64 * self.alpha * self.ls * self.ls)).powf(-self.alpha)
}
}