quantrs2_ml/torchquantum/
layer.rs

1//! Pre-built quantum layer templates (TorchQuantum-compatible)
2//!
3//! This module provides various quantum layer templates:
4//! - TQOp1QAllLayer: Apply single-qubit operation to all wires
5//! - TQOp2QAllLayer: Apply two-qubit operation to pairs of wires
6//! - TQBarrenLayer: Barren plateau layer
7//! - TQRXYZCXLayer: RX, RY, RZ, CNOT layer
8//! - TQFarhiLayer: QAOA-style mixer layer
9//! - TQMaxwellLayer: Hardware-efficient ansatz
10//! - TQSethLayer: Simple efficient ansatz
11//! - TQStrongEntanglingLayer: Strong entanglement with varying patterns
12
13use super::{
14    gates::{
15        TQHadamard, TQPauliX, TQPauliY, TQPauliZ, TQRx, TQRy, TQRz, TQCNOT, TQCRX, TQCRY, TQCRZ,
16        TQCZ, TQRXX, TQRYY, TQRZX, TQRZZ, TQS, TQSWAP, TQSX, TQT,
17    },
18    CType, TQDevice, TQModule, TQOperator, TQParameter,
19};
20use crate::error::{MLError, Result};
21use scirs2_core::ndarray::Array2;
22
23/// Apply single-qubit operation to all wires
24pub struct TQOp1QAllLayer {
25    /// Number of wires
26    pub n_wires: usize,
27    /// Gate type name
28    pub op_name: String,
29    /// Whether gates have parameters
30    pub has_params: bool,
31    /// Whether parameters are trainable
32    pub trainable: bool,
33    /// Gate instances for each wire
34    gates: Vec<Box<dyn TQOperator>>,
35    static_mode: bool,
36}
37
38impl TQOp1QAllLayer {
39    pub fn new(
40        op_name: impl Into<String>,
41        n_wires: usize,
42        has_params: bool,
43        trainable: bool,
44    ) -> Self {
45        let op_name = op_name.into();
46        let gates: Vec<Box<dyn TQOperator>> = (0..n_wires)
47            .map(|_| create_single_qubit_gate(&op_name, has_params, trainable))
48            .collect();
49
50        Self {
51            n_wires,
52            op_name,
53            has_params,
54            trainable,
55            gates,
56            static_mode: false,
57        }
58    }
59
60    /// Create RX layer
61    pub fn rx(n_wires: usize, trainable: bool) -> Self {
62        Self::new("rx", n_wires, true, trainable)
63    }
64
65    /// Create RY layer
66    pub fn ry(n_wires: usize, trainable: bool) -> Self {
67        Self::new("ry", n_wires, true, trainable)
68    }
69
70    /// Create RZ layer
71    pub fn rz(n_wires: usize, trainable: bool) -> Self {
72        Self::new("rz", n_wires, true, trainable)
73    }
74
75    /// Create Hadamard layer
76    pub fn hadamard(n_wires: usize) -> Self {
77        Self::new("hadamard", n_wires, false, false)
78    }
79}
80
81impl TQModule for TQOp1QAllLayer {
82    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
83        for (wire, gate) in self.gates.iter_mut().enumerate() {
84            gate.apply(qdev, &[wire])?;
85        }
86        Ok(())
87    }
88
89    fn parameters(&self) -> Vec<TQParameter> {
90        self.gates.iter().flat_map(|g| g.parameters()).collect()
91    }
92
93    fn n_wires(&self) -> Option<usize> {
94        Some(self.n_wires)
95    }
96
97    fn set_n_wires(&mut self, n_wires: usize) {
98        self.n_wires = n_wires;
99    }
100
101    fn is_static_mode(&self) -> bool {
102        self.static_mode
103    }
104
105    fn static_on(&mut self) {
106        self.static_mode = true;
107        for gate in &mut self.gates {
108            gate.static_on();
109        }
110    }
111
112    fn static_off(&mut self) {
113        self.static_mode = false;
114        for gate in &mut self.gates {
115            gate.static_off();
116        }
117    }
118
119    fn name(&self) -> &str {
120        "Op1QAllLayer"
121    }
122
123    fn zero_grad(&mut self) {
124        for gate in &mut self.gates {
125            gate.zero_grad();
126        }
127    }
128}
129
130/// Apply two-qubit operation to pairs of wires
131pub struct TQOp2QAllLayer {
132    /// Number of wires
133    pub n_wires: usize,
134    /// Gate type name
135    pub op_name: String,
136    /// Whether gates have parameters
137    pub has_params: bool,
138    /// Whether parameters are trainable
139    pub trainable: bool,
140    /// Jump between wire pairs (1 = nearest neighbor)
141    pub jump: usize,
142    /// Whether to connect last qubit to first (circular)
143    pub circular: bool,
144    /// Gate instances
145    gates: Vec<Box<dyn TQOperator>>,
146    static_mode: bool,
147}
148
149impl TQOp2QAllLayer {
150    pub fn new(
151        op_name: impl Into<String>,
152        n_wires: usize,
153        has_params: bool,
154        trainable: bool,
155        jump: usize,
156        circular: bool,
157    ) -> Self {
158        let op_name = op_name.into();
159
160        // Calculate number of gate pairs
161        let n_pairs = if circular {
162            n_wires
163        } else {
164            n_wires.saturating_sub(jump)
165        };
166
167        let gates: Vec<Box<dyn TQOperator>> = (0..n_pairs)
168            .map(|_| create_two_qubit_gate(&op_name, has_params, trainable))
169            .collect();
170
171        Self {
172            n_wires,
173            op_name,
174            has_params,
175            trainable,
176            jump,
177            circular,
178            gates,
179            static_mode: false,
180        }
181    }
182
183    /// Create CNOT layer
184    pub fn cnot(n_wires: usize, circular: bool) -> Self {
185        Self::new("cnot", n_wires, false, false, 1, circular)
186    }
187
188    /// Create CZ layer
189    pub fn cz(n_wires: usize, circular: bool) -> Self {
190        Self::new("cz", n_wires, false, false, 1, circular)
191    }
192
193    /// Create SWAP layer
194    pub fn swap(n_wires: usize, circular: bool) -> Self {
195        Self::new("swap", n_wires, false, false, 1, circular)
196    }
197}
198
199impl TQModule for TQOp2QAllLayer {
200    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
201        let n_pairs = if self.circular {
202            self.n_wires
203        } else {
204            self.n_wires.saturating_sub(self.jump)
205        };
206
207        for i in 0..n_pairs {
208            let wire0 = i;
209            let wire1 = (i + self.jump) % self.n_wires;
210
211            if i < self.gates.len() {
212                self.gates[i].apply(qdev, &[wire0, wire1])?;
213            }
214        }
215        Ok(())
216    }
217
218    fn parameters(&self) -> Vec<TQParameter> {
219        self.gates.iter().flat_map(|g| g.parameters()).collect()
220    }
221
222    fn n_wires(&self) -> Option<usize> {
223        Some(self.n_wires)
224    }
225
226    fn set_n_wires(&mut self, n_wires: usize) {
227        self.n_wires = n_wires;
228    }
229
230    fn is_static_mode(&self) -> bool {
231        self.static_mode
232    }
233
234    fn static_on(&mut self) {
235        self.static_mode = true;
236        for gate in &mut self.gates {
237            gate.static_on();
238        }
239    }
240
241    fn static_off(&mut self) {
242        self.static_mode = false;
243        for gate in &mut self.gates {
244            gate.static_off();
245        }
246    }
247
248    fn name(&self) -> &str {
249        "Op2QAllLayer"
250    }
251
252    fn zero_grad(&mut self) {
253        for gate in &mut self.gates {
254            gate.zero_grad();
255        }
256    }
257}
258
259/// Layer configuration
260#[derive(Debug, Clone)]
261pub struct TQLayerConfig {
262    pub n_wires: usize,
263    pub n_blocks: usize,
264    pub n_layers_per_block: Option<usize>,
265}
266
267impl TQLayerConfig {
268    pub fn new(n_wires: usize, n_blocks: usize) -> Self {
269        Self {
270            n_wires,
271            n_blocks,
272            n_layers_per_block: None,
273        }
274    }
275
276    pub fn with_layers_per_block(mut self, n: usize) -> Self {
277        self.n_layers_per_block = Some(n);
278        self
279    }
280}
281
282/// Barren plateau layer (from TorchQuantum)
283/// Pattern: H -> (RX -> RY -> RZ -> CZ) * n_blocks
284pub struct TQBarrenLayer {
285    config: TQLayerConfig,
286    layers: Vec<Box<dyn TQModule>>,
287    static_mode: bool,
288}
289
290impl TQBarrenLayer {
291    pub fn new(config: TQLayerConfig) -> Self {
292        let mut layers: Vec<Box<dyn TQModule>> = Vec::new();
293
294        // Initial Hadamard layer
295        layers.push(Box::new(TQOp1QAllLayer::hadamard(config.n_wires)));
296
297        // Blocks
298        for _ in 0..config.n_blocks {
299            layers.push(Box::new(TQOp1QAllLayer::rx(config.n_wires, true)));
300            layers.push(Box::new(TQOp1QAllLayer::ry(config.n_wires, true)));
301            layers.push(Box::new(TQOp1QAllLayer::rz(config.n_wires, true)));
302            layers.push(Box::new(TQOp2QAllLayer::cz(config.n_wires, false)));
303        }
304
305        Self {
306            config,
307            layers,
308            static_mode: false,
309        }
310    }
311}
312
313impl TQModule for TQBarrenLayer {
314    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
315        for layer in &mut self.layers {
316            layer.forward(qdev)?;
317        }
318        Ok(())
319    }
320
321    fn parameters(&self) -> Vec<TQParameter> {
322        self.layers.iter().flat_map(|l| l.parameters()).collect()
323    }
324
325    fn n_wires(&self) -> Option<usize> {
326        Some(self.config.n_wires)
327    }
328
329    fn set_n_wires(&mut self, n_wires: usize) {
330        self.config.n_wires = n_wires;
331    }
332
333    fn is_static_mode(&self) -> bool {
334        self.static_mode
335    }
336
337    fn static_on(&mut self) {
338        self.static_mode = true;
339        for layer in &mut self.layers {
340            layer.static_on();
341        }
342    }
343
344    fn static_off(&mut self) {
345        self.static_mode = false;
346        for layer in &mut self.layers {
347            layer.static_off();
348        }
349    }
350
351    fn name(&self) -> &str {
352        "BarrenLayer"
353    }
354
355    fn zero_grad(&mut self) {
356        for layer in &mut self.layers {
357            layer.zero_grad();
358        }
359    }
360}
361
362/// RXYZCX layer (from TorchQuantum)
363/// Pattern: (RX -> RY -> RZ -> CNOT) * n_blocks
364pub struct TQRXYZCXLayer {
365    config: TQLayerConfig,
366    layers: Vec<Box<dyn TQModule>>,
367    static_mode: bool,
368}
369
370impl TQRXYZCXLayer {
371    pub fn new(config: TQLayerConfig) -> Self {
372        let mut layers: Vec<Box<dyn TQModule>> = Vec::new();
373
374        for _ in 0..config.n_blocks {
375            layers.push(Box::new(TQOp1QAllLayer::rx(config.n_wires, true)));
376            layers.push(Box::new(TQOp1QAllLayer::ry(config.n_wires, true)));
377            layers.push(Box::new(TQOp1QAllLayer::rz(config.n_wires, true)));
378            layers.push(Box::new(TQOp2QAllLayer::cnot(config.n_wires, true)));
379        }
380
381        Self {
382            config,
383            layers,
384            static_mode: false,
385        }
386    }
387}
388
389impl TQModule for TQRXYZCXLayer {
390    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
391        for layer in &mut self.layers {
392            layer.forward(qdev)?;
393        }
394        Ok(())
395    }
396
397    fn parameters(&self) -> Vec<TQParameter> {
398        self.layers.iter().flat_map(|l| l.parameters()).collect()
399    }
400
401    fn n_wires(&self) -> Option<usize> {
402        Some(self.config.n_wires)
403    }
404
405    fn set_n_wires(&mut self, n_wires: usize) {
406        self.config.n_wires = n_wires;
407    }
408
409    fn is_static_mode(&self) -> bool {
410        self.static_mode
411    }
412
413    fn static_on(&mut self) {
414        self.static_mode = true;
415        for layer in &mut self.layers {
416            layer.static_on();
417        }
418    }
419
420    fn static_off(&mut self) {
421        self.static_mode = false;
422        for layer in &mut self.layers {
423            layer.static_off();
424        }
425    }
426
427    fn name(&self) -> &str {
428        "RXYZCXLayer"
429    }
430
431    fn zero_grad(&mut self) {
432        for layer in &mut self.layers {
433            layer.zero_grad();
434        }
435    }
436}
437
438/// Helper to create single-qubit gates
439fn create_single_qubit_gate(name: &str, has_params: bool, trainable: bool) -> Box<dyn TQOperator> {
440    match name.to_lowercase().as_str() {
441        "rx" => Box::new(TQRx::new(has_params, trainable)),
442        "ry" => Box::new(TQRy::new(has_params, trainable)),
443        "rz" => Box::new(TQRz::new(has_params, trainable)),
444        "h" | "hadamard" => Box::new(TQHadamard::new()),
445        "x" | "paulix" => Box::new(TQPauliX::new()),
446        "y" | "pauliy" => Box::new(TQPauliY::new()),
447        "z" | "pauliz" => Box::new(TQPauliZ::new()),
448        "s" => Box::new(TQS::new()),
449        "t" => Box::new(TQT::new()),
450        "sx" => Box::new(TQSX::new()),
451        _ => Box::new(TQRy::new(has_params, trainable)), // Default
452    }
453}
454
455/// Helper to create two-qubit gates
456fn create_two_qubit_gate(name: &str, has_params: bool, trainable: bool) -> Box<dyn TQOperator> {
457    match name.to_lowercase().as_str() {
458        "cnot" | "cx" => Box::new(TQCNOT::new()),
459        "cz" => Box::new(TQCZ::new()),
460        "swap" => Box::new(TQSWAP::new()),
461        // Parameterized two-qubit gates
462        "rxx" => Box::new(TQRXX::new(has_params, trainable)),
463        "ryy" => Box::new(TQRYY::new(has_params, trainable)),
464        "rzz" => Box::new(TQRZZ::new(has_params, trainable)),
465        "rzx" => Box::new(TQRZX::new(has_params, trainable)),
466        // Controlled rotation gates
467        "crx" => Box::new(TQCRX::new(has_params, trainable)),
468        "cry" => Box::new(TQCRY::new(has_params, trainable)),
469        "crz" => Box::new(TQCRZ::new(has_params, trainable)),
470        _ => Box::new(TQCNOT::new()), // Default
471    }
472}
473
474/// Farhi layer (from TorchQuantum)
475/// Pattern: (RZX -> RXX) * n_blocks with circular connectivity
476/// Implements the QAOA-style mixer for variational quantum circuits
477pub struct TQFarhiLayer {
478    config: TQLayerConfig,
479    layers: Vec<Box<dyn TQModule>>,
480    static_mode: bool,
481}
482
483impl TQFarhiLayer {
484    pub fn new(config: TQLayerConfig) -> Self {
485        let mut layers: Vec<Box<dyn TQModule>> = Vec::new();
486
487        for _ in 0..config.n_blocks {
488            // RZX layer with circular connectivity
489            layers.push(Box::new(TQOp2QAllLayer::new(
490                "rzx",
491                config.n_wires,
492                true,
493                true,
494                1,
495                true, // circular
496            )));
497            // RXX layer with circular connectivity
498            layers.push(Box::new(TQOp2QAllLayer::new(
499                "rxx",
500                config.n_wires,
501                true,
502                true,
503                1,
504                true, // circular
505            )));
506        }
507
508        Self {
509            config,
510            layers,
511            static_mode: false,
512        }
513    }
514}
515
516impl TQModule for TQFarhiLayer {
517    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
518        for layer in &mut self.layers {
519            layer.forward(qdev)?;
520        }
521        Ok(())
522    }
523
524    fn parameters(&self) -> Vec<TQParameter> {
525        self.layers.iter().flat_map(|l| l.parameters()).collect()
526    }
527
528    fn n_wires(&self) -> Option<usize> {
529        Some(self.config.n_wires)
530    }
531
532    fn set_n_wires(&mut self, n_wires: usize) {
533        self.config.n_wires = n_wires;
534    }
535
536    fn is_static_mode(&self) -> bool {
537        self.static_mode
538    }
539
540    fn static_on(&mut self) {
541        self.static_mode = true;
542        for layer in &mut self.layers {
543            layer.static_on();
544        }
545    }
546
547    fn static_off(&mut self) {
548        self.static_mode = false;
549        for layer in &mut self.layers {
550            layer.static_off();
551        }
552    }
553
554    fn name(&self) -> &str {
555        "FarhiLayer"
556    }
557
558    fn zero_grad(&mut self) {
559        for layer in &mut self.layers {
560            layer.zero_grad();
561        }
562    }
563}
564
565/// Maxwell layer (from TorchQuantum)
566/// Pattern: (RX -> S -> CNOT -> RY -> T -> SWAP -> RZ -> H -> CNOT) * n_blocks
567/// A hardware-efficient ansatz with diverse gate types
568pub struct TQMaxwellLayer {
569    config: TQLayerConfig,
570    layers: Vec<Box<dyn TQModule>>,
571    static_mode: bool,
572}
573
574impl TQMaxwellLayer {
575    pub fn new(config: TQLayerConfig) -> Self {
576        let mut layers: Vec<Box<dyn TQModule>> = Vec::new();
577
578        for _ in 0..config.n_blocks {
579            // First block: RX -> S -> CNOT
580            layers.push(Box::new(TQOp1QAllLayer::rx(config.n_wires, true)));
581            layers.push(Box::new(TQOp1QAllLayer::new(
582                "s",
583                config.n_wires,
584                false,
585                false,
586            )));
587            layers.push(Box::new(TQOp2QAllLayer::new(
588                "cnot",
589                config.n_wires,
590                false,
591                false,
592                1,
593                true,
594            )));
595
596            // Second block: RY -> T -> SWAP
597            layers.push(Box::new(TQOp1QAllLayer::ry(config.n_wires, true)));
598            layers.push(Box::new(TQOp1QAllLayer::new(
599                "t",
600                config.n_wires,
601                false,
602                false,
603            )));
604            layers.push(Box::new(TQOp2QAllLayer::new(
605                "swap",
606                config.n_wires,
607                false,
608                false,
609                1,
610                true,
611            )));
612
613            // Third block: RZ -> H -> CNOT
614            layers.push(Box::new(TQOp1QAllLayer::rz(config.n_wires, true)));
615            layers.push(Box::new(TQOp1QAllLayer::hadamard(config.n_wires)));
616            layers.push(Box::new(TQOp2QAllLayer::new(
617                "cnot",
618                config.n_wires,
619                false,
620                false,
621                1,
622                true,
623            )));
624        }
625
626        Self {
627            config,
628            layers,
629            static_mode: false,
630        }
631    }
632}
633
634impl TQModule for TQMaxwellLayer {
635    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
636        for layer in &mut self.layers {
637            layer.forward(qdev)?;
638        }
639        Ok(())
640    }
641
642    fn parameters(&self) -> Vec<TQParameter> {
643        self.layers.iter().flat_map(|l| l.parameters()).collect()
644    }
645
646    fn n_wires(&self) -> Option<usize> {
647        Some(self.config.n_wires)
648    }
649
650    fn set_n_wires(&mut self, n_wires: usize) {
651        self.config.n_wires = n_wires;
652    }
653
654    fn is_static_mode(&self) -> bool {
655        self.static_mode
656    }
657
658    fn static_on(&mut self) {
659        self.static_mode = true;
660        for layer in &mut self.layers {
661            layer.static_on();
662        }
663    }
664
665    fn static_off(&mut self) {
666        self.static_mode = false;
667        for layer in &mut self.layers {
668            layer.static_off();
669        }
670    }
671
672    fn name(&self) -> &str {
673        "MaxwellLayer"
674    }
675
676    fn zero_grad(&mut self) {
677        for layer in &mut self.layers {
678            layer.zero_grad();
679        }
680    }
681}
682
683/// Seth layer (from TorchQuantum)
684/// Pattern: (RY -> RZ -> CZ) * n_blocks
685/// Simple efficient ansatz similar to EfficientSU2
686pub struct TQSethLayer {
687    config: TQLayerConfig,
688    layers: Vec<Box<dyn TQModule>>,
689    static_mode: bool,
690}
691
692impl TQSethLayer {
693    pub fn new(config: TQLayerConfig) -> Self {
694        let mut layers: Vec<Box<dyn TQModule>> = Vec::new();
695
696        for _ in 0..config.n_blocks {
697            layers.push(Box::new(TQOp1QAllLayer::ry(config.n_wires, true)));
698            layers.push(Box::new(TQOp1QAllLayer::rz(config.n_wires, true)));
699            layers.push(Box::new(TQOp2QAllLayer::cz(config.n_wires, true)));
700        }
701
702        Self {
703            config,
704            layers,
705            static_mode: false,
706        }
707    }
708}
709
710impl TQModule for TQSethLayer {
711    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
712        for layer in &mut self.layers {
713            layer.forward(qdev)?;
714        }
715        Ok(())
716    }
717
718    fn parameters(&self) -> Vec<TQParameter> {
719        self.layers.iter().flat_map(|l| l.parameters()).collect()
720    }
721
722    fn n_wires(&self) -> Option<usize> {
723        Some(self.config.n_wires)
724    }
725
726    fn set_n_wires(&mut self, n_wires: usize) {
727        self.config.n_wires = n_wires;
728    }
729
730    fn is_static_mode(&self) -> bool {
731        self.static_mode
732    }
733
734    fn static_on(&mut self) {
735        self.static_mode = true;
736        for layer in &mut self.layers {
737            layer.static_on();
738        }
739    }
740
741    fn static_off(&mut self) {
742        self.static_mode = false;
743        for layer in &mut self.layers {
744            layer.static_off();
745        }
746    }
747
748    fn name(&self) -> &str {
749        "SethLayer"
750    }
751
752    fn zero_grad(&mut self) {
753        for layer in &mut self.layers {
754            layer.zero_grad();
755        }
756    }
757}
758
759/// Strong entangling layer (from TorchQuantum)
760/// Pattern: (RX -> RY -> RZ -> CNOT) * n_blocks with varying entanglement patterns
761/// Each block has different CNOT ranges for stronger entanglement
762pub struct TQStrongEntanglingLayer {
763    config: TQLayerConfig,
764    layers: Vec<Box<dyn TQModule>>,
765    static_mode: bool,
766}
767
768impl TQStrongEntanglingLayer {
769    pub fn new(config: TQLayerConfig) -> Self {
770        let mut layers: Vec<Box<dyn TQModule>> = Vec::new();
771
772        for block_idx in 0..config.n_blocks {
773            // Rotation layers
774            layers.push(Box::new(TQOp1QAllLayer::rx(config.n_wires, true)));
775            layers.push(Box::new(TQOp1QAllLayer::ry(config.n_wires, true)));
776            layers.push(Box::new(TQOp1QAllLayer::rz(config.n_wires, true)));
777
778            // CNOT entanglement with varying range
779            let jump = (block_idx % config.n_wires) + 1;
780            layers.push(Box::new(TQOp2QAllLayer::new(
781                "cnot",
782                config.n_wires,
783                false,
784                false,
785                jump,
786                true, // circular
787            )));
788        }
789
790        Self {
791            config,
792            layers,
793            static_mode: false,
794        }
795    }
796}
797
798impl TQModule for TQStrongEntanglingLayer {
799    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
800        for layer in &mut self.layers {
801            layer.forward(qdev)?;
802        }
803        Ok(())
804    }
805
806    fn parameters(&self) -> Vec<TQParameter> {
807        self.layers.iter().flat_map(|l| l.parameters()).collect()
808    }
809
810    fn n_wires(&self) -> Option<usize> {
811        Some(self.config.n_wires)
812    }
813
814    fn set_n_wires(&mut self, n_wires: usize) {
815        self.config.n_wires = n_wires;
816    }
817
818    fn is_static_mode(&self) -> bool {
819        self.static_mode
820    }
821
822    fn static_on(&mut self) {
823        self.static_mode = true;
824        for layer in &mut self.layers {
825            layer.static_on();
826        }
827    }
828
829    fn static_off(&mut self) {
830        self.static_mode = false;
831        for layer in &mut self.layers {
832            layer.static_off();
833        }
834    }
835
836    fn name(&self) -> &str {
837        "StrongEntanglingLayer"
838    }
839
840    fn zero_grad(&mut self) {
841        for layer in &mut self.layers {
842            layer.zero_grad();
843        }
844    }
845}
846
847/// Quantum Fourier Transform (QFT) layer
848/// Implements the quantum Fourier transform on n qubits
849pub struct TQQFTLayer {
850    n_wires: usize,
851    wires: Vec<usize>,
852    do_swaps: bool,
853    inverse: bool,
854    static_mode: bool,
855}
856
857impl TQQFTLayer {
858    pub fn new(n_wires: usize, do_swaps: bool, inverse: bool) -> Self {
859        Self {
860            n_wires,
861            wires: (0..n_wires).collect(),
862            do_swaps,
863            inverse,
864            static_mode: false,
865        }
866    }
867
868    /// Create a standard QFT layer
869    pub fn standard(n_wires: usize) -> Self {
870        Self::new(n_wires, true, false)
871    }
872
873    /// Create an inverse QFT layer
874    pub fn inverse(n_wires: usize) -> Self {
875        Self::new(n_wires, true, true)
876    }
877
878    /// Create a QFT layer without final swaps
879    pub fn no_swaps(n_wires: usize) -> Self {
880        Self::new(n_wires, false, false)
881    }
882
883    /// Create a QFT layer with custom wires
884    pub fn with_wires(wires: Vec<usize>, do_swaps: bool, inverse: bool) -> Self {
885        let n_wires = wires.len();
886        Self {
887            n_wires,
888            wires,
889            do_swaps,
890            inverse,
891            static_mode: false,
892        }
893    }
894}
895
896impl TQModule for TQQFTLayer {
897    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
898        use super::gates::{TQHadamard, TQCU1, TQSWAP};
899        use std::f64::consts::PI;
900
901        if self.inverse {
902            // Inverse QFT: swaps first, then reversed CU1 and H operations
903            if self.do_swaps {
904                for wire in 0..(self.n_wires / 2) {
905                    let mut swap_gate = TQSWAP::new();
906                    swap_gate.apply(
907                        qdev,
908                        &[self.wires[wire], self.wires[self.n_wires - wire - 1]],
909                    )?;
910                }
911            }
912
913            for top_wire in (0..self.n_wires).rev() {
914                for wire in ((top_wire + 1)..self.n_wires).rev() {
915                    let lam = -PI / (1 << (wire - top_wire)) as f64;
916                    let mut cu1_gate = TQCU1::new(true, false);
917                    cu1_gate.apply_with_params(
918                        qdev,
919                        &[self.wires[wire], self.wires[top_wire]],
920                        Some(&[lam]),
921                    )?;
922                }
923                let mut h_gate = TQHadamard::new();
924                h_gate.apply(qdev, &[self.wires[top_wire]])?;
925            }
926        } else {
927            // Standard QFT: H and CU1 operations, then swaps
928            for top_wire in 0..self.n_wires {
929                let mut h_gate = TQHadamard::new();
930                h_gate.apply(qdev, &[self.wires[top_wire]])?;
931
932                for wire in (top_wire + 1)..self.n_wires {
933                    let lam = PI / (1 << (wire - top_wire)) as f64;
934                    let mut cu1_gate = TQCU1::new(true, false);
935                    cu1_gate.apply_with_params(
936                        qdev,
937                        &[self.wires[wire], self.wires[top_wire]],
938                        Some(&[lam]),
939                    )?;
940                }
941            }
942
943            if self.do_swaps {
944                for wire in 0..(self.n_wires / 2) {
945                    let mut swap_gate = TQSWAP::new();
946                    swap_gate.apply(
947                        qdev,
948                        &[self.wires[wire], self.wires[self.n_wires - wire - 1]],
949                    )?;
950                }
951            }
952        }
953
954        Ok(())
955    }
956
957    fn parameters(&self) -> Vec<TQParameter> {
958        Vec::new() // QFT has no trainable parameters
959    }
960
961    fn n_wires(&self) -> Option<usize> {
962        Some(self.n_wires)
963    }
964
965    fn set_n_wires(&mut self, n_wires: usize) {
966        self.n_wires = n_wires;
967        self.wires = (0..n_wires).collect();
968    }
969
970    fn is_static_mode(&self) -> bool {
971        self.static_mode
972    }
973
974    fn static_on(&mut self) {
975        self.static_mode = true;
976    }
977
978    fn static_off(&mut self) {
979        self.static_mode = false;
980    }
981
982    fn name(&self) -> &str {
983        if self.inverse {
984            "InverseQFTLayer"
985        } else {
986            "QFTLayer"
987        }
988    }
989}
990
991/// Entanglement pattern type
992#[derive(Debug, Clone, Copy, PartialEq)]
993pub enum EntanglementPattern {
994    /// Linear: (0,1), (1,2), (2,3), ...
995    Linear,
996    /// Reverse linear: (n-1,n-2), (n-2,n-3), ...
997    ReverseLinear,
998    /// Circular: Linear + (n-1, 0)
999    Circular,
1000    /// Full: All-to-all connectivity
1001    Full,
1002}
1003
1004/// TwoLocal layer (from TorchQuantum)
1005/// Generic hardware-efficient ansatz with configurable rotation and entanglement gates
1006pub struct TQTwoLocalLayer {
1007    n_wires: usize,
1008    rotation_ops: Vec<String>,
1009    entanglement_ops: Vec<String>,
1010    entanglement_pattern: EntanglementPattern,
1011    reps: usize,
1012    skip_final_rotation: bool,
1013    layers: Vec<Box<dyn TQModule>>,
1014    static_mode: bool,
1015}
1016
1017impl TQTwoLocalLayer {
1018    pub fn new(
1019        n_wires: usize,
1020        rotation_ops: Vec<&str>,
1021        entanglement_ops: Vec<&str>,
1022        entanglement_pattern: EntanglementPattern,
1023        reps: usize,
1024        skip_final_rotation: bool,
1025    ) -> Self {
1026        let rotation_ops: Vec<String> = rotation_ops.iter().map(|s| s.to_string()).collect();
1027        let entanglement_ops: Vec<String> =
1028            entanglement_ops.iter().map(|s| s.to_string()).collect();
1029
1030        let layers = Self::build_layers(
1031            n_wires,
1032            &rotation_ops,
1033            &entanglement_ops,
1034            entanglement_pattern,
1035            reps,
1036            skip_final_rotation,
1037        );
1038
1039        Self {
1040            n_wires,
1041            rotation_ops,
1042            entanglement_ops,
1043            entanglement_pattern,
1044            reps,
1045            skip_final_rotation,
1046            layers,
1047            static_mode: false,
1048        }
1049    }
1050
1051    fn build_layers(
1052        n_wires: usize,
1053        rotation_ops: &[String],
1054        entanglement_ops: &[String],
1055        entanglement_pattern: EntanglementPattern,
1056        reps: usize,
1057        skip_final_rotation: bool,
1058    ) -> Vec<Box<dyn TQModule>> {
1059        let mut layers: Vec<Box<dyn TQModule>> = Vec::new();
1060
1061        let circular = matches!(entanglement_pattern, EntanglementPattern::Circular);
1062
1063        for _ in 0..reps {
1064            // Rotation layer
1065            for op in rotation_ops {
1066                layers.push(Box::new(TQOp1QAllLayer::new(op, n_wires, true, true)));
1067            }
1068
1069            // Entanglement layer
1070            if entanglement_pattern == EntanglementPattern::Full {
1071                // Full connectivity - all pairs
1072                for op in entanglement_ops {
1073                    layers.push(Box::new(TQOp2QDenseLayer::new(op, n_wires)));
1074                }
1075            } else {
1076                for op in entanglement_ops {
1077                    layers.push(Box::new(TQOp2QAllLayer::new(
1078                        op, n_wires, false, false, 1, circular,
1079                    )));
1080                }
1081            }
1082        }
1083
1084        // Final rotation layer
1085        if !skip_final_rotation {
1086            for op in rotation_ops {
1087                layers.push(Box::new(TQOp1QAllLayer::new(op, n_wires, true, true)));
1088            }
1089        }
1090
1091        layers
1092    }
1093}
1094
1095impl TQModule for TQTwoLocalLayer {
1096    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
1097        for layer in &mut self.layers {
1098            layer.forward(qdev)?;
1099        }
1100        Ok(())
1101    }
1102
1103    fn parameters(&self) -> Vec<TQParameter> {
1104        self.layers.iter().flat_map(|l| l.parameters()).collect()
1105    }
1106
1107    fn n_wires(&self) -> Option<usize> {
1108        Some(self.n_wires)
1109    }
1110
1111    fn set_n_wires(&mut self, n_wires: usize) {
1112        self.n_wires = n_wires;
1113        self.layers = Self::build_layers(
1114            n_wires,
1115            &self.rotation_ops,
1116            &self.entanglement_ops,
1117            self.entanglement_pattern,
1118            self.reps,
1119            self.skip_final_rotation,
1120        );
1121    }
1122
1123    fn is_static_mode(&self) -> bool {
1124        self.static_mode
1125    }
1126
1127    fn static_on(&mut self) {
1128        self.static_mode = true;
1129        for layer in &mut self.layers {
1130            layer.static_on();
1131        }
1132    }
1133
1134    fn static_off(&mut self) {
1135        self.static_mode = false;
1136        for layer in &mut self.layers {
1137            layer.static_off();
1138        }
1139    }
1140
1141    fn name(&self) -> &str {
1142        "TwoLocalLayer"
1143    }
1144
1145    fn zero_grad(&mut self) {
1146        for layer in &mut self.layers {
1147            layer.zero_grad();
1148        }
1149    }
1150}
1151
1152/// EfficientSU2 layer (from TorchQuantum/Qiskit)
1153/// Hardware-efficient ansatz with RY-RZ rotations and CX entanglement
1154pub struct TQEfficientSU2Layer {
1155    inner: TQTwoLocalLayer,
1156}
1157
1158impl TQEfficientSU2Layer {
1159    pub fn new(n_wires: usize, reps: usize, entanglement: EntanglementPattern) -> Self {
1160        Self {
1161            inner: TQTwoLocalLayer::new(
1162                n_wires,
1163                vec!["ry", "rz"],
1164                vec!["cnot"],
1165                entanglement,
1166                reps,
1167                false,
1168            ),
1169        }
1170    }
1171
1172    /// Create with default reverse linear entanglement
1173    pub fn default_entanglement(n_wires: usize, reps: usize) -> Self {
1174        Self::new(n_wires, reps, EntanglementPattern::ReverseLinear)
1175    }
1176}
1177
1178impl TQModule for TQEfficientSU2Layer {
1179    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
1180        self.inner.forward(qdev)
1181    }
1182
1183    fn parameters(&self) -> Vec<TQParameter> {
1184        self.inner.parameters()
1185    }
1186
1187    fn n_wires(&self) -> Option<usize> {
1188        self.inner.n_wires()
1189    }
1190
1191    fn set_n_wires(&mut self, n_wires: usize) {
1192        self.inner.set_n_wires(n_wires);
1193    }
1194
1195    fn is_static_mode(&self) -> bool {
1196        self.inner.is_static_mode()
1197    }
1198
1199    fn static_on(&mut self) {
1200        self.inner.static_on();
1201    }
1202
1203    fn static_off(&mut self) {
1204        self.inner.static_off();
1205    }
1206
1207    fn name(&self) -> &str {
1208        "EfficientSU2Layer"
1209    }
1210
1211    fn zero_grad(&mut self) {
1212        self.inner.zero_grad();
1213    }
1214}
1215
1216/// RealAmplitudes layer (from TorchQuantum/Qiskit)
1217/// Hardware-efficient ansatz with RY rotations and CX entanglement
1218pub struct TQRealAmplitudesLayer {
1219    inner: TQTwoLocalLayer,
1220}
1221
1222impl TQRealAmplitudesLayer {
1223    pub fn new(n_wires: usize, reps: usize, entanglement: EntanglementPattern) -> Self {
1224        Self {
1225            inner: TQTwoLocalLayer::new(
1226                n_wires,
1227                vec!["ry"],
1228                vec!["cnot"],
1229                entanglement,
1230                reps,
1231                false,
1232            ),
1233        }
1234    }
1235
1236    /// Create with default reverse linear entanglement
1237    pub fn default_entanglement(n_wires: usize, reps: usize) -> Self {
1238        Self::new(n_wires, reps, EntanglementPattern::ReverseLinear)
1239    }
1240}
1241
1242impl TQModule for TQRealAmplitudesLayer {
1243    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
1244        self.inner.forward(qdev)
1245    }
1246
1247    fn parameters(&self) -> Vec<TQParameter> {
1248        self.inner.parameters()
1249    }
1250
1251    fn n_wires(&self) -> Option<usize> {
1252        self.inner.n_wires()
1253    }
1254
1255    fn set_n_wires(&mut self, n_wires: usize) {
1256        self.inner.set_n_wires(n_wires);
1257    }
1258
1259    fn is_static_mode(&self) -> bool {
1260        self.inner.is_static_mode()
1261    }
1262
1263    fn static_on(&mut self) {
1264        self.inner.static_on();
1265    }
1266
1267    fn static_off(&mut self) {
1268        self.inner.static_off();
1269    }
1270
1271    fn name(&self) -> &str {
1272        "RealAmplitudesLayer"
1273    }
1274
1275    fn zero_grad(&mut self) {
1276        self.inner.zero_grad();
1277    }
1278}
1279
1280/// Dense two-qubit operation layer (full connectivity)
1281/// Applies gates to all pairs of qubits
1282pub struct TQOp2QDenseLayer {
1283    n_wires: usize,
1284    op_name: String,
1285    gates: Vec<Box<dyn TQOperator>>,
1286    static_mode: bool,
1287}
1288
1289impl TQOp2QDenseLayer {
1290    pub fn new(op_name: impl Into<String>, n_wires: usize) -> Self {
1291        let op_name = op_name.into();
1292        let n_pairs = n_wires * (n_wires - 1) / 2;
1293        let gates: Vec<Box<dyn TQOperator>> = (0..n_pairs)
1294            .map(|_| create_two_qubit_gate(&op_name, false, false))
1295            .collect();
1296
1297        Self {
1298            n_wires,
1299            op_name,
1300            gates,
1301            static_mode: false,
1302        }
1303    }
1304
1305    /// Create CNOT dense layer
1306    pub fn cnot(n_wires: usize) -> Self {
1307        Self::new("cnot", n_wires)
1308    }
1309
1310    /// Create CZ dense layer
1311    pub fn cz(n_wires: usize) -> Self {
1312        Self::new("cz", n_wires)
1313    }
1314}
1315
1316impl TQModule for TQOp2QDenseLayer {
1317    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
1318        let mut gate_idx = 0;
1319        for i in 0..self.n_wires {
1320            for j in (i + 1)..self.n_wires {
1321                if gate_idx < self.gates.len() {
1322                    self.gates[gate_idx].apply(qdev, &[i, j])?;
1323                    gate_idx += 1;
1324                }
1325            }
1326        }
1327        Ok(())
1328    }
1329
1330    fn parameters(&self) -> Vec<TQParameter> {
1331        self.gates.iter().flat_map(|g| g.parameters()).collect()
1332    }
1333
1334    fn n_wires(&self) -> Option<usize> {
1335        Some(self.n_wires)
1336    }
1337
1338    fn set_n_wires(&mut self, n_wires: usize) {
1339        self.n_wires = n_wires;
1340    }
1341
1342    fn is_static_mode(&self) -> bool {
1343        self.static_mode
1344    }
1345
1346    fn static_on(&mut self) {
1347        self.static_mode = true;
1348        for gate in &mut self.gates {
1349            gate.static_on();
1350        }
1351    }
1352
1353    fn static_off(&mut self) {
1354        self.static_mode = false;
1355        for gate in &mut self.gates {
1356            gate.static_off();
1357        }
1358    }
1359
1360    fn name(&self) -> &str {
1361        "Op2QDenseLayer"
1362    }
1363
1364    fn zero_grad(&mut self) {
1365        for gate in &mut self.gates {
1366            gate.zero_grad();
1367        }
1368    }
1369}
1370
1371/// Random layer - applies random gates from a set
1372pub struct TQRandomLayer {
1373    n_wires: usize,
1374    n_ops: usize,
1375    rotation_ops: Vec<String>,
1376    entanglement_ops: Vec<String>,
1377    seed: Option<u64>,
1378    static_mode: bool,
1379    /// Cached gate sequence
1380    gate_sequence: Vec<(String, Vec<usize>)>,
1381}
1382
1383impl TQRandomLayer {
1384    pub fn new(
1385        n_wires: usize,
1386        n_ops: usize,
1387        rotation_ops: Vec<&str>,
1388        entanglement_ops: Vec<&str>,
1389        seed: Option<u64>,
1390    ) -> Self {
1391        let rotation_ops: Vec<String> = rotation_ops.iter().map(|s| s.to_string()).collect();
1392        let entanglement_ops: Vec<String> =
1393            entanglement_ops.iter().map(|s| s.to_string()).collect();
1394
1395        let gate_sequence =
1396            Self::generate_sequence(n_wires, n_ops, &rotation_ops, &entanglement_ops, seed);
1397
1398        Self {
1399            n_wires,
1400            n_ops,
1401            rotation_ops,
1402            entanglement_ops,
1403            seed,
1404            static_mode: false,
1405            gate_sequence,
1406        }
1407    }
1408
1409    fn generate_sequence(
1410        n_wires: usize,
1411        n_ops: usize,
1412        rotation_ops: &[String],
1413        entanglement_ops: &[String],
1414        seed: Option<u64>,
1415    ) -> Vec<(String, Vec<usize>)> {
1416        let mut sequence = Vec::with_capacity(n_ops);
1417
1418        if let Some(s) = seed {
1419            fastrand::seed(s);
1420        }
1421
1422        let all_ops: Vec<&String> = rotation_ops.iter().chain(entanglement_ops.iter()).collect();
1423
1424        for _ in 0..n_ops {
1425            let op_idx = fastrand::usize(0..all_ops.len());
1426            let op_name = all_ops[op_idx].clone();
1427
1428            let wires = if rotation_ops.contains(&op_name) {
1429                // Single-qubit gate
1430                vec![fastrand::usize(0..n_wires)]
1431            } else {
1432                // Two-qubit gate
1433                let w0 = fastrand::usize(0..n_wires);
1434                let mut w1 = fastrand::usize(0..n_wires);
1435                while w1 == w0 {
1436                    w1 = fastrand::usize(0..n_wires);
1437                }
1438                vec![w0, w1]
1439            };
1440
1441            sequence.push((op_name, wires));
1442        }
1443
1444        sequence
1445    }
1446
1447    /// Regenerate the random gate sequence
1448    pub fn regenerate(&mut self) {
1449        self.gate_sequence = Self::generate_sequence(
1450            self.n_wires,
1451            self.n_ops,
1452            &self.rotation_ops,
1453            &self.entanglement_ops,
1454            self.seed,
1455        );
1456    }
1457
1458    /// Create with default ops (RX, RY, RZ, CNOT)
1459    pub fn default_ops(n_wires: usize, n_ops: usize, seed: Option<u64>) -> Self {
1460        Self::new(n_wires, n_ops, vec!["rx", "ry", "rz"], vec!["cnot"], seed)
1461    }
1462}
1463
1464impl TQModule for TQRandomLayer {
1465    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
1466        for (op_name, wires) in &self.gate_sequence {
1467            if wires.len() == 1 {
1468                let mut gate = create_single_qubit_gate(op_name, true, false);
1469                gate.apply(qdev, wires)?;
1470            } else {
1471                let mut gate = create_two_qubit_gate(op_name, false, false);
1472                gate.apply(qdev, wires)?;
1473            }
1474        }
1475        Ok(())
1476    }
1477
1478    fn parameters(&self) -> Vec<TQParameter> {
1479        Vec::new() // Random layer doesn't expose trainable parameters
1480    }
1481
1482    fn n_wires(&self) -> Option<usize> {
1483        Some(self.n_wires)
1484    }
1485
1486    fn set_n_wires(&mut self, n_wires: usize) {
1487        self.n_wires = n_wires;
1488        self.regenerate();
1489    }
1490
1491    fn is_static_mode(&self) -> bool {
1492        self.static_mode
1493    }
1494
1495    fn static_on(&mut self) {
1496        self.static_mode = true;
1497    }
1498
1499    fn static_off(&mut self) {
1500        self.static_mode = false;
1501    }
1502
1503    fn name(&self) -> &str {
1504        "RandomLayer"
1505    }
1506}
1507
1508/// CX layer - applies CNOT gates in sequence
1509pub struct TQCXLayer {
1510    n_wires: usize,
1511    circular: bool,
1512    static_mode: bool,
1513}
1514
1515impl TQCXLayer {
1516    pub fn new(n_wires: usize, circular: bool) -> Self {
1517        Self {
1518            n_wires,
1519            circular,
1520            static_mode: false,
1521        }
1522    }
1523}
1524
1525impl TQModule for TQCXLayer {
1526    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
1527        let n_pairs = if self.circular {
1528            self.n_wires
1529        } else {
1530            self.n_wires.saturating_sub(1)
1531        };
1532
1533        for i in 0..n_pairs {
1534            let wire0 = i;
1535            let wire1 = (i + 1) % self.n_wires;
1536            let mut gate = TQCNOT::new();
1537            gate.apply(qdev, &[wire0, wire1])?;
1538        }
1539        Ok(())
1540    }
1541
1542    fn parameters(&self) -> Vec<TQParameter> {
1543        Vec::new()
1544    }
1545
1546    fn n_wires(&self) -> Option<usize> {
1547        Some(self.n_wires)
1548    }
1549
1550    fn set_n_wires(&mut self, n_wires: usize) {
1551        self.n_wires = n_wires;
1552    }
1553
1554    fn is_static_mode(&self) -> bool {
1555        self.static_mode
1556    }
1557
1558    fn static_on(&mut self) {
1559        self.static_mode = true;
1560    }
1561
1562    fn static_off(&mut self) {
1563        self.static_mode = false;
1564    }
1565
1566    fn name(&self) -> &str {
1567        "CXLayer"
1568    }
1569}
1570
1571/// Triple CX layer - applies CNOT gates three times (for error correction patterns)
1572pub struct TQCXCXCXLayer {
1573    n_wires: usize,
1574    static_mode: bool,
1575}
1576
1577impl TQCXCXCXLayer {
1578    pub fn new(n_wires: usize) -> Self {
1579        Self {
1580            n_wires,
1581            static_mode: false,
1582        }
1583    }
1584}
1585
1586impl TQModule for TQCXCXCXLayer {
1587    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
1588        // Three rounds of CX gates
1589        for _ in 0..3 {
1590            for i in 0..(self.n_wires - 1) {
1591                let mut gate = TQCNOT::new();
1592                gate.apply(qdev, &[i, i + 1])?;
1593            }
1594        }
1595        Ok(())
1596    }
1597
1598    fn parameters(&self) -> Vec<TQParameter> {
1599        Vec::new()
1600    }
1601
1602    fn n_wires(&self) -> Option<usize> {
1603        Some(self.n_wires)
1604    }
1605
1606    fn set_n_wires(&mut self, n_wires: usize) {
1607        self.n_wires = n_wires;
1608    }
1609
1610    fn is_static_mode(&self) -> bool {
1611        self.static_mode
1612    }
1613
1614    fn static_on(&mut self) {
1615        self.static_mode = true;
1616    }
1617
1618    fn static_off(&mut self) {
1619        self.static_mode = false;
1620    }
1621
1622    fn name(&self) -> &str {
1623        "CXCXCXLayer"
1624    }
1625}
1626
1627// =============================================================================
1628// Chemistry/Fermionic Ansatz Layers
1629// =============================================================================
1630
1631use super::gates::{TQFSimGate, TQGivensRotation};
1632
1633/// Excitation preserving layer for quantum chemistry
1634///
1635/// This layer preserves the total number of excitations (particles) in the
1636/// quantum state, making it suitable for variational quantum eigensolver (VQE)
1637/// and other chemistry applications.
1638///
1639/// The layer uses fSim gates which naturally preserve particle number
1640/// while providing entanglement.
1641///
1642/// Pattern: For each pair of adjacent qubits, apply fSim gate with trainable
1643/// theta and phi parameters.
1644pub struct TQExcitationPreservingLayer {
1645    n_wires: usize,
1646    n_blocks: usize,
1647    circular: bool,
1648    gates: Vec<TQFSimGate>,
1649    static_mode: bool,
1650}
1651
1652impl TQExcitationPreservingLayer {
1653    /// Create a new excitation preserving layer
1654    pub fn new(n_wires: usize, n_blocks: usize, circular: bool) -> Self {
1655        let n_pairs = if circular {
1656            n_wires
1657        } else {
1658            n_wires.saturating_sub(1)
1659        };
1660        let total_gates = n_pairs * n_blocks;
1661
1662        let gates: Vec<TQFSimGate> = (0..total_gates)
1663            .map(|_| TQFSimGate::new(true, true))
1664            .collect();
1665
1666        Self {
1667            n_wires,
1668            n_blocks,
1669            circular,
1670            gates,
1671            static_mode: false,
1672        }
1673    }
1674
1675    /// Create with linear (non-circular) connectivity
1676    pub fn linear(n_wires: usize, n_blocks: usize) -> Self {
1677        Self::new(n_wires, n_blocks, false)
1678    }
1679
1680    /// Create with circular connectivity
1681    pub fn circular(n_wires: usize, n_blocks: usize) -> Self {
1682        Self::new(n_wires, n_blocks, true)
1683    }
1684}
1685
1686impl TQModule for TQExcitationPreservingLayer {
1687    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
1688        let n_pairs = if self.circular {
1689            self.n_wires
1690        } else {
1691            self.n_wires.saturating_sub(1)
1692        };
1693
1694        let mut gate_idx = 0;
1695        for _ in 0..self.n_blocks {
1696            for pair in 0..n_pairs {
1697                let w0 = pair;
1698                let w1 = (pair + 1) % self.n_wires;
1699
1700                if gate_idx < self.gates.len() {
1701                    self.gates[gate_idx].apply(qdev, &[w0, w1])?;
1702                    gate_idx += 1;
1703                }
1704            }
1705        }
1706        Ok(())
1707    }
1708
1709    fn parameters(&self) -> Vec<TQParameter> {
1710        self.gates.iter().flat_map(|g| g.parameters()).collect()
1711    }
1712
1713    fn n_wires(&self) -> Option<usize> {
1714        Some(self.n_wires)
1715    }
1716
1717    fn set_n_wires(&mut self, n_wires: usize) {
1718        self.n_wires = n_wires;
1719        // Recreate gates for new wire count
1720        let n_pairs = if self.circular {
1721            n_wires
1722        } else {
1723            n_wires.saturating_sub(1)
1724        };
1725        let total_gates = n_pairs * self.n_blocks;
1726        self.gates = (0..total_gates)
1727            .map(|_| TQFSimGate::new(true, true))
1728            .collect();
1729    }
1730
1731    fn is_static_mode(&self) -> bool {
1732        self.static_mode
1733    }
1734
1735    fn static_on(&mut self) {
1736        self.static_mode = true;
1737        for gate in &mut self.gates {
1738            gate.static_on();
1739        }
1740    }
1741
1742    fn static_off(&mut self) {
1743        self.static_mode = false;
1744        for gate in &mut self.gates {
1745            gate.static_off();
1746        }
1747    }
1748
1749    fn name(&self) -> &str {
1750        "ExcitationPreservingLayer"
1751    }
1752
1753    fn zero_grad(&mut self) {
1754        for gate in &mut self.gates {
1755            gate.zero_grad();
1756        }
1757    }
1758}
1759
1760/// Particle conserving layer using Givens rotations
1761///
1762/// This layer is specifically designed for quantum chemistry applications
1763/// where particle number conservation is critical. It uses Givens rotations
1764/// which naturally preserve the number of particles.
1765///
1766/// The layer can be used as an excitation preserving ansatz for molecular
1767/// simulations in variational quantum algorithms.
1768pub struct TQParticleConservingLayer {
1769    n_wires: usize,
1770    n_blocks: usize,
1771    pattern: GivensPattern,
1772    gates: Vec<TQGivensRotation>,
1773    static_mode: bool,
1774}
1775
1776/// Pattern for Givens rotation application
1777#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1778pub enum GivensPattern {
1779    /// Adjacent pairs only
1780    Adjacent,
1781    /// Staircase pattern (used in chemistry)
1782    Staircase,
1783    /// Bricklayer pattern (alternating)
1784    Bricklayer,
1785}
1786
1787impl TQParticleConservingLayer {
1788    /// Create a new particle conserving layer
1789    pub fn new(n_wires: usize, n_blocks: usize, pattern: GivensPattern) -> Self {
1790        let n_gates = Self::count_gates(n_wires, n_blocks, pattern);
1791
1792        let gates: Vec<TQGivensRotation> = (0..n_gates)
1793            .map(|_| TQGivensRotation::new(true, true))
1794            .collect();
1795
1796        Self {
1797            n_wires,
1798            n_blocks,
1799            pattern,
1800            gates,
1801            static_mode: false,
1802        }
1803    }
1804
1805    /// Create with adjacent pattern (default)
1806    pub fn adjacent(n_wires: usize, n_blocks: usize) -> Self {
1807        Self::new(n_wires, n_blocks, GivensPattern::Adjacent)
1808    }
1809
1810    /// Create with staircase pattern
1811    pub fn staircase(n_wires: usize, n_blocks: usize) -> Self {
1812        Self::new(n_wires, n_blocks, GivensPattern::Staircase)
1813    }
1814
1815    /// Create with bricklayer pattern
1816    pub fn bricklayer(n_wires: usize, n_blocks: usize) -> Self {
1817        Self::new(n_wires, n_blocks, GivensPattern::Bricklayer)
1818    }
1819
1820    fn count_gates(n_wires: usize, n_blocks: usize, pattern: GivensPattern) -> usize {
1821        match pattern {
1822            GivensPattern::Adjacent => (n_wires - 1) * n_blocks,
1823            GivensPattern::Staircase => {
1824                // Staircase: (0,1), (1,2), ..., (n-2,n-1), (n-2,n-1), ..., (1,2), (0,1)
1825                // This creates a "up and down" pattern
1826                (n_wires - 1) * 2 * n_blocks
1827            }
1828            GivensPattern::Bricklayer => {
1829                // Even pairs + odd pairs
1830                let even = n_wires / 2;
1831                let odd = (n_wires - 1) / 2;
1832                (even + odd) * n_blocks
1833            }
1834        }
1835    }
1836
1837    fn get_wire_pairs(&self) -> Vec<(usize, usize)> {
1838        let mut pairs = Vec::new();
1839
1840        match self.pattern {
1841            GivensPattern::Adjacent => {
1842                for _ in 0..self.n_blocks {
1843                    for i in 0..(self.n_wires - 1) {
1844                        pairs.push((i, i + 1));
1845                    }
1846                }
1847            }
1848            GivensPattern::Staircase => {
1849                for _ in 0..self.n_blocks {
1850                    // Up staircase
1851                    for i in 0..(self.n_wires - 1) {
1852                        pairs.push((i, i + 1));
1853                    }
1854                    // Down staircase
1855                    for i in (0..(self.n_wires - 1)).rev() {
1856                        pairs.push((i, i + 1));
1857                    }
1858                }
1859            }
1860            GivensPattern::Bricklayer => {
1861                for _ in 0..self.n_blocks {
1862                    // Even pairs: (0,1), (2,3), ...
1863                    for i in (0..self.n_wires - 1).step_by(2) {
1864                        pairs.push((i, i + 1));
1865                    }
1866                    // Odd pairs: (1,2), (3,4), ...
1867                    for i in (1..self.n_wires - 1).step_by(2) {
1868                        pairs.push((i, i + 1));
1869                    }
1870                }
1871            }
1872        }
1873
1874        pairs
1875    }
1876}
1877
1878impl TQModule for TQParticleConservingLayer {
1879    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
1880        let pairs = self.get_wire_pairs();
1881
1882        for (gate_idx, (w0, w1)) in pairs.iter().enumerate() {
1883            if gate_idx < self.gates.len() {
1884                self.gates[gate_idx].apply(qdev, &[*w0, *w1])?;
1885            }
1886        }
1887        Ok(())
1888    }
1889
1890    fn parameters(&self) -> Vec<TQParameter> {
1891        self.gates.iter().flat_map(|g| g.parameters()).collect()
1892    }
1893
1894    fn n_wires(&self) -> Option<usize> {
1895        Some(self.n_wires)
1896    }
1897
1898    fn set_n_wires(&mut self, n_wires: usize) {
1899        self.n_wires = n_wires;
1900        let n_gates = Self::count_gates(n_wires, self.n_blocks, self.pattern);
1901        self.gates = (0..n_gates)
1902            .map(|_| TQGivensRotation::new(true, true))
1903            .collect();
1904    }
1905
1906    fn is_static_mode(&self) -> bool {
1907        self.static_mode
1908    }
1909
1910    fn static_on(&mut self) {
1911        self.static_mode = true;
1912        for gate in &mut self.gates {
1913            gate.static_on();
1914        }
1915    }
1916
1917    fn static_off(&mut self) {
1918        self.static_mode = false;
1919        for gate in &mut self.gates {
1920            gate.static_off();
1921        }
1922    }
1923
1924    fn name(&self) -> &str {
1925        "ParticleConservingLayer"
1926    }
1927
1928    fn zero_grad(&mut self) {
1929        for gate in &mut self.gates {
1930            gate.zero_grad();
1931        }
1932    }
1933}
1934
1935/// Hardware Efficient 2 Layer - Alternative hardware efficient ansatz
1936///
1937/// This is an alternative to the standard hardware efficient ansatz with
1938/// different rotation and entanglement patterns. It uses:
1939/// - Initial layer of RY rotations
1940/// - Alternating CZ and CNOT entanglement
1941/// - RX and RZ rotations between entanglement layers
1942///
1943/// Pattern: RY -> (CZ -> RX -> CNOT -> RZ) * n_blocks
1944pub struct TQHardwareEfficient2Layer {
1945    config: TQLayerConfig,
1946    layers: Vec<Box<dyn TQModule>>,
1947    static_mode: bool,
1948}
1949
1950impl TQHardwareEfficient2Layer {
1951    pub fn new(config: TQLayerConfig) -> Self {
1952        let mut layers: Vec<Box<dyn TQModule>> = Vec::new();
1953
1954        // Initial RY layer
1955        layers.push(Box::new(TQOp1QAllLayer::ry(config.n_wires, true)));
1956
1957        for _ in 0..config.n_blocks {
1958            // CZ entanglement
1959            layers.push(Box::new(TQOp2QAllLayer::cz(config.n_wires, true)));
1960
1961            // RX rotation
1962            layers.push(Box::new(TQOp1QAllLayer::rx(config.n_wires, true)));
1963
1964            // CNOT entanglement (shifted by 1)
1965            layers.push(Box::new(TQOp2QAllLayer::new(
1966                "cnot",
1967                config.n_wires,
1968                false,
1969                false,
1970                1,
1971                true,
1972            )));
1973
1974            // RZ rotation
1975            layers.push(Box::new(TQOp1QAllLayer::rz(config.n_wires, true)));
1976        }
1977
1978        Self {
1979            config,
1980            layers,
1981            static_mode: false,
1982        }
1983    }
1984}
1985
1986impl TQModule for TQHardwareEfficient2Layer {
1987    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
1988        for layer in &mut self.layers {
1989            layer.forward(qdev)?;
1990        }
1991        Ok(())
1992    }
1993
1994    fn parameters(&self) -> Vec<TQParameter> {
1995        self.layers.iter().flat_map(|l| l.parameters()).collect()
1996    }
1997
1998    fn n_wires(&self) -> Option<usize> {
1999        Some(self.config.n_wires)
2000    }
2001
2002    fn set_n_wires(&mut self, n_wires: usize) {
2003        self.config.n_wires = n_wires;
2004    }
2005
2006    fn is_static_mode(&self) -> bool {
2007        self.static_mode
2008    }
2009
2010    fn static_on(&mut self) {
2011        self.static_mode = true;
2012        for layer in &mut self.layers {
2013            layer.static_on();
2014        }
2015    }
2016
2017    fn static_off(&mut self) {
2018        self.static_mode = false;
2019        for layer in &mut self.layers {
2020            layer.static_off();
2021        }
2022    }
2023
2024    fn name(&self) -> &str {
2025        "HardwareEfficient2Layer"
2026    }
2027
2028    fn zero_grad(&mut self) {
2029        for layer in &mut self.layers {
2030            layer.zero_grad();
2031        }
2032    }
2033}
2034
2035/// UCCSD-inspired layer for molecular simulations
2036///
2037/// This layer provides a simplified version of the Unitary Coupled Cluster
2038/// Singles and Doubles (UCCSD) ansatz commonly used in VQE for chemistry.
2039///
2040/// It uses Givens rotations to implement fermionic excitations.
2041pub struct TQUCCSDLayer {
2042    n_wires: usize,
2043    n_electrons: usize,
2044    gates: Vec<TQGivensRotation>,
2045    static_mode: bool,
2046}
2047
2048impl TQUCCSDLayer {
2049    /// Create a new UCCSD-inspired layer
2050    ///
2051    /// # Arguments
2052    /// * `n_wires` - Number of qubits (spin-orbitals)
2053    /// * `n_electrons` - Number of electrons
2054    pub fn new(n_wires: usize, n_electrons: usize) -> Self {
2055        // Calculate number of single and double excitations
2056        let n_virtual = n_wires - n_electrons;
2057        let n_singles = n_electrons * n_virtual;
2058        let n_doubles = n_singles * (n_singles - 1) / 2;
2059
2060        // Simplified: just use n_singles Givens rotations
2061        // A full UCCSD would need many more gates
2062        let n_gates = n_singles.min(n_wires * 2);
2063
2064        let gates: Vec<TQGivensRotation> = (0..n_gates)
2065            .map(|_| TQGivensRotation::new(true, true))
2066            .collect();
2067
2068        Self {
2069            n_wires,
2070            n_electrons,
2071            gates,
2072            static_mode: false,
2073        }
2074    }
2075}
2076
2077impl TQModule for TQUCCSDLayer {
2078    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
2079        // Apply Givens rotations in a pattern that mimics UCCSD excitations
2080        let mut gate_idx = 0;
2081
2082        // Single excitations: connect occupied to virtual orbitals
2083        for occ in 0..self.n_electrons.min(self.n_wires) {
2084            for virt in self.n_electrons..self.n_wires {
2085                if gate_idx < self.gates.len() {
2086                    // Apply Givens rotation between occupied and virtual
2087                    if virt > occ {
2088                        // Chain Givens rotations to connect distant orbitals
2089                        self.gates[gate_idx].apply(qdev, &[occ, occ + 1])?;
2090                        gate_idx += 1;
2091                    }
2092                }
2093            }
2094        }
2095
2096        Ok(())
2097    }
2098
2099    fn parameters(&self) -> Vec<TQParameter> {
2100        self.gates.iter().flat_map(|g| g.parameters()).collect()
2101    }
2102
2103    fn n_wires(&self) -> Option<usize> {
2104        Some(self.n_wires)
2105    }
2106
2107    fn set_n_wires(&mut self, n_wires: usize) {
2108        self.n_wires = n_wires;
2109    }
2110
2111    fn is_static_mode(&self) -> bool {
2112        self.static_mode
2113    }
2114
2115    fn static_on(&mut self) {
2116        self.static_mode = true;
2117        for gate in &mut self.gates {
2118            gate.static_on();
2119        }
2120    }
2121
2122    fn static_off(&mut self) {
2123        self.static_mode = false;
2124        for gate in &mut self.gates {
2125            gate.static_off();
2126        }
2127    }
2128
2129    fn name(&self) -> &str {
2130        "UCCSDLayer"
2131    }
2132
2133    fn zero_grad(&mut self) {
2134        for gate in &mut self.gates {
2135            gate.zero_grad();
2136        }
2137    }
2138}
2139
2140/// Symmetry preserving layer
2141///
2142/// This layer preserves certain symmetries of the quantum state,
2143/// useful for applications where conservation laws must be respected.
2144pub struct TQSymmetryPreservingLayer {
2145    n_wires: usize,
2146    n_blocks: usize,
2147    symmetry_type: SymmetryType,
2148    layers: Vec<Box<dyn TQModule>>,
2149    static_mode: bool,
2150}
2151
2152/// Type of symmetry to preserve
2153#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2154pub enum SymmetryType {
2155    /// Particle number conservation
2156    ParticleNumber,
2157    /// Spin conservation
2158    SpinConservation,
2159    /// Time reversal symmetry
2160    TimeReversal,
2161}
2162
2163impl TQSymmetryPreservingLayer {
2164    pub fn new(n_wires: usize, n_blocks: usize, symmetry_type: SymmetryType) -> Self {
2165        let layers = Self::build_layers(n_wires, n_blocks, symmetry_type);
2166
2167        Self {
2168            n_wires,
2169            n_blocks,
2170            symmetry_type,
2171            layers,
2172            static_mode: false,
2173        }
2174    }
2175
2176    fn build_layers(
2177        n_wires: usize,
2178        n_blocks: usize,
2179        symmetry_type: SymmetryType,
2180    ) -> Vec<Box<dyn TQModule>> {
2181        let mut layers: Vec<Box<dyn TQModule>> = Vec::new();
2182
2183        match symmetry_type {
2184            SymmetryType::ParticleNumber => {
2185                // Use fSim gates which preserve particle number
2186                for _ in 0..n_blocks {
2187                    layers.push(Box::new(TQExcitationPreservingLayer::new(
2188                        n_wires, 1, false,
2189                    )));
2190                }
2191            }
2192            SymmetryType::SpinConservation => {
2193                // Use RZ rotations (diagonal) and XX+YY interactions
2194                for _ in 0..n_blocks {
2195                    layers.push(Box::new(TQOp1QAllLayer::rz(n_wires, true)));
2196                    layers.push(Box::new(TQOp2QAllLayer::new(
2197                        "rxx", n_wires, true, true, 1, false,
2198                    )));
2199                    layers.push(Box::new(TQOp2QAllLayer::new(
2200                        "ryy", n_wires, true, true, 1, false,
2201                    )));
2202                }
2203            }
2204            SymmetryType::TimeReversal => {
2205                // Use real operations only (RY rotations and real entanglement)
2206                for _ in 0..n_blocks {
2207                    layers.push(Box::new(TQOp1QAllLayer::ry(n_wires, true)));
2208                    layers.push(Box::new(TQOp2QAllLayer::cnot(n_wires, true)));
2209                }
2210            }
2211        }
2212
2213        layers
2214    }
2215
2216    pub fn particle_number(n_wires: usize, n_blocks: usize) -> Self {
2217        Self::new(n_wires, n_blocks, SymmetryType::ParticleNumber)
2218    }
2219
2220    pub fn spin_conserving(n_wires: usize, n_blocks: usize) -> Self {
2221        Self::new(n_wires, n_blocks, SymmetryType::SpinConservation)
2222    }
2223
2224    pub fn time_reversal(n_wires: usize, n_blocks: usize) -> Self {
2225        Self::new(n_wires, n_blocks, SymmetryType::TimeReversal)
2226    }
2227}
2228
2229impl TQModule for TQSymmetryPreservingLayer {
2230    fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
2231        for layer in &mut self.layers {
2232            layer.forward(qdev)?;
2233        }
2234        Ok(())
2235    }
2236
2237    fn parameters(&self) -> Vec<TQParameter> {
2238        self.layers.iter().flat_map(|l| l.parameters()).collect()
2239    }
2240
2241    fn n_wires(&self) -> Option<usize> {
2242        Some(self.n_wires)
2243    }
2244
2245    fn set_n_wires(&mut self, n_wires: usize) {
2246        self.n_wires = n_wires;
2247        self.layers = Self::build_layers(n_wires, self.n_blocks, self.symmetry_type);
2248    }
2249
2250    fn is_static_mode(&self) -> bool {
2251        self.static_mode
2252    }
2253
2254    fn static_on(&mut self) {
2255        self.static_mode = true;
2256        for layer in &mut self.layers {
2257            layer.static_on();
2258        }
2259    }
2260
2261    fn static_off(&mut self) {
2262        self.static_mode = false;
2263        for layer in &mut self.layers {
2264            layer.static_off();
2265        }
2266    }
2267
2268    fn name(&self) -> &str {
2269        "SymmetryPreservingLayer"
2270    }
2271
2272    fn zero_grad(&mut self) {
2273        for layer in &mut self.layers {
2274            layer.zero_grad();
2275        }
2276    }
2277}