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![];
141
142 let angles = compute_amplitude_angles(&normalized);
144
145 if let Some(&angle) = angles.first() {
147 gates.push(Box::new(ParametricRotationY::new(QubitId(0), angle)));
148 }
149
150 for level in 1..self.num_qubits {
153 let num_angles_at_level = 1usize << level;
154 let level_start = num_angles_at_level - 1; let level_end = level_start + num_angles_at_level;
156 let level_angles = if level_end <= angles.len() {
157 &angles[level_start..level_end]
158 } else {
159 continue;
160 };
161
162 let ucry_angles = ucry_decompose(level_angles);
165 let target = QubitId(level as u32);
166
167 for (k, &theta) in ucry_angles.iter().enumerate() {
168 gates.push(Box::new(ParametricRotationY::new(target, theta)));
169 if k < ucry_angles.len().saturating_sub(1) {
170 let gray_k = k ^ (k >> 1);
172 let gray_k1 = (k + 1) ^ ((k + 1) >> 1);
173 let diff_bit = gray_k ^ gray_k1;
174 let ctrl_qubit = diff_bit.trailing_zeros();
176 if (ctrl_qubit as usize) < level {
177 gates.push(Box::new(CNOT {
178 control: QubitId(ctrl_qubit),
179 target,
180 }));
181 }
182 }
183 }
184 }
185
186 Ok(gates)
187 }
188
189 fn angle_encoding(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
191 let mut gates: Vec<Box<dyn GateOp>> = vec![];
192
193 for i in 0..self.num_qubits {
195 gates.push(Box::new(Hadamard {
196 target: QubitId(i as u32),
197 }));
198 }
199
200 for (i, &value) in data.iter().enumerate() {
202 let qubit = QubitId(i as u32);
203 let angle = value * PI;
205 gates.push(Box::new(ParametricRotationY::new(qubit, angle)));
206 }
207
208 Ok(gates)
209 }
210
211 fn iqp_encoding(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
213 let mut gates: Vec<Box<dyn GateOp>> = vec![];
214
215 for i in 0..self.num_qubits {
217 gates.push(Box::new(Hadamard {
218 target: QubitId(i as u32),
219 }));
220 }
221
222 for i in 0..self.num_qubits {
224 let angle = data[i] * PI;
225 gates.push(Box::new(ParametricRotationZ::new(QubitId(i as u32), angle)));
226 }
227
228 let mut idx = self.num_qubits;
230 for i in 0..self.num_qubits {
231 for j in i + 1..self.num_qubits {
232 if idx < data.len() {
233 let angle = data[idx] * PI;
234 gates.push(Box::new(CNOT {
237 control: QubitId(i as u32),
238 target: QubitId(j as u32),
239 }));
240 gates.push(Box::new(ParametricRotationZ::new(QubitId(j as u32), angle)));
241 gates.push(Box::new(CNOT {
242 control: QubitId(i as u32),
243 target: QubitId(j as u32),
244 }));
245 idx += 1;
246 }
247 }
248 }
249
250 Ok(gates)
251 }
252
253 fn basis_encoding(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
255 use crate::gate::single::PauliX;
256
257 let mut gates: Vec<Box<dyn GateOp>> = vec![];
258
259 for (i, &value) in data.iter().enumerate() {
261 if value.abs() > 0.5 {
262 gates.push(Box::new(PauliX {
264 target: QubitId(i as u32),
265 }));
266 }
267 }
268
269 Ok(gates)
270 }
271}
272
273pub struct FeatureMap {
275 num_qubits: usize,
277 num_features: usize,
279 map_type: FeatureMapType,
281 reps: usize,
283}
284
285#[derive(Debug, Clone, Copy)]
286pub enum FeatureMapType {
287 Pauli,
289 ZFeature,
291 ZZFeature,
293 Custom,
295}
296
297impl FeatureMap {
298 pub const fn new(num_qubits: usize, map_type: FeatureMapType, reps: usize) -> Self {
300 let num_features = num_qubits; Self {
303 num_qubits,
304 num_features,
305 map_type,
306 reps,
307 }
308 }
309
310 pub fn create_gates(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
312 if features.len() != self.num_features {
313 return Err(QuantRS2Error::InvalidInput(format!(
314 "Expected {} features, got {}",
315 self.num_features,
316 features.len()
317 )));
318 }
319
320 let mut gates = vec![];
321
322 for _ in 0..self.reps {
323 match self.map_type {
324 FeatureMapType::Pauli => {
325 gates.extend(self.pauli_feature_map(features)?);
326 }
327 FeatureMapType::ZFeature => {
328 gates.extend(self.z_feature_map(features)?);
329 }
330 FeatureMapType::ZZFeature => {
331 gates.extend(self.zz_feature_map(features)?);
332 }
333 FeatureMapType::Custom => {
334 }
336 }
337 }
338
339 Ok(gates)
340 }
341
342 fn pauli_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
344 let mut gates: Vec<Box<dyn GateOp>> = vec![];
345
346 for i in 0..self.num_qubits {
348 gates.push(Box::new(Hadamard {
349 target: QubitId(i as u32),
350 }));
351 }
352
353 for (i, &feature) in features.iter().enumerate() {
355 gates.push(Box::new(ParametricRotationZ::new(
356 QubitId(i as u32),
357 2.0 * feature,
358 )));
359 }
360
361 Ok(gates)
362 }
363
364 fn z_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
366 let mut gates: Vec<Box<dyn GateOp>> = vec![];
367
368 for i in 0..self.num_qubits {
370 gates.push(Box::new(Hadamard {
371 target: QubitId(i as u32),
372 }));
373 }
374
375 for (i, &feature) in features.iter().enumerate() {
377 gates.push(Box::new(ParametricRotationZ::new(
378 QubitId(i as u32),
379 2.0 * feature,
380 )));
381 }
382
383 Ok(gates)
384 }
385
386 fn zz_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
388 let mut gates = self.z_feature_map(features)?;
389
390 for i in 0..self.num_qubits - 1 {
392 gates.push(Box::new(CNOT {
393 control: QubitId(i as u32),
394 target: QubitId((i + 1) as u32),
395 }));
396
397 let angle = (PI - features[i]) * (PI - features[i + 1]);
399 gates.push(Box::new(ParametricRotationZ::new(
400 QubitId((i + 1) as u32),
401 angle,
402 )));
403
404 gates.push(Box::new(CNOT {
405 control: QubitId(i as u32),
406 target: QubitId((i + 1) as u32),
407 }));
408 }
409
410 Ok(gates)
411 }
412}
413
414pub struct DataReuploader {
416 encoder: DataEncoder,
418 num_layers: usize,
420 trainable_scaling: bool,
422}
423
424impl DataReuploader {
425 pub const fn new(encoder: DataEncoder, num_layers: usize, trainable_scaling: bool) -> Self {
427 Self {
428 encoder,
429 num_layers,
430 trainable_scaling,
431 }
432 }
433
434 pub fn create_gates(
436 &self,
437 data: &[f64],
438 scaling_params: Option<&[f64]>,
439 ) -> QuantRS2Result<Vec<Vec<Box<dyn GateOp>>>> {
440 let mut layers = vec![];
441
442 for layer in 0..self.num_layers {
443 let scaled_data = if self.trainable_scaling {
444 if let Some(params) = scaling_params {
445 let offset = layer * data.len();
446 if offset + data.len() > params.len() {
447 return Err(QuantRS2Error::InvalidInput(
448 "Not enough scaling parameters".to_string(),
449 ));
450 }
451
452 data.iter()
453 .zip(¶ms[offset..offset + data.len()])
454 .map(|(d, p)| d * p)
455 .collect()
456 } else {
457 data.to_vec()
458 }
459 } else {
460 data.to_vec()
461 };
462
463 layers.push(self.encoder.encode(&scaled_data)?);
464 }
465
466 Ok(layers)
467 }
468}
469
470fn compute_amplitude_angles(amplitudes: &[f64]) -> Vec<f64> {
485 let n = amplitudes.len();
486 if n == 0 {
487 return vec![];
488 }
489
490 let mut angles: Vec<f64> = Vec::new();
491 let mut current_level: Vec<f64> = amplitudes.to_vec();
493
494 while current_level.len() > 1 {
495 let mut next_level: Vec<f64> = Vec::with_capacity(current_level.len() / 2);
496 let mut level_angles: Vec<f64> = Vec::with_capacity(current_level.len() / 2);
497
498 let chunks = current_level.chunks(2);
499 for chunk in chunks {
500 let left = chunk[0];
501 let right = if chunk.len() > 1 { chunk[1] } else { 0.0 };
502 let norm = (left * left + right * right).sqrt();
503 next_level.push(norm);
504 let angle = 2.0 * right.atan2(left);
505 level_angles.push(angle);
506 }
507
508 angles.extend(level_angles);
509 current_level = next_level;
510 }
511
512 angles.reverse();
514 angles
515}
516
517fn ucry_decompose(angles: &[f64]) -> Vec<f64> {
524 let n = angles.len();
525 if n == 0 {
526 return vec![];
527 }
528
529 let mut result = angles.to_vec();
531 let mut step = 1usize;
532
533 while step < n {
534 let mut k = 0usize;
535 while k < n {
536 for j in 0..step {
537 let a = result[k + j];
538 let b = result[k + j + step];
539 result[k + j] = (a + b) / 2.0;
540 result[k + j + step] = (a - b) / 2.0;
541 }
542 k += 2 * step;
543 }
544 step *= 2;
545 }
546
547 result
548}
549
550#[cfg(test)]
551mod tests {
552 use super::*;
553
554 #[test]
555 fn test_angle_encoding() {
556 let encoder = DataEncoder::new(EncodingStrategy::Angle, 3);
557 assert_eq!(encoder.num_features(), 3);
558
559 let data = vec![0.5, 1.0, 0.0];
560 let gates = encoder.encode(&data).expect("Failed to encode angle data");
561
562 assert_eq!(gates.len(), 6);
564 }
565
566 #[test]
567 fn test_basis_encoding() {
568 let encoder = DataEncoder::new(EncodingStrategy::Basis, 4);
569 assert_eq!(encoder.num_features(), 4);
570
571 let data = vec![1.0, 0.0, 1.0, 0.0];
572 let gates = encoder.encode(&data).expect("Failed to encode basis data");
573
574 assert_eq!(gates.len(), 2);
576 }
577
578 #[test]
579 fn test_feature_map() {
580 let feature_map = FeatureMap::new(2, FeatureMapType::ZFeature, 1);
581 let features = vec![0.5, 0.7];
582
583 let gates = feature_map
584 .create_gates(&features)
585 .expect("Failed to create feature map gates");
586
587 assert_eq!(gates.len(), 4);
589 }
590
591 #[test]
592 fn test_data_reuploader() {
593 let encoder = DataEncoder::new(EncodingStrategy::Angle, 2);
594 let reuploader = DataReuploader::new(encoder, 3, false);
595
596 let data = vec![0.5, 0.5];
597 let layers = reuploader
598 .create_gates(&data, None)
599 .expect("Failed to create reuploader gates");
600
601 assert_eq!(layers.len(), 3); assert_eq!(layers[0].len(), 4); }
604}