1use super::EncodingStrategy;
7use crate::{
8 error::{QuantRS2Error, QuantRS2Result},
9 gate::{single::Hadamard, GateOp},
10 parametric::{ParametricRotationY, ParametricRotationZ},
11 qubit::QubitId,
12};
13use num_complex::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 fn new(strategy: EncodingStrategy, num_qubits: usize) -> Self {
81 let num_features = match strategy {
82 EncodingStrategy::Amplitude => 1 << num_qubits, EncodingStrategy::Angle => num_qubits, EncodingStrategy::IQP => num_qubits * (num_qubits + 1) / 2, EncodingStrategy::Basis => num_qubits, };
87
88 Self {
89 strategy,
90 num_qubits,
91 num_features,
92 }
93 }
94
95 pub fn num_features(&self) -> usize {
97 self.num_features
98 }
99
100 pub fn encode(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
102 if data.len() != self.num_features {
103 return Err(QuantRS2Error::InvalidInput(format!(
104 "Expected {} features, got {}",
105 self.num_features,
106 data.len()
107 )));
108 }
109
110 match self.strategy {
111 EncodingStrategy::Amplitude => self.amplitude_encoding(data),
112 EncodingStrategy::Angle => self.angle_encoding(data),
113 EncodingStrategy::IQP => self.iqp_encoding(data),
114 EncodingStrategy::Basis => self.basis_encoding(data),
115 }
116 }
117
118 fn amplitude_encoding(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
120 let norm: f64 = data.iter().map(|x| x * x).sum::<f64>().sqrt();
122 if norm < 1e-10 {
123 return Err(QuantRS2Error::InvalidInput(
124 "Cannot encode zero vector".to_string(),
125 ));
126 }
127
128 let _normalized: Vec<f64> = data.iter().map(|x| x / norm).collect();
129
130 let mut gates: Vec<Box<dyn GateOp>> = vec![];
135
136 for i in 0..self.num_qubits {
138 gates.push(Box::new(Hadamard {
139 target: QubitId(i as u32),
140 }));
141 }
142
143 Ok(gates)
147 }
148
149 fn angle_encoding(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
151 let mut gates: Vec<Box<dyn GateOp>> = vec![];
152
153 for i in 0..self.num_qubits {
155 gates.push(Box::new(Hadamard {
156 target: QubitId(i as u32),
157 }));
158 }
159
160 for (i, &value) in data.iter().enumerate() {
162 let qubit = QubitId(i as u32);
163 let angle = value * PI;
165 gates.push(Box::new(ParametricRotationY::new(qubit, angle)));
166 }
167
168 Ok(gates)
169 }
170
171 fn iqp_encoding(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
173 let mut gates: Vec<Box<dyn GateOp>> = vec![];
174
175 for i in 0..self.num_qubits {
177 gates.push(Box::new(Hadamard {
178 target: QubitId(i as u32),
179 }));
180 }
181
182 for i in 0..self.num_qubits {
184 let angle = data[i] * PI;
185 gates.push(Box::new(ParametricRotationZ::new(QubitId(i as u32), angle)));
186 }
187
188 let mut idx = self.num_qubits;
190 for i in 0..self.num_qubits {
191 for j in i + 1..self.num_qubits {
192 if idx < data.len() {
193 let angle = data[idx] * PI;
194 gates.push(Box::new(ParametricRotationZ::new(
197 QubitId(i as u32),
198 angle / 2.0,
199 )));
200 gates.push(Box::new(ParametricRotationZ::new(
201 QubitId(j as u32),
202 angle / 2.0,
203 )));
204 idx += 1;
205 }
206 }
207 }
208
209 Ok(gates)
210 }
211
212 fn basis_encoding(&self, data: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
214 use crate::gate::single::PauliX;
215
216 let mut gates: Vec<Box<dyn GateOp>> = vec![];
217
218 for (i, &value) in data.iter().enumerate() {
220 if value.abs() > 0.5 {
221 gates.push(Box::new(PauliX {
223 target: QubitId(i as u32),
224 }));
225 }
226 }
227
228 Ok(gates)
229 }
230}
231
232pub struct FeatureMap {
234 num_qubits: usize,
236 num_features: usize,
238 map_type: FeatureMapType,
240 reps: usize,
242}
243
244#[derive(Debug, Clone, Copy)]
245pub enum FeatureMapType {
246 Pauli,
248 ZFeature,
250 ZZFeature,
252 Custom,
254}
255
256impl FeatureMap {
257 pub fn new(num_qubits: usize, map_type: FeatureMapType, reps: usize) -> Self {
259 let num_features = match map_type {
260 FeatureMapType::Pauli => num_qubits,
261 FeatureMapType::ZFeature => num_qubits,
262 FeatureMapType::ZZFeature => num_qubits,
263 FeatureMapType::Custom => num_qubits,
264 };
265
266 Self {
267 num_qubits,
268 num_features,
269 map_type,
270 reps,
271 }
272 }
273
274 pub fn create_gates(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
276 if features.len() != self.num_features {
277 return Err(QuantRS2Error::InvalidInput(format!(
278 "Expected {} features, got {}",
279 self.num_features,
280 features.len()
281 )));
282 }
283
284 let mut gates = vec![];
285
286 for _ in 0..self.reps {
287 match self.map_type {
288 FeatureMapType::Pauli => {
289 gates.extend(self.pauli_feature_map(features)?);
290 }
291 FeatureMapType::ZFeature => {
292 gates.extend(self.z_feature_map(features)?);
293 }
294 FeatureMapType::ZZFeature => {
295 gates.extend(self.zz_feature_map(features)?);
296 }
297 FeatureMapType::Custom => {
298 }
300 }
301 }
302
303 Ok(gates)
304 }
305
306 fn pauli_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
308 let mut gates: Vec<Box<dyn GateOp>> = vec![];
309
310 for i in 0..self.num_qubits {
312 gates.push(Box::new(Hadamard {
313 target: QubitId(i as u32),
314 }));
315 }
316
317 for (i, &feature) in features.iter().enumerate() {
319 gates.push(Box::new(ParametricRotationZ::new(
320 QubitId(i as u32),
321 2.0 * feature,
322 )));
323 }
324
325 Ok(gates)
326 }
327
328 fn z_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
330 let mut gates: Vec<Box<dyn GateOp>> = vec![];
331
332 for i in 0..self.num_qubits {
334 gates.push(Box::new(Hadamard {
335 target: QubitId(i as u32),
336 }));
337 }
338
339 for (i, &feature) in features.iter().enumerate() {
341 gates.push(Box::new(ParametricRotationZ::new(
342 QubitId(i as u32),
343 2.0 * feature,
344 )));
345 }
346
347 Ok(gates)
348 }
349
350 fn zz_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
352 let mut gates = self.z_feature_map(features)?;
353
354 for i in 0..self.num_qubits - 1 {
356 gates.push(Box::new(CNOT {
357 control: QubitId(i as u32),
358 target: QubitId((i + 1) as u32),
359 }));
360
361 let angle = (PI - features[i]) * (PI - features[i + 1]);
363 gates.push(Box::new(ParametricRotationZ::new(
364 QubitId((i + 1) as u32),
365 angle,
366 )));
367
368 gates.push(Box::new(CNOT {
369 control: QubitId(i as u32),
370 target: QubitId((i + 1) as u32),
371 }));
372 }
373
374 Ok(gates)
375 }
376}
377
378pub struct DataReuploader {
380 encoder: DataEncoder,
382 num_layers: usize,
384 trainable_scaling: bool,
386}
387
388impl DataReuploader {
389 pub fn new(encoder: DataEncoder, num_layers: usize, trainable_scaling: bool) -> Self {
391 Self {
392 encoder,
393 num_layers,
394 trainable_scaling,
395 }
396 }
397
398 pub fn create_gates(
400 &self,
401 data: &[f64],
402 scaling_params: Option<&[f64]>,
403 ) -> QuantRS2Result<Vec<Vec<Box<dyn GateOp>>>> {
404 let mut layers = vec![];
405
406 for layer in 0..self.num_layers {
407 let scaled_data = if self.trainable_scaling {
408 if let Some(params) = scaling_params {
409 let offset = layer * data.len();
410 if offset + data.len() > params.len() {
411 return Err(QuantRS2Error::InvalidInput(
412 "Not enough scaling parameters".to_string(),
413 ));
414 }
415
416 data.iter()
417 .zip(¶ms[offset..offset + data.len()])
418 .map(|(d, p)| d * p)
419 .collect()
420 } else {
421 data.to_vec()
422 }
423 } else {
424 data.to_vec()
425 };
426
427 layers.push(self.encoder.encode(&scaled_data)?);
428 }
429
430 Ok(layers)
431 }
432}
433
434#[cfg(test)]
435mod tests {
436 use super::*;
437
438 #[test]
439 fn test_angle_encoding() {
440 let encoder = DataEncoder::new(EncodingStrategy::Angle, 3);
441 assert_eq!(encoder.num_features(), 3);
442
443 let data = vec![0.5, 1.0, 0.0];
444 let gates = encoder.encode(&data).unwrap();
445
446 assert_eq!(gates.len(), 6);
448 }
449
450 #[test]
451 fn test_basis_encoding() {
452 let encoder = DataEncoder::new(EncodingStrategy::Basis, 4);
453 assert_eq!(encoder.num_features(), 4);
454
455 let data = vec![1.0, 0.0, 1.0, 0.0];
456 let gates = encoder.encode(&data).unwrap();
457
458 assert_eq!(gates.len(), 2);
460 }
461
462 #[test]
463 fn test_feature_map() {
464 let feature_map = FeatureMap::new(2, FeatureMapType::ZFeature, 1);
465 let features = vec![0.5, 0.7];
466
467 let gates = feature_map.create_gates(&features).unwrap();
468
469 assert_eq!(gates.len(), 4);
471 }
472
473 #[test]
474 fn test_data_reuploader() {
475 let encoder = DataEncoder::new(EncodingStrategy::Angle, 2);
476 let reuploader = DataReuploader::new(encoder, 3, false);
477
478 let data = vec![0.5, 0.5];
479 let layers = reuploader.create_gates(&data, None).unwrap();
480
481 assert_eq!(layers.len(), 3); assert_eq!(layers[0].len(), 4); }
484}