quantrs2_sim/jit_compilation/
mod.rs

1//! Just-in-time compilation for frequently used gate sequences.
2//!
3//! This module provides advanced JIT compilation capabilities for quantum circuit
4//! simulation, enabling compilation of frequently used gate sequences into optimized
5//! machine code for dramatic performance improvements.
6
7mod analyzer;
8mod compiler;
9mod profiler;
10mod simulator;
11mod types;
12
13// Re-export all public types
14pub use analyzer::*;
15pub use compiler::*;
16pub use profiler::*;
17pub use simulator::*;
18pub use types::*;
19
20#[cfg(test)]
21#[allow(clippy::field_reassign_with_default)]
22mod tests {
23    use super::*;
24    use crate::circuit_interfaces::{InterfaceGate, InterfaceGateType};
25    use scirs2_core::Complex64;
26
27    #[test]
28    fn test_jit_compiler_creation() {
29        let config = JITConfig::default();
30        let compiler = JITCompiler::new(config);
31        let stats = compiler.get_stats();
32        assert_eq!(stats.total_compilations, 0);
33    }
34
35    #[test]
36    fn test_pattern_extraction() {
37        let config = JITConfig::default();
38        let _compiler = JITCompiler::new(config);
39
40        let gates = vec![
41            InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]),
42            InterfaceGate::new(InterfaceGateType::PauliX, vec![1]),
43        ];
44
45        let pattern =
46            JITCompiler::extract_pattern(&gates).expect("Pattern extraction should succeed");
47        assert_eq!(pattern.gate_types.len(), 2);
48        assert_eq!(pattern.frequency, 1);
49    }
50
51    #[test]
52    fn test_gate_matrix_generation() {
53        let config = JITConfig::default();
54        let _compiler = JITCompiler::new(config);
55
56        let pauli_x = JITCompiler::get_gate_matrix(&InterfaceGateType::PauliX)
57            .expect("PauliX matrix generation should succeed");
58        assert_eq!(pauli_x.shape(), [2, 2]);
59        assert_eq!(pauli_x[(0, 1)], Complex64::new(1.0, 0.0));
60        assert_eq!(pauli_x[(1, 0)], Complex64::new(1.0, 0.0));
61    }
62
63    #[test]
64    fn test_pattern_analysis() {
65        let mut analyzer = PatternAnalyzer::new();
66
67        let gates = vec![
68            InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]),
69            InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]),
70        ];
71
72        let result = analyzer.analyze_pattern(&gates);
73        assert_eq!(result.frequency, 1);
74        assert!(result
75            .optimization_suggestions
76            .contains(&OptimizationSuggestion::GateFusion));
77    }
78
79    #[test]
80    fn test_complexity_analysis() {
81        let analyzer = ComplexityAnalyzer::new();
82
83        let gates = vec![
84            InterfaceGate::new(InterfaceGateType::PauliX, vec![0]),
85            InterfaceGate::new(InterfaceGateType::CNOT, vec![0, 1]),
86        ];
87
88        let complexity = analyzer.analyze_complexity(&gates);
89        assert_eq!(complexity.gate_count, 2);
90        assert!(complexity.computational_cost > 0.0);
91    }
92
93    #[test]
94    fn test_jit_simulator_creation() {
95        let config = JITConfig::default();
96        let simulator = JITQuantumSimulator::new(2, config);
97
98        assert_eq!(simulator.num_qubits, 2);
99        assert_eq!(simulator.get_state().len(), 4);
100        assert_eq!(simulator.get_state()[0], Complex64::new(1.0, 0.0));
101    }
102
103    #[test]
104    fn test_gate_application() {
105        let config = JITConfig::default();
106        let mut simulator = JITQuantumSimulator::new(1, config);
107
108        let gate = InterfaceGate::new(InterfaceGateType::PauliX, vec![0]);
109
110        simulator
111            .apply_gate_interpreted(&gate)
112            .expect("PauliX gate application should succeed");
113
114        // After Pauli-X, state should be |1⟩
115        assert_eq!(simulator.get_state()[0], Complex64::new(0.0, 0.0));
116        assert_eq!(simulator.get_state()[1], Complex64::new(1.0, 0.0));
117    }
118
119    #[test]
120    fn test_hadamard_gate() {
121        let config = JITConfig::default();
122        let mut simulator = JITQuantumSimulator::new(1, config);
123
124        let gate = InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]);
125
126        simulator
127            .apply_gate_interpreted(&gate)
128            .expect("Hadamard gate application should succeed");
129
130        // After Hadamard, state should be (|0⟩ + |1⟩)/√2
131        let sqrt2_inv = 1.0 / (2.0_f64).sqrt();
132        assert!((simulator.get_state()[0].re - sqrt2_inv).abs() < 1e-10);
133        assert!((simulator.get_state()[1].re - sqrt2_inv).abs() < 1e-10);
134    }
135
136    #[test]
137    fn test_cnot_gate() {
138        let config = JITConfig::default();
139        let mut simulator = JITQuantumSimulator::new(2, config);
140
141        // Prepare |10⟩ state by applying X gate to qubit 1
142        // In little-endian convention: |10⟩ means qubit 1 is |1⟩, qubit 0 is |0⟩
143        let x_gate = InterfaceGate::new(InterfaceGateType::PauliX, vec![1]);
144        simulator
145            .apply_gate_interpreted(&x_gate)
146            .expect("PauliX gate application should succeed");
147
148        // Verify we have |10⟩ state (index 2 in little-endian)
149        assert!((simulator.get_state()[0].norm() - 0.0).abs() < 1e-10);
150        assert!((simulator.get_state()[1].norm() - 0.0).abs() < 1e-10);
151        assert!((simulator.get_state()[2].norm() - 1.0).abs() < 1e-10);
152        assert!((simulator.get_state()[3].norm() - 0.0).abs() < 1e-10);
153
154        let gate = InterfaceGate::new(InterfaceGateType::CNOT, vec![1, 0]);
155
156        simulator
157            .apply_gate_interpreted(&gate)
158            .expect("CNOT gate application should succeed");
159
160        // After CNOT with control=1, target=0: |10⟩ → |11⟩ (index 3)
161        assert!((simulator.get_state()[0].norm() - 0.0).abs() < 1e-10);
162        assert!((simulator.get_state()[1].norm() - 0.0).abs() < 1e-10);
163        assert!((simulator.get_state()[2].norm() - 0.0).abs() < 1e-10);
164        assert!((simulator.get_state()[3].norm() - 1.0).abs() < 1e-10);
165    }
166
167    #[test]
168    fn test_rotation_gates() {
169        let config = JITConfig::default();
170        let mut simulator = JITQuantumSimulator::new(1, config);
171
172        // Test RX gate
173        let gate_rx = InterfaceGate::new(InterfaceGateType::RX(std::f64::consts::PI), vec![0]);
174
175        simulator
176            .apply_gate_interpreted(&gate_rx)
177            .expect("RX gate application should succeed");
178
179        // RX(π) should be equivalent to Pauli-X up to global phase
180        assert!((simulator.get_state()[0].norm() - 0.0).abs() < 1e-10);
181        assert!((simulator.get_state()[1].norm() - 1.0).abs() < 1e-10);
182    }
183
184    #[test]
185    fn test_gate_sequence_compilation() {
186        let mut config = JITConfig::default();
187        config.compilation_threshold = 1; // Compile after 1 usage
188
189        let mut simulator = JITQuantumSimulator::new(2, config);
190
191        let sequence = vec![
192            InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]),
193            InterfaceGate::new(InterfaceGateType::PauliX, vec![1]),
194        ];
195
196        // First execution should be interpreted
197        let _time1 = simulator
198            .apply_gate_sequence(&sequence)
199            .expect("First gate sequence should succeed");
200        assert_eq!(simulator.get_stats().interpreted_executions, 1);
201
202        // Second execution might be compiled
203        let _time2 = simulator
204            .apply_gate_sequence(&sequence)
205            .expect("Second gate sequence should succeed");
206        assert!(simulator.get_compiler_stats().patterns_analyzed > 0);
207    }
208
209    #[test]
210    fn test_optimization_suggestions() {
211        let mut analyzer = PatternAnalyzer::new();
212
213        let gates = vec![
214            InterfaceGate::new(InterfaceGateType::RX(std::f64::consts::PI / 4.0), vec![0]),
215            InterfaceGate::new(InterfaceGateType::RY(std::f64::consts::PI / 2.0), vec![0]),
216        ];
217
218        let result = analyzer.analyze_pattern(&gates);
219        assert!(result
220            .optimization_suggestions
221            .contains(&OptimizationSuggestion::GateFusion));
222    }
223
224    #[test]
225    fn test_runtime_profiler() {
226        use std::time::Duration;
227
228        let mut profiler = RuntimeProfiler::new();
229
230        profiler.record_execution_time(Duration::from_millis(100));
231        profiler.record_execution_time(Duration::from_millis(200));
232        profiler.record_memory_usage(1024);
233        profiler.record_memory_usage(2048);
234
235        let stats = profiler.get_stats();
236        assert_eq!(stats.sample_count, 2);
237        assert_eq!(stats.average_memory_usage, 1536);
238        assert_eq!(stats.peak_memory_usage, 2048);
239    }
240
241    #[test]
242    fn test_constant_folding_optimization() {
243        let config = JITConfig::default();
244        let _compiler = JITCompiler::new(config);
245
246        let mut instructions = vec![
247            BytecodeInstruction::ApplySingleQubit {
248                gate_type: InterfaceGateType::RX(0.0), // Zero rotation
249                target: 0,
250            },
251            BytecodeInstruction::ApplySingleQubit {
252                gate_type: InterfaceGateType::RY(std::f64::consts::PI),
253                target: 0,
254            },
255        ];
256
257        JITCompiler::apply_constant_folding(&mut instructions)
258            .expect("Constant folding should succeed");
259
260        // Check that zero rotation was folded to identity
261        if let BytecodeInstruction::ApplySingleQubit { gate_type, .. } = &instructions[0] {
262            assert_eq!(*gate_type, InterfaceGateType::Identity);
263        }
264    }
265
266    #[test]
267    fn test_dead_code_elimination() {
268        let config = JITConfig::default();
269        let _compiler = JITCompiler::new(config);
270
271        let mut instructions = vec![
272            BytecodeInstruction::ApplySingleQubit {
273                gate_type: InterfaceGateType::Identity,
274                target: 0,
275            },
276            BytecodeInstruction::ApplySingleQubit {
277                gate_type: InterfaceGateType::RY(std::f64::consts::PI),
278                target: 0,
279            },
280        ];
281
282        let original_len = instructions.len();
283        JITCompiler::apply_dead_code_elimination(&mut instructions)
284            .expect("Dead code elimination should succeed");
285
286        assert!(instructions.len() <= original_len);
287    }
288
289    #[test]
290    fn test_benchmark_jit_compilation() {
291        let results =
292            benchmark_jit_compilation().expect("JIT benchmark should complete successfully");
293
294        assert!(results.total_sequences > 0);
295        assert!(results.compilation_success_rate >= 0.0);
296        assert!(results.compilation_success_rate <= 1.0);
297        assert!(results.speedup_factor >= 0.0);
298    }
299}