1use super::EncodingStrategy;
7use crate::{
8 error::{QuantRS2Error, QuantRS2Result},
9 gate::{single::Hadamard, GateOp},
10 parametric::{ParametricRotationY, ParametricRotationZ},
11 qubit::QubitId,
12};
13use ndarray::{Array1, Array2};
14use num_complex::Complex64;
15use std::f64::consts::PI;
16
17type RYGate = ParametricRotationY;
19type RZGate = ParametricRotationZ;
20
21#[derive(Debug, Clone, Copy)]
23struct CNOT {
24 control: QubitId,
25 target: QubitId,
26}
27
28impl GateOp for CNOT {
29 fn name(&self) -> &'static str {
30 "CNOT"
31 }
32
33 fn qubits(&self) -> Vec<QubitId> {
34 vec![self.control, self.target]
35 }
36
37 fn matrix(&self) -> crate::error::QuantRS2Result<Vec<Complex64>> {
38 Ok(vec![
39 Complex64::new(1.0, 0.0),
40 Complex64::new(0.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(1.0, 0.0),
45 Complex64::new(0.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(1.0, 0.0),
51 Complex64::new(0.0, 0.0),
52 Complex64::new(0.0, 0.0),
53 Complex64::new(1.0, 0.0),
54 Complex64::new(0.0, 0.0),
55 ])
56 }
57
58 fn as_any(&self) -> &dyn std::any::Any {
59 self
60 }
61
62 fn clone_gate(&self) -> Box<dyn GateOp> {
63 Box::new(*self)
64 }
65}
66
67pub struct DataEncoder {
69 strategy: EncodingStrategy,
71 num_qubits: usize,
73 num_features: usize,
75}
76
77impl DataEncoder {
78 pub fn new(strategy: EncodingStrategy, num_qubits: usize) -> Self {
80 let num_features = match strategy {
81 EncodingStrategy::Amplitude => 1 << num_qubits, EncodingStrategy::Angle => num_qubits, EncodingStrategy::IQP => num_qubits * (num_qubits + 1) / 2, EncodingStrategy::Basis => num_qubits, };
86
87 Self {
88 strategy,
89 num_qubits,
90 num_features,
91 }
92 }
93
94 pub 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 fn new(num_qubits: usize, map_type: FeatureMapType, reps: usize) -> Self {
258 let num_features = match map_type {
259 FeatureMapType::Pauli => num_qubits,
260 FeatureMapType::ZFeature => num_qubits,
261 FeatureMapType::ZZFeature => num_qubits,
262 FeatureMapType::Custom => num_qubits,
263 };
264
265 Self {
266 num_qubits,
267 num_features,
268 map_type,
269 reps,
270 }
271 }
272
273 pub fn create_gates(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
275 if features.len() != self.num_features {
276 return Err(QuantRS2Error::InvalidInput(format!(
277 "Expected {} features, got {}",
278 self.num_features,
279 features.len()
280 )));
281 }
282
283 let mut gates = vec![];
284
285 for _ in 0..self.reps {
286 match self.map_type {
287 FeatureMapType::Pauli => {
288 gates.extend(self.pauli_feature_map(features)?);
289 }
290 FeatureMapType::ZFeature => {
291 gates.extend(self.z_feature_map(features)?);
292 }
293 FeatureMapType::ZZFeature => {
294 gates.extend(self.zz_feature_map(features)?);
295 }
296 FeatureMapType::Custom => {
297 }
299 }
300 }
301
302 Ok(gates)
303 }
304
305 fn pauli_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
307 let mut gates: Vec<Box<dyn GateOp>> = vec![];
308
309 for i in 0..self.num_qubits {
311 gates.push(Box::new(Hadamard {
312 target: QubitId(i as u32),
313 }));
314 }
315
316 for (i, &feature) in features.iter().enumerate() {
318 gates.push(Box::new(ParametricRotationZ::new(
319 QubitId(i as u32),
320 2.0 * feature,
321 )));
322 }
323
324 Ok(gates)
325 }
326
327 fn z_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
329 let mut gates: Vec<Box<dyn GateOp>> = vec![];
330
331 for i in 0..self.num_qubits {
333 gates.push(Box::new(Hadamard {
334 target: QubitId(i as u32),
335 }));
336 }
337
338 for (i, &feature) in features.iter().enumerate() {
340 gates.push(Box::new(ParametricRotationZ::new(
341 QubitId(i as u32),
342 2.0 * feature,
343 )));
344 }
345
346 Ok(gates)
347 }
348
349 fn zz_feature_map(&self, features: &[f64]) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
351 let mut gates = self.z_feature_map(features)?;
352
353 for i in 0..self.num_qubits - 1 {
355 gates.push(Box::new(CNOT {
356 control: QubitId(i as u32),
357 target: QubitId((i + 1) as u32),
358 }));
359
360 let angle = (PI - features[i]) * (PI - features[i + 1]);
362 gates.push(Box::new(ParametricRotationZ::new(
363 QubitId((i + 1) as u32),
364 angle,
365 )));
366
367 gates.push(Box::new(CNOT {
368 control: QubitId(i as u32),
369 target: QubitId((i + 1) as u32),
370 }));
371 }
372
373 Ok(gates)
374 }
375}
376
377pub struct DataReuploader {
379 encoder: DataEncoder,
381 num_layers: usize,
383 trainable_scaling: bool,
385}
386
387impl DataReuploader {
388 pub fn new(encoder: DataEncoder, num_layers: usize, trainable_scaling: bool) -> Self {
390 Self {
391 encoder,
392 num_layers,
393 trainable_scaling,
394 }
395 }
396
397 pub fn create_gates(
399 &self,
400 data: &[f64],
401 scaling_params: Option<&[f64]>,
402 ) -> QuantRS2Result<Vec<Vec<Box<dyn GateOp>>>> {
403 let mut layers = vec![];
404
405 for layer in 0..self.num_layers {
406 let scaled_data = if self.trainable_scaling {
407 if let Some(params) = scaling_params {
408 let offset = layer * data.len();
409 if offset + data.len() > params.len() {
410 return Err(QuantRS2Error::InvalidInput(
411 "Not enough scaling parameters".to_string(),
412 ));
413 }
414
415 data.iter()
416 .zip(¶ms[offset..offset + data.len()])
417 .map(|(d, p)| d * p)
418 .collect()
419 } else {
420 data.to_vec()
421 }
422 } else {
423 data.to_vec()
424 };
425
426 layers.push(self.encoder.encode(&scaled_data)?);
427 }
428
429 Ok(layers)
430 }
431}
432
433#[cfg(test)]
434mod tests {
435 use super::*;
436
437 #[test]
438 fn test_angle_encoding() {
439 let encoder = DataEncoder::new(EncodingStrategy::Angle, 3);
440 assert_eq!(encoder.num_features(), 3);
441
442 let data = vec![0.5, 1.0, 0.0];
443 let gates = encoder.encode(&data).unwrap();
444
445 assert_eq!(gates.len(), 6);
447 }
448
449 #[test]
450 fn test_basis_encoding() {
451 let encoder = DataEncoder::new(EncodingStrategy::Basis, 4);
452 assert_eq!(encoder.num_features(), 4);
453
454 let data = vec![1.0, 0.0, 1.0, 0.0];
455 let gates = encoder.encode(&data).unwrap();
456
457 assert_eq!(gates.len(), 2);
459 }
460
461 #[test]
462 fn test_feature_map() {
463 let feature_map = FeatureMap::new(2, FeatureMapType::ZFeature, 1);
464 let features = vec![0.5, 0.7];
465
466 let gates = feature_map.create_gates(&features).unwrap();
467
468 assert_eq!(gates.len(), 4);
470 }
471
472 #[test]
473 fn test_data_reuploader() {
474 let encoder = DataEncoder::new(EncodingStrategy::Angle, 2);
475 let reuploader = DataReuploader::new(encoder, 3, false);
476
477 let data = vec![0.5, 0.5];
478 let layers = reuploader.create_gates(&data, None).unwrap();
479
480 assert_eq!(layers.len(), 3); assert_eq!(layers[0].len(), 4); }
483}