1use super::{create_entangling_gates, EntanglementPattern, QMLLayer};
7use crate::{
8 error::{QuantRS2Error, QuantRS2Result},
9 gate::GateOp,
10 parametric::{
11 ParametricGate, ParametricRotationX, ParametricRotationY, ParametricRotationZ,
12 SymbolicParameter,
13 },
14 qubit::QubitId,
15};
16use ndarray::{Array1, Array2};
17use num_complex::Complex64;
18use std::f64::consts::PI;
19
20#[derive(Debug, Clone)]
22pub struct Parameter {
23 pub name: String,
24 pub value: f64,
25 pub bounds: Option<(f64, f64)>,
26}
27
28type RXGate = ParametricRotationX;
30type RYGate = ParametricRotationY;
31type RZGate = ParametricRotationZ;
32
33#[derive(Debug, Clone, Copy)]
35struct CNOT {
36 control: QubitId,
37 target: QubitId,
38}
39
40impl GateOp for CNOT {
41 fn name(&self) -> &'static str {
42 "CNOT"
43 }
44
45 fn qubits(&self) -> Vec<QubitId> {
46 vec![self.control, self.target]
47 }
48
49 fn matrix(&self) -> crate::error::QuantRS2Result<Vec<Complex64>> {
50 Ok(vec![
51 Complex64::new(1.0, 0.0),
52 Complex64::new(0.0, 0.0),
53 Complex64::new(0.0, 0.0),
54 Complex64::new(0.0, 0.0),
55 Complex64::new(0.0, 0.0),
56 Complex64::new(1.0, 0.0),
57 Complex64::new(0.0, 0.0),
58 Complex64::new(0.0, 0.0),
59 Complex64::new(0.0, 0.0),
60 Complex64::new(0.0, 0.0),
61 Complex64::new(0.0, 0.0),
62 Complex64::new(1.0, 0.0),
63 Complex64::new(0.0, 0.0),
64 Complex64::new(0.0, 0.0),
65 Complex64::new(1.0, 0.0),
66 Complex64::new(0.0, 0.0),
67 ])
68 }
69
70 fn as_any(&self) -> &dyn std::any::Any {
71 self
72 }
73
74 fn clone_gate(&self) -> Box<dyn GateOp> {
75 Box::new(*self)
76 }
77}
78
79#[derive(Debug, Clone)]
81pub struct RotationLayer {
82 num_qubits: usize,
84 axes: Vec<char>,
86 parameters: Vec<Parameter>,
88 name: String,
90}
91
92impl RotationLayer {
93 pub fn new(num_qubits: usize, axes: Vec<char>) -> QuantRS2Result<Self> {
95 if axes.len() != num_qubits {
96 return Err(QuantRS2Error::InvalidInput(format!(
97 "Expected {} axes, got {}",
98 num_qubits,
99 axes.len()
100 )));
101 }
102
103 for &axis in &axes {
104 if !['X', 'Y', 'Z'].contains(&axis) {
105 return Err(QuantRS2Error::InvalidInput(format!(
106 "Invalid rotation axis: {}",
107 axis
108 )));
109 }
110 }
111
112 let parameters = (0..num_qubits)
113 .map(|i| Parameter {
114 name: format!("rot_{}_{}", axes[i], i),
115 value: 0.0,
116 bounds: Some((-2.0 * PI, 2.0 * PI)),
117 })
118 .collect();
119
120 let name = format!("RotationLayer_{}", axes.iter().collect::<String>());
121
122 Ok(Self {
123 num_qubits,
124 axes,
125 parameters,
126 name,
127 })
128 }
129
130 pub fn uniform(num_qubits: usize, axis: char) -> QuantRS2Result<Self> {
132 Self::new(num_qubits, vec![axis; num_qubits])
133 }
134}
135
136impl QMLLayer for RotationLayer {
137 fn num_qubits(&self) -> usize {
138 self.num_qubits
139 }
140
141 fn parameters(&self) -> &[Parameter] {
142 &self.parameters
143 }
144
145 fn parameters_mut(&mut self) -> &mut [Parameter] {
146 &mut self.parameters
147 }
148
149 fn gates(&self) -> Vec<Box<dyn GateOp>> {
150 self.parameters
151 .iter()
152 .enumerate()
153 .map(|(i, param)| {
154 let qubit = QubitId(i as u32);
155 let gate: Box<dyn GateOp> = match self.axes[i] {
156 'X' => Box::new(ParametricRotationX::new(qubit, param.value)),
157 'Y' => Box::new(ParametricRotationY::new(qubit, param.value)),
158 'Z' => Box::new(ParametricRotationZ::new(qubit, param.value)),
159 _ => unreachable!(),
160 };
161 gate
162 })
163 .collect()
164 }
165
166 fn compute_gradients(
167 &self,
168 _state: &Array1<Complex64>,
169 _loss_gradient: &Array1<Complex64>,
170 ) -> QuantRS2Result<Vec<f64>> {
171 let gradients = vec![0.0; self.parameters.len()];
174 Ok(gradients)
175 }
176
177 fn name(&self) -> &str {
178 &self.name
179 }
180}
181
182#[derive(Debug, Clone)]
184pub struct EntanglingLayer {
185 num_qubits: usize,
187 pattern: EntanglementPattern,
189 parameters: Vec<Parameter>,
191 parameterized: bool,
193 name: String,
195}
196
197impl EntanglingLayer {
198 pub fn new(num_qubits: usize, pattern: EntanglementPattern) -> Self {
200 let name = format!("EntanglingLayer_{:?}", pattern);
201
202 Self {
203 num_qubits,
204 pattern,
205 parameters: vec![],
206 parameterized: false,
207 name,
208 }
209 }
210
211 pub fn parameterized(num_qubits: usize, pattern: EntanglementPattern) -> Self {
213 let pairs = create_entangling_gates(num_qubits, pattern);
214 let parameters = pairs
215 .iter()
216 .enumerate()
217 .map(|(i, (ctrl, tgt))| Parameter {
218 name: format!("entangle_{}_{}", ctrl.0, tgt.0),
219 value: 0.0,
220 bounds: Some((-PI, PI)),
221 })
222 .collect();
223
224 let name = format!("ParameterizedEntanglingLayer_{:?}", pattern);
225
226 Self {
227 num_qubits,
228 pattern,
229 parameters,
230 parameterized: true,
231 name,
232 }
233 }
234}
235
236impl QMLLayer for EntanglingLayer {
237 fn num_qubits(&self) -> usize {
238 self.num_qubits
239 }
240
241 fn parameters(&self) -> &[Parameter] {
242 &self.parameters
243 }
244
245 fn parameters_mut(&mut self) -> &mut [Parameter] {
246 &mut self.parameters
247 }
248
249 fn gates(&self) -> Vec<Box<dyn GateOp>> {
250 let pairs = create_entangling_gates(self.num_qubits, self.pattern);
251
252 if self.parameterized {
253 pairs
255 .iter()
256 .zip(self.parameters.iter())
257 .map(|((ctrl, tgt), param)| {
258 Box::new(CNOT {
260 control: *ctrl,
261 target: *tgt,
262 }) as Box<dyn GateOp>
263 })
264 .collect()
265 } else {
266 pairs
268 .iter()
269 .map(|(ctrl, tgt)| {
270 Box::new(CNOT {
271 control: *ctrl,
272 target: *tgt,
273 }) as Box<dyn GateOp>
274 })
275 .collect()
276 }
277 }
278
279 fn compute_gradients(
280 &self,
281 _state: &Array1<Complex64>,
282 _loss_gradient: &Array1<Complex64>,
283 ) -> QuantRS2Result<Vec<f64>> {
284 if self.parameterized {
285 Ok(vec![0.0; self.parameters.len()])
287 } else {
288 Ok(vec![])
290 }
291 }
292
293 fn name(&self) -> &str {
294 &self.name
295 }
296}
297
298#[derive(Debug, Clone)]
300pub struct StronglyEntanglingLayer {
301 num_qubits: usize,
303 rotation_layers: Vec<RotationLayer>,
305 entangling_layer: EntanglingLayer,
307 total_parameters: usize,
309 name: String,
311}
312
313impl StronglyEntanglingLayer {
314 pub fn new(num_qubits: usize, pattern: EntanglementPattern) -> QuantRS2Result<Self> {
316 let rotation_layers = vec![
317 RotationLayer::uniform(num_qubits, 'X')?,
318 RotationLayer::uniform(num_qubits, 'Y')?,
319 RotationLayer::uniform(num_qubits, 'Z')?,
320 ];
321
322 let entangling_layer = EntanglingLayer::new(num_qubits, pattern);
323
324 let total_parameters = rotation_layers
325 .iter()
326 .map(|layer| layer.parameters().len())
327 .sum::<usize>()
328 + entangling_layer.parameters().len();
329
330 let name = format!("StronglyEntanglingLayer_{:?}", pattern);
331
332 Ok(Self {
333 num_qubits,
334 rotation_layers,
335 entangling_layer,
336 total_parameters,
337 name,
338 })
339 }
340}
341
342impl QMLLayer for StronglyEntanglingLayer {
343 fn num_qubits(&self) -> usize {
344 self.num_qubits
345 }
346
347 fn parameters(&self) -> &[Parameter] {
348 &[]
351 }
352
353 fn parameters_mut(&mut self) -> &mut [Parameter] {
354 &mut []
356 }
357
358 fn set_parameters(&mut self, values: &[f64]) -> QuantRS2Result<()> {
359 if values.len() != self.total_parameters {
360 return Err(QuantRS2Error::InvalidInput(format!(
361 "Expected {} parameters, got {}",
362 self.total_parameters,
363 values.len()
364 )));
365 }
366
367 let mut offset = 0;
368 for layer in &mut self.rotation_layers {
369 let n = layer.parameters().len();
370 layer.set_parameters(&values[offset..offset + n])?;
371 offset += n;
372 }
373
374 if self.entangling_layer.parameterized {
375 self.entangling_layer.set_parameters(&values[offset..])?;
376 }
377
378 Ok(())
379 }
380
381 fn gates(&self) -> Vec<Box<dyn GateOp>> {
382 let mut gates = Vec::new();
383
384 for layer in &self.rotation_layers {
386 gates.extend(layer.gates());
387 }
388
389 gates.extend(self.entangling_layer.gates());
391
392 gates
393 }
394
395 fn compute_gradients(
396 &self,
397 state: &Array1<Complex64>,
398 loss_gradient: &Array1<Complex64>,
399 ) -> QuantRS2Result<Vec<f64>> {
400 let mut gradients = Vec::new();
401
402 for layer in &self.rotation_layers {
403 gradients.extend(layer.compute_gradients(state, loss_gradient)?);
404 }
405
406 if self.entangling_layer.parameterized {
407 gradients.extend(
408 self.entangling_layer
409 .compute_gradients(state, loss_gradient)?,
410 );
411 }
412
413 Ok(gradients)
414 }
415
416 fn name(&self) -> &str {
417 &self.name
418 }
419}
420
421#[derive(Debug, Clone)]
423pub struct HardwareEfficientLayer {
424 num_qubits: usize,
426 single_qubit_gates: Vec<RotationLayer>,
428 entangling_gates: EntanglingLayer,
430 name: String,
432}
433
434impl HardwareEfficientLayer {
435 pub fn new(num_qubits: usize) -> QuantRS2Result<Self> {
437 let single_qubit_gates = vec![
439 RotationLayer::uniform(num_qubits, 'Y')?,
440 RotationLayer::uniform(num_qubits, 'Z')?,
441 ];
442
443 let entangling_gates = EntanglingLayer::new(num_qubits, EntanglementPattern::Linear);
445
446 Ok(Self {
447 num_qubits,
448 single_qubit_gates,
449 entangling_gates,
450 name: "HardwareEfficientLayer".to_string(),
451 })
452 }
453}
454
455impl QMLLayer for HardwareEfficientLayer {
456 fn num_qubits(&self) -> usize {
457 self.num_qubits
458 }
459
460 fn parameters(&self) -> &[Parameter] {
461 &[]
463 }
464
465 fn parameters_mut(&mut self) -> &mut [Parameter] {
466 &mut []
467 }
468
469 fn gates(&self) -> Vec<Box<dyn GateOp>> {
470 let mut gates = Vec::new();
471
472 for layer in &self.single_qubit_gates {
473 gates.extend(layer.gates());
474 }
475
476 gates.extend(self.entangling_gates.gates());
477
478 gates
479 }
480
481 fn compute_gradients(
482 &self,
483 state: &Array1<Complex64>,
484 loss_gradient: &Array1<Complex64>,
485 ) -> QuantRS2Result<Vec<f64>> {
486 let mut gradients = Vec::new();
487
488 for layer in &self.single_qubit_gates {
489 gradients.extend(layer.compute_gradients(state, loss_gradient)?);
490 }
491
492 Ok(gradients)
493 }
494
495 fn name(&self) -> &str {
496 &self.name
497 }
498}
499
500#[derive(Debug, Clone)]
502pub struct QuantumPoolingLayer {
503 input_qubits: usize,
505 output_qubits: usize,
507 strategy: PoolingStrategy,
509 name: String,
511}
512
513#[derive(Debug, Clone, Copy)]
514pub enum PoolingStrategy {
515 TraceOut,
517 MeasureCondition,
519 Parameterized,
521}
522
523impl QuantumPoolingLayer {
524 pub fn new(input_qubits: usize, strategy: PoolingStrategy) -> Self {
526 let output_qubits = input_qubits / 2;
527
528 Self {
529 input_qubits,
530 output_qubits,
531 strategy,
532 name: format!("QuantumPoolingLayer_{:?}", strategy),
533 }
534 }
535}
536
537impl QMLLayer for QuantumPoolingLayer {
538 fn num_qubits(&self) -> usize {
539 self.input_qubits
540 }
541
542 fn parameters(&self) -> &[Parameter] {
543 &[]
544 }
545
546 fn parameters_mut(&mut self) -> &mut [Parameter] {
547 &mut []
548 }
549
550 fn gates(&self) -> Vec<Box<dyn GateOp>> {
551 vec![]
554 }
555
556 fn compute_gradients(
557 &self,
558 _state: &Array1<Complex64>,
559 _loss_gradient: &Array1<Complex64>,
560 ) -> QuantRS2Result<Vec<f64>> {
561 Ok(vec![])
562 }
563
564 fn name(&self) -> &str {
565 &self.name
566 }
567}
568
569#[cfg(test)]
570mod tests {
571 use super::*;
572
573 #[test]
574 fn test_rotation_layer() {
575 let layer = RotationLayer::uniform(3, 'X').unwrap();
576 assert_eq!(layer.num_qubits(), 3);
577 assert_eq!(layer.parameters().len(), 3);
578
579 let gates = layer.gates();
580 assert_eq!(gates.len(), 3);
581 }
582
583 #[test]
584 fn test_entangling_layer() {
585 let layer = EntanglingLayer::new(4, EntanglementPattern::Linear);
586 assert_eq!(layer.num_qubits(), 4);
587
588 let gates = layer.gates();
589 assert_eq!(gates.len(), 3); }
591
592 #[test]
593 fn test_strongly_entangling_layer() {
594 let layer = StronglyEntanglingLayer::new(2, EntanglementPattern::Full).unwrap();
595 assert_eq!(layer.num_qubits(), 2);
596
597 let gates = layer.gates();
598 assert_eq!(gates.len(), 7); }
600
601 #[test]
602 fn test_hardware_efficient_layer() {
603 let layer = HardwareEfficientLayer::new(3).unwrap();
604 assert_eq!(layer.num_qubits(), 3);
605
606 let gates = layer.gates();
607 assert_eq!(gates.len(), 8); }
609}