1use crate::error::{MLError, Result};
2use scirs2_core::ndarray::{Array1, Array2};
3use quantrs2_circuit::prelude::Circuit;
4use quantrs2_sim::statevector::StateVectorSimulator;
5
6#[derive(Debug, Clone, Copy)]
8pub enum KernelMethod {
9 Linear,
11
12 Polynomial,
14
15 RBF,
17
18 QuantumKernel,
20
21 HybridKernel,
23}
24
25pub trait KernelFunction {
27 fn compute(&self, x1: &Array1<f64>, x2: &Array1<f64>) -> Result<f64>;
29
30 fn compute_matrix(&self, x: &Array2<f64>) -> Result<Array2<f64>> {
32 let n = x.nrows();
33 let mut kernel_matrix = Array2::zeros((n, n));
34
35 for i in 0..n {
36 let x_i = x.row(i).to_owned();
37
38 for j in 0..=i {
39 let x_j = x.row(j).to_owned();
40
41 let k_ij = self.compute(&x_i, &x_j)?;
42 kernel_matrix[[i, j]] = k_ij;
43
44 if i != j {
45 kernel_matrix[[j, i]] = k_ij; }
47 }
48 }
49
50 Ok(kernel_matrix)
51 }
52}
53
54#[derive(Debug, Clone)]
56pub struct LinearKernel;
57
58impl KernelFunction for LinearKernel {
59 fn compute(&self, x1: &Array1<f64>, x2: &Array1<f64>) -> Result<f64> {
60 if x1.len() != x2.len() {
61 return Err(MLError::InvalidParameter(format!(
62 "Vector dimensions mismatch: {} != {}",
63 x1.len(),
64 x2.len()
65 )));
66 }
67
68 let dot_product = x1.iter().zip(x2.iter()).map(|(&a, &b)| a * b).sum();
69
70 Ok(dot_product)
71 }
72}
73
74#[derive(Debug, Clone)]
76pub struct PolynomialKernel {
77 pub degree: usize,
79
80 pub coef: f64,
82}
83
84impl PolynomialKernel {
85 pub fn new(degree: usize, coef: f64) -> Self {
87 PolynomialKernel { degree, coef }
88 }
89}
90
91impl KernelFunction for PolynomialKernel {
92 fn compute(&self, x1: &Array1<f64>, x2: &Array1<f64>) -> Result<f64> {
93 if x1.len() != x2.len() {
94 return Err(MLError::InvalidParameter(format!(
95 "Vector dimensions mismatch: {} != {}",
96 x1.len(),
97 x2.len()
98 )));
99 }
100
101 let dot_product = x1.iter().zip(x2.iter()).map(|(&a, &b)| a * b).sum::<f64>();
102 let value = (dot_product + self.coef).powi(self.degree as i32);
103
104 Ok(value)
105 }
106}
107
108#[derive(Debug, Clone)]
110pub struct RBFKernel {
111 pub gamma: f64,
113}
114
115impl RBFKernel {
116 pub fn new(gamma: f64) -> Self {
118 RBFKernel { gamma }
119 }
120}
121
122impl KernelFunction for RBFKernel {
123 fn compute(&self, x1: &Array1<f64>, x2: &Array1<f64>) -> Result<f64> {
124 if x1.len() != x2.len() {
125 return Err(MLError::InvalidParameter(format!(
126 "Vector dimensions mismatch: {} != {}",
127 x1.len(),
128 x2.len()
129 )));
130 }
131
132 let squared_distance = x1
133 .iter()
134 .zip(x2.iter())
135 .map(|(&a, &b)| (a - b).powi(2))
136 .sum::<f64>();
137
138 let value = (-self.gamma * squared_distance).exp();
139
140 Ok(value)
141 }
142}
143
144#[derive(Debug, Clone)]
146pub struct QuantumKernel {
147 pub num_qubits: usize,
149
150 pub feature_dim: usize,
152
153 pub num_measurements: usize,
155}
156
157impl QuantumKernel {
158 pub fn new(num_qubits: usize, feature_dim: usize) -> Self {
160 QuantumKernel {
161 num_qubits,
162 feature_dim,
163 num_measurements: 1000,
164 }
165 }
166
167 pub fn with_measurements(mut self, num_measurements: usize) -> Self {
169 self.num_measurements = num_measurements;
170 self
171 }
172
173 fn encode_features<const N: usize>(
175 &self,
176 features: &Array1<f64>,
177 circuit: &mut Circuit<N>,
178 ) -> Result<()> {
179 for i in 0..N.min(features.len()) {
183 let angle = features[i] * std::f64::consts::PI;
184 circuit.ry(i, angle)?;
185 }
186
187 Ok(())
188 }
189
190 fn prepare_kernel_circuit<const N: usize>(
192 &self,
193 x1: &Array1<f64>,
194 x2: &Array1<f64>,
195 ) -> Result<Circuit<N>> {
196 let mut circuit = Circuit::<N>::new();
197
198 for i in 0..N.min(self.num_qubits) {
200 circuit.h(i)?;
201 }
202
203 self.encode_features(x1, &mut circuit)?;
205
206 for i in 0..N.min(self.num_qubits) {
208 circuit.x(i)?;
209 }
210
211 self.encode_features(x2, &mut circuit)?;
213
214 for i in 0..N.min(self.num_qubits) {
216 circuit.h(i)?;
217 }
218
219 Ok(circuit)
220 }
221}
222
223impl KernelFunction for QuantumKernel {
224 fn compute(&self, x1: &Array1<f64>, x2: &Array1<f64>) -> Result<f64> {
225 if x1.len() != x2.len() {
226 return Err(MLError::InvalidParameter(format!(
227 "Vector dimensions mismatch: {} != {}",
228 x1.len(),
229 x2.len()
230 )));
231 }
232
233 if x1.len() != self.feature_dim {
234 return Err(MLError::InvalidParameter(format!(
235 "Feature dimension mismatch: {} != {}",
236 x1.len(),
237 self.feature_dim
238 )));
239 }
240
241 let dot_product = x1.iter().zip(x2.iter()).map(|(&a, &b)| a * b).sum::<f64>();
246 let similarity = dot_product.abs().min(1.0);
247
248 Ok(similarity)
249 }
250}