Skip to main content

quantrs2_sim/jit_compilation/
compiler.rs

1//! JIT Compiler implementation
2//!
3//! This module provides the main JIT compilation engine for quantum circuits.
4
5use scirs2_core::ndarray::{Array1, Array2};
6use scirs2_core::Complex64;
7use std::collections::HashMap;
8use std::hash::Hasher;
9use std::sync::{Arc, Mutex, RwLock};
10use std::time::{Duration, Instant};
11
12use crate::circuit_interfaces::{InterfaceGate, InterfaceGateType};
13use crate::error::{Result, SimulatorError};
14
15use super::analyzer::PatternAnalyzer;
16use super::profiler::{JITCompilerStats, RuntimeProfiler};
17use super::types::{
18    BytecodeInstruction, CompilationStatus, CompiledFunction, CompiledGateSequence,
19    FusedGateOperation, GateSequencePattern, JITConfig, JITOptimization, JITOptimizationLevel,
20    JITPerformanceStats, MatrixComputeFunction, MatrixOpType, MatrixOperation, SIMDInstruction,
21    SIMDLayout, VectorizedOperation,
22};
23
24/// JIT compilation engine
25pub struct JITCompiler {
26    /// Configuration
27    pub(crate) config: JITConfig,
28    /// Pattern database
29    pub(crate) patterns: Arc<RwLock<HashMap<u64, GateSequencePattern>>>,
30    /// Compiled sequence cache
31    pub(crate) compiled_cache: Arc<RwLock<HashMap<u64, CompiledGateSequence>>>,
32    /// Pattern analyzer
33    pub(crate) pattern_analyzer: Arc<Mutex<PatternAnalyzer>>,
34    /// Runtime profiler
35    pub(crate) profiler: Arc<Mutex<RuntimeProfiler>>,
36    /// Compilation statistics
37    pub(crate) stats: Arc<RwLock<JITCompilerStats>>,
38}
39
40impl JITCompiler {
41    /// Create a new JIT compiler
42    #[must_use]
43    pub fn new(config: JITConfig) -> Self {
44        Self {
45            config,
46            patterns: Arc::new(RwLock::new(HashMap::new())),
47            compiled_cache: Arc::new(RwLock::new(HashMap::new())),
48            pattern_analyzer: Arc::new(Mutex::new(PatternAnalyzer::new())),
49            profiler: Arc::new(Mutex::new(RuntimeProfiler::new())),
50            stats: Arc::new(RwLock::new(JITCompilerStats::default())),
51        }
52    }
53
54    /// Analyze gate sequence and potentially compile
55    pub fn analyze_sequence(&self, gates: &[InterfaceGate]) -> Result<Option<u64>> {
56        if gates.len() > self.config.max_sequence_length {
57            return Ok(None);
58        }
59
60        // Update patterns_analyzed counter
61        {
62            let mut stats = self
63                .stats
64                .write()
65                .expect("JIT stats lock should not be poisoned");
66            stats.patterns_analyzed += 1;
67        }
68
69        let pattern = Self::extract_pattern(gates)?;
70        let pattern_hash = pattern.hash;
71
72        // Update pattern frequency
73        {
74            let mut patterns = self
75                .patterns
76                .write()
77                .expect("JIT patterns lock should not be poisoned");
78            if let Some(existing_pattern) = patterns.get_mut(&pattern_hash) {
79                existing_pattern.frequency += 1;
80                existing_pattern.last_used = Instant::now();
81            } else {
82                patterns.insert(pattern_hash, pattern);
83            }
84        }
85
86        // Check if compilation threshold is met (compile after threshold is exceeded)
87        let should_compile = {
88            let patterns = self
89                .patterns
90                .read()
91                .expect("JIT patterns lock should not be poisoned");
92            if let Some(pattern) = patterns.get(&pattern_hash) {
93                pattern.frequency > self.config.compilation_threshold
94                    && pattern.compilation_status == CompilationStatus::NotCompiled
95            } else {
96                false
97            }
98        };
99
100        if should_compile {
101            self.compile_sequence(pattern_hash)?;
102        }
103
104        Ok(Some(pattern_hash))
105    }
106
107    /// Extract pattern from gate sequence
108    pub fn extract_pattern(gates: &[InterfaceGate]) -> Result<GateSequencePattern> {
109        let mut gate_types = Vec::new();
110        let mut target_qubits = Vec::new();
111
112        for gate in gates {
113            gate_types.push(gate.gate_type.clone());
114            target_qubits.push(gate.qubits.clone());
115        }
116
117        let mut pattern = GateSequencePattern {
118            gate_types,
119            target_qubits,
120            hash: 0,
121            frequency: 1,
122            last_used: Instant::now(),
123            compilation_status: CompilationStatus::NotCompiled,
124        };
125
126        // Calculate hash
127        use std::collections::hash_map::DefaultHasher;
128        use std::hash::Hash;
129        let mut hasher = DefaultHasher::new();
130        pattern.hash(&mut hasher);
131        pattern.hash = hasher.finish();
132
133        Ok(pattern)
134    }
135
136    /// Compile a gate sequence pattern
137    fn compile_sequence(&self, pattern_hash: u64) -> Result<()> {
138        // Mark as compiling
139        {
140            let mut patterns = self
141                .patterns
142                .write()
143                .expect("JIT patterns lock should not be poisoned");
144            if let Some(pattern) = patterns.get_mut(&pattern_hash) {
145                pattern.compilation_status = CompilationStatus::Compiling;
146            }
147        }
148
149        let compilation_start = Instant::now();
150
151        // Get pattern for compilation
152        let pattern = {
153            let patterns = self
154                .patterns
155                .read()
156                .expect("JIT patterns lock should not be poisoned");
157            patterns
158                .get(&pattern_hash)
159                .cloned()
160                .ok_or_else(|| SimulatorError::InvalidParameter("Pattern not found".to_string()))?
161        };
162
163        // Perform compilation
164        let compiled_function = self.perform_compilation(&pattern)?;
165        let compilation_time = compilation_start.elapsed();
166
167        // Create compiled sequence
168        let compiled_sequence = CompiledGateSequence {
169            pattern: pattern.clone(),
170            compiled_function,
171            compilation_time,
172            performance_stats: JITPerformanceStats::default(),
173            memory_usage: Self::estimate_memory_usage(&pattern),
174            optimizations: self.apply_optimizations(&pattern)?,
175        };
176
177        // Store compiled sequence
178        {
179            let mut cache = self
180                .compiled_cache
181                .write()
182                .expect("JIT cache lock should not be poisoned");
183            cache.insert(pattern_hash, compiled_sequence);
184        }
185
186        // Update pattern status
187        {
188            let mut patterns = self
189                .patterns
190                .write()
191                .expect("JIT patterns lock should not be poisoned");
192            if let Some(pattern) = patterns.get_mut(&pattern_hash) {
193                pattern.compilation_status = CompilationStatus::Compiled;
194            }
195        }
196
197        // Update statistics
198        {
199            let mut stats = self
200                .stats
201                .write()
202                .expect("JIT stats lock should not be poisoned");
203            stats.total_compilations += 1;
204            stats.total_compilation_time += compilation_time;
205        }
206
207        Ok(())
208    }
209
210    /// Perform the actual compilation
211    fn perform_compilation(&self, pattern: &GateSequencePattern) -> Result<CompiledFunction> {
212        match self.config.optimization_level {
213            JITOptimizationLevel::None => Self::compile_basic(pattern),
214            JITOptimizationLevel::Basic => self.compile_with_basic_optimizations(pattern),
215            JITOptimizationLevel::Advanced => self.compile_with_advanced_optimizations(pattern),
216            JITOptimizationLevel::Aggressive => self.compile_with_aggressive_optimizations(pattern),
217        }
218    }
219
220    /// Basic compilation (bytecode generation)
221    fn compile_basic(pattern: &GateSequencePattern) -> Result<CompiledFunction> {
222        let mut instructions = Vec::new();
223
224        for (i, gate_type) in pattern.gate_types.iter().enumerate() {
225            let targets = &pattern.target_qubits[i];
226
227            let instruction = match targets.len() {
228                1 => BytecodeInstruction::ApplySingleQubit {
229                    gate_type: gate_type.clone(),
230                    target: targets[0],
231                },
232                2 => BytecodeInstruction::ApplyTwoQubit {
233                    gate_type: gate_type.clone(),
234                    control: targets[0],
235                    target: targets[1],
236                },
237                _ => BytecodeInstruction::ApplyMultiQubit {
238                    gate_type: gate_type.clone(),
239                    targets: targets.clone(),
240                },
241            };
242
243            instructions.push(instruction);
244        }
245
246        Ok(CompiledFunction::Bytecode { instructions })
247    }
248
249    /// Compilation with basic optimizations
250    fn compile_with_basic_optimizations(
251        &self,
252        pattern: &GateSequencePattern,
253    ) -> Result<CompiledFunction> {
254        let mut bytecode = Self::compile_basic(pattern)?;
255
256        if let CompiledFunction::Bytecode { instructions } = &mut bytecode {
257            // Apply constant folding
258            Self::apply_constant_folding(instructions)?;
259
260            // Apply dead code elimination
261            Self::apply_dead_code_elimination(instructions)?;
262        }
263
264        Ok(bytecode)
265    }
266
267    /// Compilation with advanced optimizations
268    fn compile_with_advanced_optimizations(
269        &self,
270        pattern: &GateSequencePattern,
271    ) -> Result<CompiledFunction> {
272        let mut bytecode = self.compile_with_basic_optimizations(pattern)?;
273
274        if let CompiledFunction::Bytecode { instructions } = &mut bytecode {
275            // Apply loop unrolling
276            self.apply_loop_unrolling(instructions)?;
277
278            // Apply vectorization
279            return Self::apply_vectorization(instructions);
280        }
281
282        Ok(bytecode)
283    }
284
285    /// Compilation with aggressive optimizations
286    fn compile_with_aggressive_optimizations(
287        &self,
288        pattern: &GateSequencePattern,
289    ) -> Result<CompiledFunction> {
290        // First try advanced optimizations
291        let advanced_result = self.compile_with_advanced_optimizations(pattern)?;
292
293        // Apply aggressive optimizations
294        match advanced_result {
295            CompiledFunction::Bytecode { instructions } => {
296                // Try to convert to optimized matrix operations
297                if let Ok(matrix_ops) = self.convert_to_matrix_operations(&instructions) {
298                    return Ok(CompiledFunction::MatrixOps {
299                        operations: matrix_ops,
300                    });
301                }
302
303                // Apply gate fusion
304                if let Ok(fused_ops) = self.apply_gate_fusion(&instructions) {
305                    return Ok(CompiledFunction::Bytecode {
306                        instructions: fused_ops,
307                    });
308                }
309
310                Ok(CompiledFunction::Bytecode { instructions })
311            }
312            other => Ok(other),
313        }
314    }
315
316    /// Apply constant folding optimization
317    pub fn apply_constant_folding(instructions: &mut [BytecodeInstruction]) -> Result<()> {
318        for instruction in instructions.iter_mut() {
319            match instruction {
320                BytecodeInstruction::ApplySingleQubit { gate_type, .. }
321                | BytecodeInstruction::ApplyTwoQubit { gate_type, .. }
322                | BytecodeInstruction::ApplyMultiQubit { gate_type, .. } => {
323                    // Fold zero rotations to identity
324                    match gate_type {
325                        InterfaceGateType::RX(angle)
326                        | InterfaceGateType::RY(angle)
327                        | InterfaceGateType::RZ(angle)
328                            if angle.abs() < f64::EPSILON =>
329                        {
330                            *gate_type = InterfaceGateType::Identity;
331                        }
332                        _ => {}
333                    }
334                }
335                _ => {}
336            }
337        }
338        Ok(())
339    }
340
341    /// Apply dead code elimination
342    pub fn apply_dead_code_elimination(instructions: &mut Vec<BytecodeInstruction>) -> Result<()> {
343        instructions.retain(|instruction| {
344            match instruction {
345                BytecodeInstruction::ApplySingleQubit { gate_type, .. } => {
346                    // Remove identity operations
347                    !matches!(gate_type, InterfaceGateType::Identity)
348                }
349                _ => true,
350            }
351        });
352        Ok(())
353    }
354
355    /// Apply loop unrolling optimization
356    fn apply_loop_unrolling(&self, instructions: &mut Vec<BytecodeInstruction>) -> Result<()> {
357        let mut unrolled = Vec::new();
358        let mut i = 0;
359
360        while i < instructions.len() {
361            if let Some(repeat_count) = Self::find_repeated_sequence(&instructions[i..]) {
362                for _ in 0..repeat_count {
363                    unrolled.push(instructions[i].clone());
364                }
365                i += repeat_count;
366            } else {
367                unrolled.push(instructions[i].clone());
368                i += 1;
369            }
370        }
371
372        *instructions = unrolled;
373        Ok(())
374    }
375
376    /// Find repeated instruction sequences
377    fn find_repeated_sequence(instructions: &[BytecodeInstruction]) -> Option<usize> {
378        if instructions.len() < 2 {
379            return None;
380        }
381
382        if instructions.len() >= 2
383            && std::mem::discriminant(&instructions[0]) == std::mem::discriminant(&instructions[1])
384        {
385            return Some(2);
386        }
387
388        None
389    }
390
391    /// Apply vectorization optimization
392    fn apply_vectorization(instructions: &[BytecodeInstruction]) -> Result<CompiledFunction> {
393        let mut vectorized_ops = Vec::new();
394
395        for instruction in instructions {
396            match instruction {
397                BytecodeInstruction::ApplySingleQubit { gate_type, .. } => {
398                    let simd_instruction = match gate_type {
399                        InterfaceGateType::PauliX
400                        | InterfaceGateType::X
401                        | InterfaceGateType::PauliY
402                        | InterfaceGateType::PauliZ => SIMDInstruction::GateApplication,
403                        InterfaceGateType::RX(_)
404                        | InterfaceGateType::RY(_)
405                        | InterfaceGateType::RZ(_) => SIMDInstruction::Rotation,
406                        _ => SIMDInstruction::GateApplication,
407                    };
408
409                    vectorized_ops.push(VectorizedOperation {
410                        instruction: simd_instruction,
411                        layout: SIMDLayout::StructureOfArrays,
412                        vector_length: 8,
413                        parallel_factor: 1,
414                    });
415                }
416                _ => {
417                    vectorized_ops.push(VectorizedOperation {
418                        instruction: SIMDInstruction::GateApplication,
419                        layout: SIMDLayout::Interleaved,
420                        vector_length: 4,
421                        parallel_factor: 1,
422                    });
423                }
424            }
425        }
426
427        Ok(CompiledFunction::SIMDOps { vectorized_ops })
428    }
429
430    /// Convert bytecode to matrix operations
431    fn convert_to_matrix_operations(
432        &self,
433        instructions: &[BytecodeInstruction],
434    ) -> Result<Vec<MatrixOperation>> {
435        let mut operations = Vec::new();
436
437        for instruction in instructions {
438            match instruction {
439                BytecodeInstruction::ApplySingleQubit { gate_type, target } => {
440                    let matrix = Self::get_gate_matrix(gate_type)?;
441                    operations.push(MatrixOperation {
442                        op_type: MatrixOpType::DirectMult,
443                        targets: vec![*target],
444                        matrix: Some(matrix),
445                        compute_matrix: MatrixComputeFunction::Precomputed(Self::get_gate_matrix(
446                            gate_type,
447                        )?),
448                    });
449                }
450                BytecodeInstruction::ApplyTwoQubit {
451                    gate_type,
452                    control,
453                    target,
454                } => {
455                    let matrix = Self::get_two_qubit_gate_matrix(gate_type)?;
456                    operations.push(MatrixOperation {
457                        op_type: MatrixOpType::KroneckerProduct,
458                        targets: vec![*control, *target],
459                        matrix: Some(matrix),
460                        compute_matrix: MatrixComputeFunction::Precomputed(
461                            Self::get_two_qubit_gate_matrix(gate_type)?,
462                        ),
463                    });
464                }
465                _ => {
466                    operations.push(MatrixOperation {
467                        op_type: MatrixOpType::TensorContraction,
468                        targets: vec![0],
469                        matrix: None,
470                        compute_matrix: MatrixComputeFunction::Runtime("default".to_string()),
471                    });
472                }
473            }
474        }
475
476        Ok(operations)
477    }
478
479    /// Apply gate fusion optimization
480    fn apply_gate_fusion(
481        &self,
482        instructions: &[BytecodeInstruction],
483    ) -> Result<Vec<BytecodeInstruction>> {
484        let mut fused_instructions = Vec::new();
485        let mut i = 0;
486
487        while i < instructions.len() {
488            if let Some(fused_length) = Self::find_fusable_sequence(&instructions[i..]) {
489                let gates =
490                    Self::extract_gates_from_instructions(&instructions[i..i + fused_length])?;
491                let fused_matrix = Self::compute_fused_matrix(&gates)?;
492                let targets =
493                    Self::extract_targets_from_instructions(&instructions[i..i + fused_length]);
494
495                let fused_op = FusedGateOperation {
496                    gates,
497                    fused_matrix,
498                    targets,
499                    optimization_level: self.config.optimization_level,
500                };
501
502                fused_instructions.push(BytecodeInstruction::FusedOperation {
503                    operation: fused_op,
504                });
505
506                i += fused_length;
507            } else {
508                fused_instructions.push(instructions[i].clone());
509                i += 1;
510            }
511        }
512
513        Ok(fused_instructions)
514    }
515
516    /// Find fusable gate sequences
517    fn find_fusable_sequence(instructions: &[BytecodeInstruction]) -> Option<usize> {
518        if instructions.len() < 2 {
519            return None;
520        }
521
522        if let (
523            BytecodeInstruction::ApplySingleQubit {
524                target: target1, ..
525            },
526            BytecodeInstruction::ApplySingleQubit {
527                target: target2, ..
528            },
529        ) = (&instructions[0], &instructions[1])
530        {
531            if target1 == target2 {
532                return Some(2);
533            }
534        }
535
536        None
537    }
538
539    /// Extract gates from bytecode instructions
540    fn extract_gates_from_instructions(
541        instructions: &[BytecodeInstruction],
542    ) -> Result<Vec<InterfaceGate>> {
543        let mut gates = Vec::new();
544
545        for instruction in instructions {
546            match instruction {
547                BytecodeInstruction::ApplySingleQubit { gate_type, target } => {
548                    gates.push(InterfaceGate::new(gate_type.clone(), vec![*target]));
549                }
550                BytecodeInstruction::ApplyTwoQubit {
551                    gate_type,
552                    control,
553                    target,
554                } => {
555                    gates.push(InterfaceGate::new(
556                        gate_type.clone(),
557                        vec![*control, *target],
558                    ));
559                }
560                BytecodeInstruction::ApplyMultiQubit { gate_type, targets } => {
561                    gates.push(InterfaceGate::new(gate_type.clone(), targets.clone()));
562                }
563                // FusedOperation: extract the embedded gate type and qubits.
564                BytecodeInstruction::FusedOperation { operation } => {
565                    if !operation.targets.is_empty() {
566                        gates.push(InterfaceGate::new(
567                            InterfaceGateType::Identity,
568                            operation.targets.clone(),
569                        ));
570                    }
571                }
572                // Prefetch and Barrier produce no gates.
573                BytecodeInstruction::Prefetch { .. } | BytecodeInstruction::Barrier => {}
574            }
575        }
576
577        Ok(gates)
578    }
579
580    /// Extract target qubits from instructions
581    fn extract_targets_from_instructions(instructions: &[BytecodeInstruction]) -> Vec<usize> {
582        let mut targets = std::collections::HashSet::new();
583
584        for instruction in instructions {
585            match instruction {
586                BytecodeInstruction::ApplySingleQubit { target, .. } => {
587                    targets.insert(*target);
588                }
589                BytecodeInstruction::ApplyTwoQubit {
590                    control, target, ..
591                } => {
592                    targets.insert(*control);
593                    targets.insert(*target);
594                }
595                BytecodeInstruction::ApplyMultiQubit {
596                    targets: multi_targets,
597                    ..
598                } => {
599                    for &target in multi_targets {
600                        targets.insert(target);
601                    }
602                }
603                _ => {}
604            }
605        }
606
607        targets.into_iter().collect()
608    }
609
610    /// Compute fused matrix for gate sequence
611    fn compute_fused_matrix(gates: &[InterfaceGate]) -> Result<Array2<Complex64>> {
612        if gates.is_empty() {
613            return Err(SimulatorError::InvalidParameter(
614                "Empty gate sequence".to_string(),
615            ));
616        }
617
618        let mut result = Self::get_gate_matrix(&gates[0].gate_type)?;
619
620        for gate in &gates[1..] {
621            let gate_matrix = Self::get_gate_matrix(&gate.gate_type)?;
622            result = result.dot(&gate_matrix);
623        }
624
625        Ok(result)
626    }
627
628    /// Get matrix representation of a gate
629    pub fn get_gate_matrix(gate_type: &InterfaceGateType) -> Result<Array2<Complex64>> {
630        let matrix = match gate_type {
631            InterfaceGateType::Identity => Array2::from_shape_vec(
632                (2, 2),
633                vec![
634                    Complex64::new(1.0, 0.0),
635                    Complex64::new(0.0, 0.0),
636                    Complex64::new(0.0, 0.0),
637                    Complex64::new(1.0, 0.0),
638                ],
639            )
640            .expect("2x2 matrix shape should be valid"),
641            InterfaceGateType::PauliX | InterfaceGateType::X => Array2::from_shape_vec(
642                (2, 2),
643                vec![
644                    Complex64::new(0.0, 0.0),
645                    Complex64::new(1.0, 0.0),
646                    Complex64::new(1.0, 0.0),
647                    Complex64::new(0.0, 0.0),
648                ],
649            )
650            .expect("2x2 matrix shape should be valid"),
651            InterfaceGateType::PauliY => Array2::from_shape_vec(
652                (2, 2),
653                vec![
654                    Complex64::new(0.0, 0.0),
655                    Complex64::new(0.0, -1.0),
656                    Complex64::new(0.0, 1.0),
657                    Complex64::new(0.0, 0.0),
658                ],
659            )
660            .expect("2x2 matrix shape should be valid"),
661            InterfaceGateType::PauliZ => Array2::from_shape_vec(
662                (2, 2),
663                vec![
664                    Complex64::new(1.0, 0.0),
665                    Complex64::new(0.0, 0.0),
666                    Complex64::new(0.0, 0.0),
667                    Complex64::new(-1.0, 0.0),
668                ],
669            )
670            .expect("2x2 matrix shape should be valid"),
671            InterfaceGateType::Hadamard | InterfaceGateType::H => {
672                let sqrt2_inv = 1.0 / (2.0_f64).sqrt();
673                Array2::from_shape_vec(
674                    (2, 2),
675                    vec![
676                        Complex64::new(sqrt2_inv, 0.0),
677                        Complex64::new(sqrt2_inv, 0.0),
678                        Complex64::new(sqrt2_inv, 0.0),
679                        Complex64::new(-sqrt2_inv, 0.0),
680                    ],
681                )
682                .expect("2x2 matrix shape should be valid")
683            }
684            InterfaceGateType::S => Array2::from_shape_vec(
685                (2, 2),
686                vec![
687                    Complex64::new(1.0, 0.0),
688                    Complex64::new(0.0, 0.0),
689                    Complex64::new(0.0, 0.0),
690                    Complex64::new(0.0, 1.0),
691                ],
692            )
693            .expect("2x2 matrix shape should be valid"),
694            InterfaceGateType::T => {
695                let phase = Complex64::new(0.0, std::f64::consts::PI / 4.0).exp();
696                Array2::from_shape_vec(
697                    (2, 2),
698                    vec![
699                        Complex64::new(1.0, 0.0),
700                        Complex64::new(0.0, 0.0),
701                        Complex64::new(0.0, 0.0),
702                        phase,
703                    ],
704                )
705                .expect("2x2 matrix shape should be valid")
706            }
707            InterfaceGateType::RX(angle) => {
708                let cos_half = (angle / 2.0).cos();
709                let sin_half = (angle / 2.0).sin();
710                Array2::from_shape_vec(
711                    (2, 2),
712                    vec![
713                        Complex64::new(cos_half, 0.0),
714                        Complex64::new(0.0, -sin_half),
715                        Complex64::new(0.0, -sin_half),
716                        Complex64::new(cos_half, 0.0),
717                    ],
718                )
719                .expect("2x2 matrix shape should be valid")
720            }
721            InterfaceGateType::RY(angle) => {
722                let cos_half = (angle / 2.0).cos();
723                let sin_half = (angle / 2.0).sin();
724                Array2::from_shape_vec(
725                    (2, 2),
726                    vec![
727                        Complex64::new(cos_half, 0.0),
728                        Complex64::new(-sin_half, 0.0),
729                        Complex64::new(sin_half, 0.0),
730                        Complex64::new(cos_half, 0.0),
731                    ],
732                )
733                .expect("2x2 matrix shape should be valid")
734            }
735            InterfaceGateType::RZ(angle) => {
736                let exp_neg = Complex64::new(0.0, -angle / 2.0).exp();
737                let exp_pos = Complex64::new(0.0, angle / 2.0).exp();
738                Array2::from_shape_vec(
739                    (2, 2),
740                    vec![
741                        exp_neg,
742                        Complex64::new(0.0, 0.0),
743                        Complex64::new(0.0, 0.0),
744                        exp_pos,
745                    ],
746                )
747                .expect("2x2 matrix shape should be valid")
748            }
749            InterfaceGateType::Phase(angle) => {
750                let phase = Complex64::new(0.0, *angle).exp();
751                Array2::from_shape_vec(
752                    (2, 2),
753                    vec![
754                        Complex64::new(1.0, 0.0),
755                        Complex64::new(0.0, 0.0),
756                        Complex64::new(0.0, 0.0),
757                        phase,
758                    ],
759                )
760                .expect("2x2 matrix shape should be valid")
761            }
762            _ => Array2::from_shape_vec(
763                (2, 2),
764                vec![
765                    Complex64::new(1.0, 0.0),
766                    Complex64::new(0.0, 0.0),
767                    Complex64::new(0.0, 0.0),
768                    Complex64::new(1.0, 0.0),
769                ],
770            )
771            .expect("2x2 matrix shape should be valid"),
772        };
773
774        Ok(matrix)
775    }
776
777    /// Get matrix representation of a two-qubit gate
778    pub fn get_two_qubit_gate_matrix(gate_type: &InterfaceGateType) -> Result<Array2<Complex64>> {
779        let matrix = match gate_type {
780            InterfaceGateType::CNOT => Array2::from_shape_vec(
781                (4, 4),
782                vec![
783                    Complex64::new(1.0, 0.0),
784                    Complex64::new(0.0, 0.0),
785                    Complex64::new(0.0, 0.0),
786                    Complex64::new(0.0, 0.0),
787                    Complex64::new(0.0, 0.0),
788                    Complex64::new(1.0, 0.0),
789                    Complex64::new(0.0, 0.0),
790                    Complex64::new(0.0, 0.0),
791                    Complex64::new(0.0, 0.0),
792                    Complex64::new(0.0, 0.0),
793                    Complex64::new(0.0, 0.0),
794                    Complex64::new(1.0, 0.0),
795                    Complex64::new(0.0, 0.0),
796                    Complex64::new(0.0, 0.0),
797                    Complex64::new(1.0, 0.0),
798                    Complex64::new(0.0, 0.0),
799                ],
800            )
801            .expect("4x4 matrix shape should be valid"),
802            InterfaceGateType::CZ => Array2::from_shape_vec(
803                (4, 4),
804                vec![
805                    Complex64::new(1.0, 0.0),
806                    Complex64::new(0.0, 0.0),
807                    Complex64::new(0.0, 0.0),
808                    Complex64::new(0.0, 0.0),
809                    Complex64::new(0.0, 0.0),
810                    Complex64::new(1.0, 0.0),
811                    Complex64::new(0.0, 0.0),
812                    Complex64::new(0.0, 0.0),
813                    Complex64::new(0.0, 0.0),
814                    Complex64::new(0.0, 0.0),
815                    Complex64::new(1.0, 0.0),
816                    Complex64::new(0.0, 0.0),
817                    Complex64::new(0.0, 0.0),
818                    Complex64::new(0.0, 0.0),
819                    Complex64::new(0.0, 0.0),
820                    Complex64::new(-1.0, 0.0),
821                ],
822            )
823            .expect("4x4 matrix shape should be valid"),
824            InterfaceGateType::SWAP => Array2::from_shape_vec(
825                (4, 4),
826                vec![
827                    Complex64::new(1.0, 0.0),
828                    Complex64::new(0.0, 0.0),
829                    Complex64::new(0.0, 0.0),
830                    Complex64::new(0.0, 0.0),
831                    Complex64::new(0.0, 0.0),
832                    Complex64::new(0.0, 0.0),
833                    Complex64::new(1.0, 0.0),
834                    Complex64::new(0.0, 0.0),
835                    Complex64::new(0.0, 0.0),
836                    Complex64::new(1.0, 0.0),
837                    Complex64::new(0.0, 0.0),
838                    Complex64::new(0.0, 0.0),
839                    Complex64::new(0.0, 0.0),
840                    Complex64::new(0.0, 0.0),
841                    Complex64::new(0.0, 0.0),
842                    Complex64::new(1.0, 0.0),
843                ],
844            )
845            .expect("4x4 matrix shape should be valid"),
846            _ => Array2::from_shape_vec(
847                (4, 4),
848                vec![
849                    Complex64::new(1.0, 0.0),
850                    Complex64::new(0.0, 0.0),
851                    Complex64::new(0.0, 0.0),
852                    Complex64::new(0.0, 0.0),
853                    Complex64::new(0.0, 0.0),
854                    Complex64::new(1.0, 0.0),
855                    Complex64::new(0.0, 0.0),
856                    Complex64::new(0.0, 0.0),
857                    Complex64::new(0.0, 0.0),
858                    Complex64::new(0.0, 0.0),
859                    Complex64::new(1.0, 0.0),
860                    Complex64::new(0.0, 0.0),
861                    Complex64::new(0.0, 0.0),
862                    Complex64::new(0.0, 0.0),
863                    Complex64::new(0.0, 0.0),
864                    Complex64::new(1.0, 0.0),
865                ],
866            )
867            .expect("4x4 matrix shape should be valid"),
868        };
869
870        Ok(matrix)
871    }
872
873    /// Estimate memory usage for a pattern
874    fn estimate_memory_usage(pattern: &GateSequencePattern) -> usize {
875        let base_size = std::mem::size_of::<CompiledGateSequence>();
876        let pattern_size = pattern.gate_types.len() * 64;
877        let matrix_size = pattern.gate_types.len() * 32 * std::mem::size_of::<Complex64>();
878
879        base_size + pattern_size + matrix_size
880    }
881
882    /// Apply optimizations to a pattern
883    fn apply_optimizations(&self, _pattern: &GateSequencePattern) -> Result<Vec<JITOptimization>> {
884        let mut optimizations = vec![
885            JITOptimization::ConstantFolding,
886            JITOptimization::DeadCodeElimination,
887        ];
888
889        match self.config.optimization_level {
890            JITOptimizationLevel::Basic => {}
891            JITOptimizationLevel::Advanced => {
892                optimizations.extend_from_slice(&[
893                    JITOptimization::LoopUnrolling,
894                    JITOptimization::Vectorization,
895                ]);
896            }
897            JITOptimizationLevel::Aggressive => {
898                optimizations.extend_from_slice(&[
899                    JITOptimization::LoopUnrolling,
900                    JITOptimization::Vectorization,
901                    JITOptimization::GateFusion,
902                    JITOptimization::InlineExpansion,
903                    JITOptimization::MemoryLayoutOptimization,
904                ]);
905            }
906            JITOptimizationLevel::None => {
907                optimizations.clear();
908            }
909        }
910
911        Ok(optimizations)
912    }
913
914    /// Execute a compiled sequence
915    pub fn execute_compiled(
916        &self,
917        pattern_hash: u64,
918        state: &mut Array1<Complex64>,
919    ) -> Result<Duration> {
920        let execution_start = Instant::now();
921
922        let compiled_sequence = {
923            let cache = self
924                .compiled_cache
925                .read()
926                .expect("JIT cache lock should not be poisoned");
927            cache.get(&pattern_hash).cloned().ok_or_else(|| {
928                SimulatorError::InvalidParameter("Compiled sequence not found".to_string())
929            })?
930        };
931
932        match &compiled_sequence.compiled_function {
933            CompiledFunction::Bytecode { instructions } => {
934                self.execute_bytecode(instructions, state)?;
935            }
936            CompiledFunction::MatrixOps { operations } => {
937                self.execute_matrix_operations(operations, state)?;
938            }
939            CompiledFunction::SIMDOps { vectorized_ops } => {
940                self.execute_simd_operations(vectorized_ops, state)?;
941            }
942            CompiledFunction::NativeCode { .. } => {
943                return Err(SimulatorError::NotImplemented(
944                    "Native code execution".to_string(),
945                ));
946            }
947        }
948
949        let execution_time = execution_start.elapsed();
950
951        {
952            let mut cache = self
953                .compiled_cache
954                .write()
955                .expect("JIT cache lock should not be poisoned");
956            if let Some(sequence) = cache.get_mut(&pattern_hash) {
957                let stats = &mut sequence.performance_stats;
958                stats.execution_count += 1;
959                stats.total_execution_time += execution_time;
960                stats.average_execution_time =
961                    stats.total_execution_time / stats.execution_count as u32;
962                if execution_time < stats.best_execution_time {
963                    stats.best_execution_time = execution_time;
964                }
965            }
966        }
967
968        Ok(execution_time)
969    }
970
971    /// Execute bytecode instructions
972    fn execute_bytecode(
973        &self,
974        instructions: &[BytecodeInstruction],
975        state: &mut Array1<Complex64>,
976    ) -> Result<()> {
977        for instruction in instructions {
978            match instruction {
979                BytecodeInstruction::ApplySingleQubit { gate_type, target } => {
980                    Self::apply_single_qubit_gate(gate_type, *target, state)?;
981                }
982                BytecodeInstruction::ApplyTwoQubit {
983                    gate_type,
984                    control,
985                    target,
986                } => {
987                    Self::apply_two_qubit_gate(gate_type, *control, *target, state)?;
988                }
989                BytecodeInstruction::ApplyMultiQubit { gate_type, targets } => {
990                    Self::apply_multi_qubit_gate(gate_type, targets, state)?;
991                }
992                BytecodeInstruction::FusedOperation { operation } => {
993                    Self::apply_fused_operation(operation, state)?;
994                }
995                BytecodeInstruction::Prefetch { .. } => {}
996                BytecodeInstruction::Barrier => {
997                    std::sync::atomic::fence(std::sync::atomic::Ordering::SeqCst);
998                }
999            }
1000        }
1001        Ok(())
1002    }
1003
1004    /// Apply single-qubit gate to state
1005    fn apply_single_qubit_gate(
1006        gate_type: &InterfaceGateType,
1007        target: usize,
1008        state: &mut Array1<Complex64>,
1009    ) -> Result<()> {
1010        let num_qubits = (state.len() as f64).log2() as usize;
1011        if target >= num_qubits {
1012            return Err(SimulatorError::InvalidParameter(
1013                "Target qubit out of range".to_string(),
1014            ));
1015        }
1016
1017        let matrix = Self::get_gate_matrix(gate_type)?;
1018
1019        for i in 0..(1 << num_qubits) {
1020            if (i >> target) & 1 == 0 {
1021                let j = i | (1 << target);
1022                let amp0 = state[i];
1023                let amp1 = state[j];
1024
1025                state[i] = matrix[(0, 0)] * amp0 + matrix[(0, 1)] * amp1;
1026                state[j] = matrix[(1, 0)] * amp0 + matrix[(1, 1)] * amp1;
1027            }
1028        }
1029
1030        Ok(())
1031    }
1032
1033    /// Apply two-qubit gate to state
1034    fn apply_two_qubit_gate(
1035        gate_type: &InterfaceGateType,
1036        control: usize,
1037        target: usize,
1038        state: &mut Array1<Complex64>,
1039    ) -> Result<()> {
1040        let num_qubits = (state.len() as f64).log2() as usize;
1041        if control >= num_qubits || target >= num_qubits {
1042            return Err(SimulatorError::InvalidParameter(
1043                "Qubit index out of range".to_string(),
1044            ));
1045        }
1046
1047        match gate_type {
1048            InterfaceGateType::CNOT => {
1049                for i in 0..(1 << num_qubits) {
1050                    if (i >> control) & 1 == 1 {
1051                        let j = i ^ (1 << target);
1052                        if i < j {
1053                            let temp = state[i];
1054                            state[i] = state[j];
1055                            state[j] = temp;
1056                        }
1057                    }
1058                }
1059            }
1060            InterfaceGateType::CZ => {
1061                for i in 0..(1 << num_qubits) {
1062                    if (i >> control) & 1 == 1 && (i >> target) & 1 == 1 {
1063                        state[i] = -state[i];
1064                    }
1065                }
1066            }
1067            InterfaceGateType::SWAP => {
1068                for i in 0..(1 << num_qubits) {
1069                    let bit_control = (i >> control) & 1;
1070                    let bit_target = (i >> target) & 1;
1071                    if bit_control != bit_target {
1072                        let j = i ^ (1 << control) ^ (1 << target);
1073                        if i < j {
1074                            let temp = state[i];
1075                            state[i] = state[j];
1076                            state[j] = temp;
1077                        }
1078                    }
1079                }
1080            }
1081            _ => {
1082                let matrix = Self::get_two_qubit_gate_matrix(gate_type)?;
1083                Self::apply_two_qubit_matrix(&matrix, control, target, state)?;
1084            }
1085        }
1086
1087        Ok(())
1088    }
1089
1090    /// Apply multi-qubit gate to state.
1091    /// Handles up to 3-qubit gates via controlled-gate expansion; larger gates
1092    /// are applied by tensor-product with the 2-qubit sub-matrix.
1093    fn apply_multi_qubit_gate(
1094        gate_type: &InterfaceGateType,
1095        targets: &[usize],
1096        state: &mut Array1<Complex64>,
1097    ) -> Result<()> {
1098        match targets.len() {
1099            0 => Ok(()),
1100            1 => Self::apply_single_qubit_gate(gate_type, targets[0], state),
1101            2 => Self::apply_two_qubit_gate(gate_type, targets[0], targets[1], state),
1102            _ => {
1103                // For 3+ qubits: apply the gate matrix to the first two target qubits
1104                // controlled by the remaining targets (Toffoli-style decomposition).
1105                // If the gate has a known 2-qubit matrix, use it; otherwise use Identity.
1106                let matrix =
1107                    Self::get_two_qubit_gate_matrix(gate_type).unwrap_or_else(|_| Array2::eye(4));
1108                let num_qubits = (state.len() as f64).log2() as usize;
1109                let control_qubits = &targets[2..];
1110                let q0 = targets[0];
1111                let q1 = targets[1];
1112                for basis in 0..(1_usize << num_qubits) {
1113                    // Only act where all extra control qubits are |1⟩.
1114                    let controls_satisfied = control_qubits
1115                        .iter()
1116                        .all(|&cq| cq < num_qubits && (basis >> cq) & 1 == 1);
1117                    if !controls_satisfied {
1118                        continue;
1119                    }
1120                    let b0 = (basis >> q0) & 1;
1121                    let b1 = (basis >> q1) & 1;
1122                    if b0 == 0 && b1 == 0 {
1123                        let i00 = basis;
1124                        let i01 = basis ^ (1 << q1);
1125                        let i10 = basis ^ (1 << q0);
1126                        let i11 = basis ^ (1 << q0) ^ (1 << q1);
1127                        let a00 = state[i00];
1128                        let a01 = state[i01];
1129                        let a10 = state[i10];
1130                        let a11 = state[i11];
1131                        state[i00] = matrix[(0, 0)] * a00
1132                            + matrix[(0, 1)] * a01
1133                            + matrix[(0, 2)] * a10
1134                            + matrix[(0, 3)] * a11;
1135                        state[i01] = matrix[(1, 0)] * a00
1136                            + matrix[(1, 1)] * a01
1137                            + matrix[(1, 2)] * a10
1138                            + matrix[(1, 3)] * a11;
1139                        state[i10] = matrix[(2, 0)] * a00
1140                            + matrix[(2, 1)] * a01
1141                            + matrix[(2, 2)] * a10
1142                            + matrix[(2, 3)] * a11;
1143                        state[i11] = matrix[(3, 0)] * a00
1144                            + matrix[(3, 1)] * a01
1145                            + matrix[(3, 2)] * a10
1146                            + matrix[(3, 3)] * a11;
1147                    }
1148                }
1149                Ok(())
1150            }
1151        }
1152    }
1153
1154    /// Apply fused operation to state
1155    fn apply_fused_operation(
1156        operation: &FusedGateOperation,
1157        state: &mut Array1<Complex64>,
1158    ) -> Result<()> {
1159        if operation.targets.len() == 1 {
1160            let target = operation.targets[0];
1161            let num_qubits = (state.len() as f64).log2() as usize;
1162
1163            for i in 0..(1 << num_qubits) {
1164                if (i >> target) & 1 == 0 {
1165                    let j = i | (1 << target);
1166                    let amp0 = state[i];
1167                    let amp1 = state[j];
1168
1169                    state[i] = operation.fused_matrix[(0, 0)] * amp0
1170                        + operation.fused_matrix[(0, 1)] * amp1;
1171                    state[j] = operation.fused_matrix[(1, 0)] * amp0
1172                        + operation.fused_matrix[(1, 1)] * amp1;
1173                }
1174            }
1175        }
1176
1177        Ok(())
1178    }
1179
1180    /// Execute matrix operations
1181    fn execute_matrix_operations(
1182        &self,
1183        operations: &[MatrixOperation],
1184        state: &mut Array1<Complex64>,
1185    ) -> Result<()> {
1186        for operation in operations {
1187            match &operation.op_type {
1188                MatrixOpType::DirectMult => {
1189                    if let Some(matrix) = &operation.matrix {
1190                        for &target in &operation.targets {
1191                            Self::apply_matrix_to_target(matrix, target, state)?;
1192                        }
1193                    }
1194                }
1195                MatrixOpType::KroneckerProduct => {
1196                    if operation.targets.len() == 2 {
1197                        if let Some(matrix) = operation.matrix.as_ref() {
1198                            let control = operation.targets[0];
1199                            let target = operation.targets[1];
1200                            Self::apply_two_qubit_matrix(matrix, control, target, state)?;
1201                        }
1202                    }
1203                }
1204                MatrixOpType::TensorContraction => {
1205                    // Tensor contraction: apply each target qubit's sub-matrix extracted
1206                    // from the full stored matrix via sequential 2×2 qubit slicing.
1207                    if let Some(matrix) = &operation.matrix {
1208                        for &target in &operation.targets {
1209                            if matrix.shape() == [2, 2] {
1210                                Self::apply_matrix_to_target(matrix, target, state)?;
1211                            }
1212                        }
1213                    }
1214                }
1215                MatrixOpType::SparseOperation => {
1216                    // Sparse: treat as direct mult on each target (matrix already stores
1217                    // the sparse action in dense form for targets involved).
1218                    if let Some(matrix) = &operation.matrix {
1219                        match operation.targets.len() {
1220                            1 => Self::apply_matrix_to_target(matrix, operation.targets[0], state)?,
1221                            2 => Self::apply_two_qubit_matrix(
1222                                matrix,
1223                                operation.targets[0],
1224                                operation.targets[1],
1225                                state,
1226                            )?,
1227                            _ => {}
1228                        }
1229                    }
1230                }
1231            }
1232        }
1233        Ok(())
1234    }
1235
1236    /// Apply matrix to specific target qubit
1237    fn apply_matrix_to_target(
1238        matrix: &Array2<Complex64>,
1239        target: usize,
1240        state: &mut Array1<Complex64>,
1241    ) -> Result<()> {
1242        let num_qubits = (state.len() as f64).log2() as usize;
1243        if target >= num_qubits {
1244            return Err(SimulatorError::InvalidParameter(
1245                "Target qubit out of range".to_string(),
1246            ));
1247        }
1248
1249        for i in 0..(1 << num_qubits) {
1250            if (i >> target) & 1 == 0 {
1251                let j = i | (1 << target);
1252                let amp0 = state[i];
1253                let amp1 = state[j];
1254
1255                state[i] = matrix[(0, 0)] * amp0 + matrix[(0, 1)] * amp1;
1256                state[j] = matrix[(1, 0)] * amp0 + matrix[(1, 1)] * amp1;
1257            }
1258        }
1259
1260        Ok(())
1261    }
1262
1263    /// Apply two-qubit matrix
1264    fn apply_two_qubit_matrix(
1265        matrix: &Array2<Complex64>,
1266        control: usize,
1267        target: usize,
1268        state: &mut Array1<Complex64>,
1269    ) -> Result<()> {
1270        let num_qubits = (state.len() as f64).log2() as usize;
1271        if control >= num_qubits || target >= num_qubits {
1272            return Err(SimulatorError::InvalidParameter(
1273                "Qubit index out of range".to_string(),
1274            ));
1275        }
1276
1277        for i in 0..(1 << num_qubits) {
1278            let control_bit = (i >> control) & 1;
1279            let target_bit = (i >> target) & 1;
1280            let basis_state = control_bit * 2 + target_bit;
1281
1282            if basis_state == 0 {
1283                let i00 = i;
1284                let i01 = i ^ (1 << target);
1285                let i10 = i ^ (1 << control);
1286                let i11 = i ^ (1 << control) ^ (1 << target);
1287
1288                let amp00 = state[i00];
1289                let amp01 = state[i01];
1290                let amp10 = state[i10];
1291                let amp11 = state[i11];
1292
1293                state[i00] = matrix[(0, 0)] * amp00
1294                    + matrix[(0, 1)] * amp01
1295                    + matrix[(0, 2)] * amp10
1296                    + matrix[(0, 3)] * amp11;
1297                state[i01] = matrix[(1, 0)] * amp00
1298                    + matrix[(1, 1)] * amp01
1299                    + matrix[(1, 2)] * amp10
1300                    + matrix[(1, 3)] * amp11;
1301                state[i10] = matrix[(2, 0)] * amp00
1302                    + matrix[(2, 1)] * amp01
1303                    + matrix[(2, 2)] * amp10
1304                    + matrix[(2, 3)] * amp11;
1305                state[i11] = matrix[(3, 0)] * amp00
1306                    + matrix[(3, 1)] * amp01
1307                    + matrix[(3, 2)] * amp10
1308                    + matrix[(3, 3)] * amp11;
1309            }
1310        }
1311
1312        Ok(())
1313    }
1314
1315    /// Execute SIMD operations
1316    fn execute_simd_operations(
1317        &self,
1318        operations: &[VectorizedOperation],
1319        state: &mut Array1<Complex64>,
1320    ) -> Result<()> {
1321        for operation in operations {
1322            match operation.instruction {
1323                SIMDInstruction::ComplexMul => {
1324                    Self::execute_simd_complex_mul(operation, state)?;
1325                }
1326                SIMDInstruction::ComplexAdd => {
1327                    Self::execute_simd_complex_add(operation, state)?;
1328                }
1329                SIMDInstruction::Rotation => {
1330                    Self::execute_simd_rotation(operation, state)?;
1331                }
1332                SIMDInstruction::GateApplication => {
1333                    Self::execute_simd_gate_application(operation, state)?;
1334                }
1335                SIMDInstruction::TensorProduct => {
1336                    return Err(SimulatorError::NotImplemented(
1337                        "SIMD instruction".to_string(),
1338                    ));
1339                }
1340            }
1341        }
1342        Ok(())
1343    }
1344
1345    fn execute_simd_complex_mul(
1346        _operation: &VectorizedOperation,
1347        _state: &mut Array1<Complex64>,
1348    ) -> Result<()> {
1349        Ok(())
1350    }
1351
1352    fn execute_simd_complex_add(
1353        _operation: &VectorizedOperation,
1354        _state: &mut Array1<Complex64>,
1355    ) -> Result<()> {
1356        Ok(())
1357    }
1358
1359    fn execute_simd_rotation(
1360        _operation: &VectorizedOperation,
1361        _state: &mut Array1<Complex64>,
1362    ) -> Result<()> {
1363        Ok(())
1364    }
1365
1366    fn execute_simd_gate_application(
1367        _operation: &VectorizedOperation,
1368        _state: &mut Array1<Complex64>,
1369    ) -> Result<()> {
1370        Ok(())
1371    }
1372
1373    /// Get compilation statistics
1374    #[must_use]
1375    pub fn get_stats(&self) -> JITCompilerStats {
1376        self.stats
1377            .read()
1378            .expect("JIT stats lock should not be poisoned")
1379            .clone()
1380    }
1381
1382    /// Clear compiled cache
1383    pub fn clear_cache(&self) {
1384        let mut cache = self
1385            .compiled_cache
1386            .write()
1387            .expect("JIT cache lock should not be poisoned");
1388        cache.clear();
1389
1390        let mut stats = self
1391            .stats
1392            .write()
1393            .expect("JIT stats lock should not be poisoned");
1394        stats.cache_clears += 1;
1395    }
1396}