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