pr_ml/svm/kernel.rs
1//! Kernel functions for SVM.
2// https://en.wikipedia.org/wiki/Kernel_function
3
4use std::fmt::Debug;
5
6use super::RowVector;
7
8/// Trait for kernel functions.
9pub trait Kernel<const D: usize>: Debug + Clone + PartialEq + Default {
10 /// Computes the kernel function between two vectors.
11 fn compute(&self, x1: &RowVector<D>, x2: &RowVector<D>) -> f32;
12}
13
14/// Linear kernel function, defined as the dot product of two vectors.
15///
16/// # Examples
17///
18/// ```
19/// use pr_ml::{RowVector, svm::{Kernel, LinearKernel}};
20///
21/// let kernel = LinearKernel;
22/// let x1 = RowVector::from([1.0, 2.0, 3.0]);
23/// let x2 = RowVector::from([4.0, 5.0, 6.0]);
24/// let result = kernel.compute(&x1, &x2);
25/// assert_eq!(result, 32.0); // 1*4 + 2*5 + 3*6 = 32
26/// ```
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
28pub struct LinearKernel;
29
30impl<const D: usize> Kernel<D> for LinearKernel {
31 fn compute(&self, x1: &RowVector<D>, x2: &RowVector<D>) -> f32 {
32 x1.dot(x2)
33 }
34}
35
36/// Polynomial kernel function, defined as $(x_1 \cdot x_2 + c)^d$.
37///
38/// # Examples
39///
40/// ```
41/// use pr_ml::{RowVector, svm::{Kernel, PolynomialKernel}};
42///
43/// let kernel = PolynomialKernel::new(2, 1.0);
44/// let x1 = RowVector::from([1.0, 2.0]);
45/// let x2 = RowVector::from([3.0, 4.0]);
46/// let result = kernel.compute(&x1, &x2);
47/// assert_eq!(result, 144.0); // (1*3 + 2*4 + 1)^2 = (3 + 8 + 1)^2 = 12^2 = 144
48/// ```
49#[derive(Debug, Clone, Copy, PartialEq)]
50pub struct PolynomialKernel {
51 /// Degree of the polynomial.
52 pub degree: u32,
53 /// Constant term.
54 pub c: f32,
55}
56
57impl<const D: usize> Kernel<D> for PolynomialKernel {
58 fn compute(&self, x1: &RowVector<D>, x2: &RowVector<D>) -> f32 {
59 (x1.dot(x2) + self.c).powi(self.degree as i32)
60 }
61}
62
63impl PolynomialKernel {
64 /// Creates a new [`PolynomialKernel`] with the given degree and constant term.
65 pub fn new(degree: u32, c: f32) -> Self {
66 Self { degree, c }
67 }
68}
69
70impl Default for PolynomialKernel {
71 fn default() -> Self {
72 Self::new(2, 1.0)
73 }
74}
75
76/// Gaussian kernel, defined as $\exp(-\frac{||x_1 - x_2||^2}{2\sigma^2})$. Also known as RBF kernel.
77///
78/// # Examples
79///
80/// ```
81/// use pr_ml::{RowVector, svm::{Kernel, GaussianKernel}};
82/// let kernel = GaussianKernel::new(1.0);
83/// let x1 = RowVector::from([1.0, 2.0]);
84/// let x2 = RowVector::from([2.0, 3.0]);
85/// let result = kernel.compute(&x1, &x2);
86/// assert!((result - 0.3679).abs() < 1e-4); // exp(-1) = 0.3679
87/// ```
88#[derive(Debug, Clone, Copy, PartialEq)]
89pub struct GaussianKernel {
90 /// Standard deviation parameter.
91 pub sigma: f32,
92}
93
94impl<const D: usize> Kernel<D> for GaussianKernel {
95 fn compute(&self, x1: &RowVector<D>, x2: &RowVector<D>) -> f32 {
96 let diff = x1 - x2;
97 let norm_sq = diff.dot(&diff);
98 (-norm_sq / (2.0 * self.sigma * self.sigma)).exp()
99 }
100}
101
102impl GaussianKernel {
103 /// Creates a new [`GaussianKernel`] with the given sigma.
104 pub fn new(sigma: f32) -> Self {
105 Self { sigma }
106 }
107}
108
109impl Default for GaussianKernel {
110 fn default() -> Self {
111 Self::new(1.0)
112 }
113}