1use super::EncodingStrategy;
7use crate::{
8 error::{QuantRS2Error, QuantRS2Result},
9 gate::{single::Hadamard, GateOp},
10 parametric::{ParametricRotationY, ParametricRotationZ},
11 qubit::QubitId,
12};
13use scirs2_core::Complex64;
14use std::f64::consts::PI;
15
16#[allow(dead_code)]
18type RYGate = ParametricRotationY;
19#[allow(dead_code)]
20type RZGate = ParametricRotationZ;
21
22#[derive(Debug, Clone, Copy)]
24struct CNOT {
25 control: QubitId,
26 target: QubitId,
27}
28
29impl GateOp for CNOT {
30 fn name(&self) -> &'static str {
31 "CNOT"
32 }
33
34 fn qubits(&self) -> Vec<QubitId> {
35 vec![self.control, self.target]
36 }
37
38 fn matrix(&self) -> crate::error::QuantRS2Result<Vec<Complex64>> {
39 Ok(vec![
40 Complex64::new(1.0, 0.0),
41 Complex64::new(0.0, 0.0),
42 Complex64::new(0.0, 0.0),
43 Complex64::new(0.0, 0.0),
44 Complex64::new(0.0, 0.0),
45 Complex64::new(1.0, 0.0),
46 Complex64::new(0.0, 0.0),
47 Complex64::new(0.0, 0.0),
48 Complex64::new(0.0, 0.0),
49 Complex64::new(0.0, 0.0),
50 Complex64::new(0.0, 0.0),
51 Complex64::new(1.0, 0.0),
52 Complex64::new(0.0, 0.0),
53 Complex64::new(0.0, 0.0),
54 Complex64::new(1.0, 0.0),
55 Complex64::new(0.0, 0.0),
56 ])
57 }
58
59 fn as_any(&self) -> &dyn std::any::Any {
60 self
61 }
62
63 fn clone_gate(&self) -> Box<dyn GateOp> {
64 Box::new(*self)
65 }
66}
67
68pub struct DataEncoder {
70 strategy: EncodingStrategy,
72 num_qubits: usize,
74 num_features: usize,
76}
77
78impl DataEncoder {
79 pub const fn new(strategy: EncodingStrategy, num_qubits: usize) -> Self {
81 let num_features = match strategy {
82 EncodingStrategy::Amplitude => 1 << num_qubits, EncodingStrategy::Angle | EncodingStrategy::Basis => num_qubits, EncodingStrategy::IQP => num_qubits * (num_qubits + 1) / 2, };
86
87 Self {
88 strategy,
89 num_qubits,
90 num_features,
91 }
92 }
93
94 pub const fn num_features(&self) -> usize {
96 self.num_features
97 }
98
99 pub fn encode(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
101 if data.len() != self.num_features {
102 return Err(QuantRS2Error::InvalidInput(format!(
103 "Expected {} features, got {}",
104 self.num_features,
105 data.len()
106 )));
107 }
108
109 match self.strategy {
110 EncodingStrategy::Amplitude => self.amplitude_encoding(data),
111 EncodingStrategy::Angle => self.angle_encoding(data),
112 EncodingStrategy::IQP => self.iqp_encoding(data),
113 EncodingStrategy::Basis => self.basis_encoding(data),
114 }
115 }
116
117 fn amplitude_encoding(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
119 let norm: f64 = data.iter().map(|x| x * x).sum::<f64>().sqrt();
121 if norm < 1e-10 {
122 return Err(QuantRS2Error::InvalidInput(
123 "Cannot encode zero vector".to_string(),
124 ));
125 }
126
127 let _normalized: Vec<f64> = data.iter().map(|x| x / norm).collect();
128
129 let mut gates: Vec<Box<dyn GateOp>> = vec![];
134
135 for i in 0..self.num_qubits {
137 gates.push(Box::new(Hadamard {
138 target: QubitId(i as u32),
139 }));
140 }
141
142 Ok(gates)
146 }
147
148 fn angle_encoding(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
150 let mut gates: Vec<Box<dyn GateOp>> = vec![];
151
152 for i in 0..self.num_qubits {
154 gates.push(Box::new(Hadamard {
155 target: QubitId(i as u32),
156 }));
157 }
158
159 for (i, &value) in data.iter().enumerate() {
161 let qubit = QubitId(i as u32);
162 let angle = value * PI;
164 gates.push(Box::new(ParametricRotationY::new(qubit, angle)));
165 }
166
167 Ok(gates)
168 }
169
170 fn iqp_encoding(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
172 let mut gates: Vec<Box<dyn GateOp>> = vec![];
173
174 for i in 0..self.num_qubits {
176 gates.push(Box::new(Hadamard {
177 target: QubitId(i as u32),
178 }));
179 }
180
181 for i in 0..self.num_qubits {
183 let angle = data[i] * PI;
184 gates.push(Box::new(ParametricRotationZ::new(QubitId(i as u32), angle)));
185 }
186
187 let mut idx = self.num_qubits;
189 for i in 0..self.num_qubits {
190 for j in i + 1..self.num_qubits {
191 if idx < data.len() {
192 let angle = data[idx] * PI;
193 gates.push(Box::new(ParametricRotationZ::new(
196 QubitId(i as u32),
197 angle / 2.0,
198 )));
199 gates.push(Box::new(ParametricRotationZ::new(
200 QubitId(j as u32),
201 angle / 2.0,
202 )));
203 idx += 1;
204 }
205 }
206 }
207
208 Ok(gates)
209 }
210
211 fn basis_encoding(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
213 use crate::gate::single::PauliX;
214
215 let mut gates: Vec<Box<dyn GateOp>> = vec![];
216
217 for (i, &value) in data.iter().enumerate() {
219 if value.abs() > 0.5 {
220 gates.push(Box::new(PauliX {
222 target: QubitId(i as u32),
223 }));
224 }
225 }
226
227 Ok(gates)
228 }
229}
230
231pub struct FeatureMap {
233 num_qubits: usize,
235 num_features: usize,
237 map_type: FeatureMapType,
239 reps: usize,
241}
242
243#[derive(Debug, Clone, Copy)]
244pub enum FeatureMapType {
245 Pauli,
247 ZFeature,
249 ZZFeature,
251 Custom,
253}
254
255impl FeatureMap {
256 pub const fn new(num_qubits: usize, map_type: FeatureMapType, reps: usize) -> Self {
258 let num_features = num_qubits; Self {
261 num_qubits,
262 num_features,
263 map_type,
264 reps,
265 }
266 }
267
268 pub fn create_gates(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
270 if features.len() != self.num_features {
271 return Err(QuantRS2Error::InvalidInput(format!(
272 "Expected {} features, got {}",
273 self.num_features,
274 features.len()
275 )));
276 }
277
278 let mut gates = vec![];
279
280 for _ in 0..self.reps {
281 match self.map_type {
282 FeatureMapType::Pauli => {
283 gates.extend(self.pauli_feature_map(features)?);
284 }
285 FeatureMapType::ZFeature => {
286 gates.extend(self.z_feature_map(features)?);
287 }
288 FeatureMapType::ZZFeature => {
289 gates.extend(self.zz_feature_map(features)?);
290 }
291 FeatureMapType::Custom => {
292 }
294 }
295 }
296
297 Ok(gates)
298 }
299
300 fn pauli_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
302 let mut gates: Vec<Box<dyn GateOp>> = vec![];
303
304 for i in 0..self.num_qubits {
306 gates.push(Box::new(Hadamard {
307 target: QubitId(i as u32),
308 }));
309 }
310
311 for (i, &feature) in features.iter().enumerate() {
313 gates.push(Box::new(ParametricRotationZ::new(
314 QubitId(i as u32),
315 2.0 * feature,
316 )));
317 }
318
319 Ok(gates)
320 }
321
322 fn z_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
324 let mut gates: Vec<Box<dyn GateOp>> = vec![];
325
326 for i in 0..self.num_qubits {
328 gates.push(Box::new(Hadamard {
329 target: QubitId(i as u32),
330 }));
331 }
332
333 for (i, &feature) in features.iter().enumerate() {
335 gates.push(Box::new(ParametricRotationZ::new(
336 QubitId(i as u32),
337 2.0 * feature,
338 )));
339 }
340
341 Ok(gates)
342 }
343
344 fn zz_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
346 let mut gates = self.z_feature_map(features)?;
347
348 for i in 0..self.num_qubits - 1 {
350 gates.push(Box::new(CNOT {
351 control: QubitId(i as u32),
352 target: QubitId((i + 1) as u32),
353 }));
354
355 let angle = (PI - features[i]) * (PI - features[i + 1]);
357 gates.push(Box::new(ParametricRotationZ::new(
358 QubitId((i + 1) as u32),
359 angle,
360 )));
361
362 gates.push(Box::new(CNOT {
363 control: QubitId(i as u32),
364 target: QubitId((i + 1) as u32),
365 }));
366 }
367
368 Ok(gates)
369 }
370}
371
372pub struct DataReuploader {
374 encoder: DataEncoder,
376 num_layers: usize,
378 trainable_scaling: bool,
380}
381
382impl DataReuploader {
383 pub const fn new(encoder: DataEncoder, num_layers: usize, trainable_scaling: bool) -> Self {
385 Self {
386 encoder,
387 num_layers,
388 trainable_scaling,
389 }
390 }
391
392 pub fn create_gates(
394 &self,
395 data: &[f64],
396 scaling_params: Option<&[f64]>,
397 ) -> QuantRS2Result<Vec<Vec<Box<dyn GateOp>>>> {
398 let mut layers = vec![];
399
400 for layer in 0..self.num_layers {
401 let scaled_data = if self.trainable_scaling {
402 if let Some(params) = scaling_params {
403 let offset = layer * data.len();
404 if offset + data.len() > params.len() {
405 return Err(QuantRS2Error::InvalidInput(
406 "Not enough scaling parameters".to_string(),
407 ));
408 }
409
410 data.iter()
411 .zip(¶ms[offset..offset + data.len()])
412 .map(|(d, p)| d * p)
413 .collect()
414 } else {
415 data.to_vec()
416 }
417 } else {
418 data.to_vec()
419 };
420
421 layers.push(self.encoder.encode(&scaled_data)?);
422 }
423
424 Ok(layers)
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431
432 #[test]
433 fn test_angle_encoding() {
434 let encoder = DataEncoder::new(EncodingStrategy::Angle, 3);
435 assert_eq!(encoder.num_features(), 3);
436
437 let data = vec![0.5, 1.0, 0.0];
438 let gates = encoder.encode(&data).expect("Failed to encode angle data");
439
440 assert_eq!(gates.len(), 6);
442 }
443
444 #[test]
445 fn test_basis_encoding() {
446 let encoder = DataEncoder::new(EncodingStrategy::Basis, 4);
447 assert_eq!(encoder.num_features(), 4);
448
449 let data = vec![1.0, 0.0, 1.0, 0.0];
450 let gates = encoder.encode(&data).expect("Failed to encode basis data");
451
452 assert_eq!(gates.len(), 2);
454 }
455
456 #[test]
457 fn test_feature_map() {
458 let feature_map = FeatureMap::new(2, FeatureMapType::ZFeature, 1);
459 let features = vec![0.5, 0.7];
460
461 let gates = feature_map
462 .create_gates(&features)
463 .expect("Failed to create feature map gates");
464
465 assert_eq!(gates.len(), 4);
467 }
468
469 #[test]
470 fn test_data_reuploader() {
471 let encoder = DataEncoder::new(EncodingStrategy::Angle, 2);
472 let reuploader = DataReuploader::new(encoder, 3, false);
473
474 let data = vec![0.5, 0.5];
475 let layers = reuploader
476 .create_gates(&data, None)
477 .expect("Failed to create reuploader gates");
478
479 assert_eq!(layers.len(), 3); assert_eq!(layers[0].len(), 4); }
482}