quantrs2_anneal/quantum_error_correction/
logical_encoding.rs

1//! Logical Qubit Encoding for Annealing Problems
2//!
3//! This module implements logical qubit encoding systems specifically designed for
4//! quantum annealing applications. It provides functionality for:
5//! - Encoding logical Ising/QUBO problems into error-corrected physical qubits
6//! - Mapping logical annealing Hamiltonians to protected physical implementations
7//! - Constructing stabilizer codes optimized for annealing hardware constraints
8//! - Managing logical operations during annealing evolution
9
10use scirs2_core::ndarray::{Array1, Array2};
11use scirs2_core::random::ChaCha8Rng;
12use scirs2_core::random::{Rng, SeedableRng};
13use std::collections::HashMap;
14use std::time::{Duration, Instant};
15
16use super::codes::{CodeParameters, ErrorCorrectionCode};
17use super::config::{QECResult, QuantumErrorCorrectionError};
18use super::logical_operations::LogicalOperation;
19use super::syndrome_detection::{SyndromeDetector, SyndromeDetectorConfig};
20use crate::ising::IsingModel;
21use crate::qaoa::QuantumState;
22use crate::simulator::AnnealingResult;
23
24/// Logical encoding system
25#[derive(Debug, Clone)]
26pub struct LogicalEncoding {
27    /// Stabilizer generators
28    pub stabilizers: Vec<PauliOperator>,
29    /// Logical operators
30    pub logical_operators: Vec<LogicalOperatorSet>,
31    /// Code space
32    pub code_space: CodeSpace,
33    /// Encoding circuits
34    pub encoding_circuits: Vec<QuantumCircuit>,
35    /// Decoding data
36    pub decoding_data: DecodingData,
37}
38
39/// Pauli operator representation
40#[derive(Debug, Clone)]
41pub struct PauliOperator {
42    /// Pauli string (I, X, Y, Z for each qubit)
43    pub pauli_string: Vec<PauliType>,
44    /// Phase factor
45    pub phase: f64,
46    /// Coefficient
47    pub coefficient: f64,
48    /// Support (qubits on which operator acts non-trivially)
49    pub support: Vec<usize>,
50}
51
52/// Pauli operator types
53#[derive(Debug, Clone, PartialEq, Eq)]
54pub enum PauliType {
55    /// Identity
56    I,
57    /// Pauli X
58    X,
59    /// Pauli Y
60    Y,
61    /// Pauli Z
62    Z,
63}
64
65/// Logical operator set
66#[derive(Debug, Clone)]
67pub struct LogicalOperatorSet {
68    /// Logical qubit index
69    pub logical_qubit: usize,
70    /// Logical X operator
71    pub logical_x: PauliOperator,
72    /// Logical Z operator
73    pub logical_z: PauliOperator,
74    /// Logical Y operator (derived)
75    pub logical_y: PauliOperator,
76}
77
78/// Code space definition
79#[derive(Debug, Clone)]
80pub struct CodeSpace {
81    /// Basis states of the code space
82    pub basis_states: Vec<LogicalBasisState>,
83    /// Projector onto code space
84    pub code_projector: Vec<Vec<f64>>,
85    /// Dimension of code space
86    pub dimension: usize,
87    /// Distance of the code
88    pub distance: usize,
89}
90
91/// Logical basis state
92#[derive(Debug, Clone)]
93pub struct LogicalBasisState {
94    /// Logical state label
95    pub label: String,
96    /// Physical state representation
97    pub physical_state: Vec<f64>,
98    /// Stabilizer eigenvalues
99    pub stabilizer_eigenvalues: Vec<i8>,
100}
101
102/// Quantum circuit representation
103#[derive(Debug, Clone)]
104pub struct QuantumCircuit {
105    /// Circuit gates
106    pub gates: Vec<QuantumGate>,
107    /// Circuit depth
108    pub depth: usize,
109    /// Qubit count
110    pub num_qubits: usize,
111    /// Classical registers for measurements
112    pub classical_registers: Vec<ClassicalRegister>,
113}
114
115/// Quantum gate
116#[derive(Debug, Clone)]
117pub struct QuantumGate {
118    /// Gate type
119    pub gate_type: GateType,
120    /// Target qubits
121    pub target_qubits: Vec<usize>,
122    /// Control qubits
123    pub control_qubits: Vec<usize>,
124    /// Gate parameters
125    pub parameters: Vec<f64>,
126    /// Gate time
127    pub gate_time: f64,
128}
129
130/// Quantum gate types
131#[derive(Debug, Clone, PartialEq)]
132pub enum GateType {
133    /// Pauli X
134    X,
135    /// Pauli Y
136    Y,
137    /// Pauli Z
138    Z,
139    /// Hadamard
140    H,
141    /// Phase gate
142    S,
143    /// T gate
144    T,
145    /// CNOT
146    CNOT,
147    /// Controlled-Z
148    CZ,
149    /// Rotation gates
150    RX(f64),
151    RY(f64),
152    RZ(f64),
153    /// Measurement
154    Measurement,
155}
156
157/// Classical register
158#[derive(Debug, Clone)]
159pub struct ClassicalRegister {
160    /// Register name
161    pub name: String,
162    /// Number of bits
163    pub num_bits: usize,
164}
165
166/// Decoding data
167#[derive(Debug, Clone)]
168pub struct DecodingData {
169    /// Syndrome lookup table
170    pub syndrome_table: HashMap<Vec<i8>, ErrorPattern>,
171    /// Decoding algorithm
172    pub decoding_algorithm: DecodingAlgorithm,
173    /// Decoding performance
174    pub decoding_performance: DecodingPerformance,
175}
176
177/// Error pattern
178#[derive(Debug, Clone)]
179pub struct ErrorPattern {
180    /// Error locations
181    pub error_locations: Vec<usize>,
182    /// Error types
183    pub error_types: Vec<PauliType>,
184    /// Correction operations
185    pub correction_operations: Vec<QuantumGate>,
186}
187
188/// Decoding algorithms
189#[derive(Debug, Clone, PartialEq, Eq)]
190pub enum DecodingAlgorithm {
191    LookupTable,
192    MinimumWeight,
193    BeliefPropagation,
194    NeuralNetwork,
195    MaximumLikelihood,
196}
197
198/// Decoding performance metrics
199#[derive(Debug, Clone)]
200pub struct DecodingPerformance {
201    /// Logical error rate
202    pub logical_error_rate: f64,
203    /// Decoding time
204    pub decoding_time: std::time::Duration,
205    /// Success probability
206    pub success_probability: f64,
207    /// Threshold estimate
208    pub threshold_estimate: f64,
209}
210
211/// Logical qubit encoder for annealing problems
212#[derive(Debug, Clone)]
213pub struct LogicalAnnealingEncoder {
214    /// Error correction code being used
215    pub code: ErrorCorrectionCode,
216    /// Code parameters
217    pub parameters: CodeParameters,
218    /// Logical encoding configuration
219    pub encoding: LogicalEncoding,
220    /// Syndrome detector for monitoring
221    pub syndrome_detector: Option<SyndromeDetector>,
222    /// Hardware topology information
223    pub hardware_topology: AnnealingTopology,
224    /// Encoding performance metrics
225    pub performance_metrics: EncodingPerformanceMetrics,
226    /// Configuration
227    pub config: LogicalEncoderConfig,
228}
229
230/// Configuration for logical encoder
231#[derive(Debug, Clone)]
232pub struct LogicalEncoderConfig {
233    /// Enable real-time error monitoring
234    pub enable_monitoring: bool,
235    /// Logical operation fidelity target
236    pub target_fidelity: f64,
237    /// Maximum encoding overhead allowed
238    pub max_encoding_overhead: f64,
239    /// Optimization strategy for encoding
240    pub optimization_strategy: EncodingOptimizationStrategy,
241    /// Hardware integration mode
242    pub hardware_integration: HardwareIntegrationMode,
243}
244
245/// Encoding optimization strategies
246#[derive(Debug, Clone, PartialEq, Eq)]
247pub enum EncodingOptimizationStrategy {
248    /// Minimize number of physical qubits
249    MinimizeQubits,
250    /// Minimize encoding depth
251    MinimizeDepth,
252    /// Maximize error threshold
253    MaximizeThreshold,
254    /// Optimize for annealing time
255    OptimizeAnnealingTime,
256    /// Balance all factors
257    Balanced,
258}
259
260/// Hardware integration modes
261#[derive(Debug, Clone, PartialEq, Eq)]
262pub enum HardwareIntegrationMode {
263    /// Software simulation only
264    Simulation,
265    /// Hardware-aware simulation
266    HardwareAware,
267    /// Full hardware integration
268    FullIntegration,
269    /// Hybrid mode
270    Hybrid,
271}
272
273/// Annealing hardware topology
274#[derive(Debug, Clone)]
275pub struct AnnealingTopology {
276    /// Connectivity graph
277    pub connectivity: Array2<bool>,
278    /// Qubit coupling strengths
279    pub coupling_strengths: Array2<f64>,
280    /// Qubit coherence times
281    pub coherence_times: Array1<f64>,
282    /// Control precision
283    pub control_precision: f64,
284    /// Topology type
285    pub topology_type: TopologyType,
286}
287
288/// Hardware topology types
289#[derive(Debug, Clone, PartialEq, Eq)]
290pub enum TopologyType {
291    /// D-Wave Chimera graph
292    Chimera { m: usize, n: usize, l: usize },
293    /// D-Wave Pegasus graph
294    Pegasus { m: usize },
295    /// Grid topology
296    Grid { rows: usize, cols: usize },
297    /// Fully connected
298    FullyConnected { n: usize },
299    /// Custom topology
300    Custom,
301}
302
303/// Encoding performance metrics
304#[derive(Debug, Clone)]
305pub struct EncodingPerformanceMetrics {
306    /// Physical to logical qubit ratio
307    pub qubit_overhead: f64,
308    /// Encoding fidelity
309    pub encoding_fidelity: f64,
310    /// Logical operation time overhead
311    pub time_overhead: f64,
312    /// Error suppression factor
313    pub error_suppression_factor: f64,
314    /// Threshold estimate
315    pub threshold_estimate: f64,
316    /// Encoding depth
317    pub encoding_depth: usize,
318    /// Success rate
319    pub success_rate: f64,
320}
321
322/// Result of logical encoding operation
323#[derive(Debug, Clone)]
324pub struct LogicalEncodingResult {
325    /// Encoded logical Hamiltonian
326    pub logical_hamiltonian: LogicalHamiltonian,
327    /// Physical implementation
328    pub physical_implementation: PhysicalImplementation,
329    /// Encoding mapping
330    pub encoding_map: EncodingMap,
331    /// Performance metrics
332    pub performance: EncodingPerformanceMetrics,
333    /// Monitoring data
334    pub monitoring_data: Option<MonitoringData>,
335}
336
337/// Logical Hamiltonian representation
338#[derive(Debug, Clone)]
339pub struct LogicalHamiltonian {
340    /// Logical coupling matrix
341    pub logical_couplings: Array2<f64>,
342    /// Logical bias vector
343    pub logical_biases: Array1<f64>,
344    /// Number of logical qubits
345    pub num_logical_qubits: usize,
346    /// Logical operators involved
347    pub logical_operators: Vec<LogicalOperatorSet>,
348}
349
350/// Physical implementation of logical problem
351#[derive(Debug, Clone)]
352pub struct PhysicalImplementation {
353    /// Physical coupling matrix
354    pub physical_couplings: Array2<f64>,
355    /// Physical bias vector
356    pub physical_biases: Array1<f64>,
357    /// Number of physical qubits
358    pub num_physical_qubits: usize,
359    /// Ancilla qubit assignments
360    pub ancilla_assignments: Vec<usize>,
361    /// Stabilizer measurement schedule
362    pub measurement_schedule: MeasurementSchedule,
363}
364
365/// Encoding map between logical and physical qubits
366#[derive(Debug, Clone)]
367pub struct EncodingMap {
368    /// Logical to physical qubit mapping
369    pub logical_to_physical: HashMap<usize, Vec<usize>>,
370    /// Physical to logical qubit mapping
371    pub physical_to_logical: HashMap<usize, Option<usize>>,
372    /// Code block assignments
373    pub code_blocks: Vec<CodeBlock>,
374    /// Auxiliary mappings
375    pub auxiliary_mappings: HashMap<String, Vec<usize>>,
376}
377
378/// Individual code block
379#[derive(Debug, Clone)]
380pub struct CodeBlock {
381    /// Logical qubit index
382    pub logical_qubit: usize,
383    /// Physical qubits in this block
384    pub physical_qubits: Vec<usize>,
385    /// Stabilizer generators for this block
386    pub stabilizers: Vec<PauliOperator>,
387    /// Block type
388    pub block_type: CodeBlockType,
389}
390
391/// Code block types
392#[derive(Debug, Clone, PartialEq, Eq)]
393pub enum CodeBlockType {
394    /// Data block (stores logical information)
395    Data,
396    /// Ancilla block (for syndrome measurement)
397    Ancilla,
398    /// Mixed block (both data and ancilla)
399    Mixed,
400}
401
402/// Measurement schedule for syndrome detection
403#[derive(Debug, Clone)]
404pub struct MeasurementSchedule {
405    /// Measurement rounds
406    pub rounds: Vec<MeasurementRound>,
407    /// Schedule timing
408    pub timing: ScheduleTiming,
409    /// Adaptive parameters
410    pub adaptive_params: AdaptiveScheduleParams,
411}
412
413/// Individual measurement round
414#[derive(Debug, Clone)]
415pub struct MeasurementRound {
416    /// Stabilizers to measure
417    pub stabilizers_to_measure: Vec<usize>,
418    /// Measurement time
419    pub measurement_time: f64,
420    /// Expected measurement outcomes
421    pub expected_outcomes: Vec<i8>,
422}
423
424/// Schedule timing parameters
425#[derive(Debug, Clone)]
426pub struct ScheduleTiming {
427    /// Base measurement period
428    pub base_period: f64,
429    /// Adaptive timing enabled
430    pub adaptive_timing: bool,
431    /// Minimum period
432    pub min_period: f64,
433    /// Maximum period
434    pub max_period: f64,
435}
436
437/// Adaptive schedule parameters
438#[derive(Debug, Clone)]
439pub struct AdaptiveScheduleParams {
440    /// Error rate threshold for adaptation
441    pub error_threshold: f64,
442    /// Adaptation rate
443    pub adaptation_rate: f64,
444    /// History window for adaptation
445    pub history_window: usize,
446}
447
448/// Monitoring data during encoding
449#[derive(Debug, Clone)]
450pub struct MonitoringData {
451    /// Syndrome measurements
452    pub syndrome_measurements: Vec<SyndromeRecord>,
453    /// Error rates over time
454    pub error_rates: Vec<(f64, f64)>, // (time, error_rate)
455    /// Logical fidelity over time
456    pub fidelity_history: Vec<(f64, f64)>, // (time, fidelity)
457    /// Correction events
458    pub correction_events: Vec<CorrectionEvent>,
459}
460
461/// Syndrome measurement record
462#[derive(Debug, Clone)]
463pub struct SyndromeRecord {
464    /// Measurement timestamp
465    pub timestamp: f64,
466    /// Measured syndrome
467    pub syndrome: Vec<i8>,
468    /// Measurement round
469    pub round: usize,
470    /// Confidence level
471    pub confidence: f64,
472}
473
474/// Correction event record
475#[derive(Debug, Clone)]
476pub struct CorrectionEvent {
477    /// Event timestamp
478    pub timestamp: f64,
479    /// Detected errors
480    pub detected_errors: Vec<ErrorLocation>,
481    /// Applied corrections
482    pub applied_corrections: Vec<CorrectionOperation>,
483    /// Success status
484    pub success: bool,
485}
486
487/// Error location information
488#[derive(Debug, Clone)]
489pub struct ErrorLocation {
490    /// Physical qubit
491    pub physical_qubit: usize,
492    /// Error type
493    pub error_type: PauliType,
494    /// Error probability
495    pub probability: f64,
496    /// Logical qubit affected
497    pub logical_qubit_affected: Option<usize>,
498}
499
500/// Correction operation details
501#[derive(Debug, Clone)]
502pub struct CorrectionOperation {
503    /// Target qubit
504    pub target_qubit: usize,
505    /// Correction type
506    pub correction_type: PauliType,
507    /// Application time
508    pub application_time: f64,
509    /// Success probability
510    pub success_probability: f64,
511}
512
513impl LogicalAnnealingEncoder {
514    /// Create new logical annealing encoder
515    pub fn new(
516        code: ErrorCorrectionCode,
517        parameters: CodeParameters,
518        config: LogicalEncoderConfig,
519    ) -> QECResult<Self> {
520        let encoding = Self::create_logical_encoding(&code, &parameters)?;
521        let hardware_topology = Self::create_default_topology(&parameters);
522        let performance_metrics = EncodingPerformanceMetrics::new();
523
524        let syndrome_detector = if config.enable_monitoring {
525            let detector_config = SyndromeDetectorConfig::default();
526            Some(SyndromeDetector::new(
527                code.clone(),
528                parameters.clone(),
529                detector_config,
530            )?)
531        } else {
532            None
533        };
534
535        Ok(Self {
536            code,
537            parameters,
538            encoding,
539            syndrome_detector,
540            hardware_topology,
541            performance_metrics,
542            config,
543        })
544    }
545
546    /// Encode logical Ising problem into physical implementation
547    pub fn encode_ising_problem(
548        &mut self,
549        logical_problem: &IsingModel,
550    ) -> QECResult<LogicalEncodingResult> {
551        let start_time = Instant::now();
552
553        // Create logical Hamiltonian representation
554        let logical_hamiltonian = self.create_logical_hamiltonian(logical_problem)?;
555
556        // Map to physical implementation
557        let physical_implementation = self.map_to_physical_implementation(&logical_hamiltonian)?;
558
559        // Create encoding map
560        let encoding_map =
561            self.create_encoding_map(&logical_hamiltonian, &physical_implementation)?;
562
563        // Calculate performance metrics
564        let performance = self.calculate_encoding_performance(
565            &logical_hamiltonian,
566            &physical_implementation,
567            start_time.elapsed(),
568        )?;
569
570        // Initialize monitoring if enabled
571        let monitoring_data = self.config.enable_monitoring.then(|| MonitoringData::new());
572
573        // Update internal metrics
574        self.performance_metrics = performance.clone();
575
576        Ok(LogicalEncodingResult {
577            logical_hamiltonian,
578            physical_implementation,
579            encoding_map,
580            performance,
581            monitoring_data,
582        })
583    }
584
585    /// Monitor logical qubits during annealing
586    pub fn monitor_logical_qubits(
587        &mut self,
588        physical_state: &QuantumState,
589        encoding_result: &mut LogicalEncodingResult,
590    ) -> QECResult<Vec<SyndromeRecord>> {
591        if let Some(ref mut detector) = self.syndrome_detector {
592            let syndrome_result = detector.detect_syndrome(physical_state)?;
593
594            let record = SyndromeRecord {
595                timestamp: std::time::SystemTime::now()
596                    .duration_since(std::time::UNIX_EPOCH)
597                    .expect("system time before UNIX_EPOCH")
598                    .as_secs_f64(),
599                syndrome: syndrome_result.syndrome.iter().map(|&x| x as i8).collect(),
600                round: 0, // Would be properly tracked
601                confidence: syndrome_result.confidence,
602            };
603
604            if let Some(ref mut monitoring) = encoding_result.monitoring_data {
605                monitoring.syndrome_measurements.push(record.clone());
606            }
607
608            Ok(vec![record])
609        } else {
610            Ok(Vec::new())
611        }
612    }
613
614    /// Apply logical operation during annealing
615    pub fn apply_logical_operation(
616        &self,
617        operation: &LogicalOperation,
618        logical_qubit: usize,
619        encoding_map: &EncodingMap,
620    ) -> QECResult<Vec<QuantumGate>> {
621        // Map logical operation to physical gates
622        let physical_qubits = encoding_map
623            .logical_to_physical
624            .get(&logical_qubit)
625            .ok_or_else(|| {
626                QuantumErrorCorrectionError::LogicalOperationError(format!(
627                    "Logical qubit {logical_qubit} not found in encoding map"
628                ))
629            })?;
630
631        let mut gates = Vec::new();
632
633        match operation {
634            LogicalOperation::LogicalX => {
635                gates.extend(self.implement_logical_x(physical_qubits)?);
636            }
637            LogicalOperation::LogicalZ => {
638                gates.extend(self.implement_logical_z(physical_qubits)?);
639            }
640            LogicalOperation::LogicalMeasurement => {
641                gates.extend(self.implement_logical_measurement(physical_qubits)?);
642            }
643            _ => {
644                return Err(QuantumErrorCorrectionError::LogicalOperationError(format!(
645                    "Logical operation {operation:?} not implemented"
646                )));
647            }
648        }
649
650        Ok(gates)
651    }
652
653    /// Create logical encoding from error correction code
654    fn create_logical_encoding(
655        code: &ErrorCorrectionCode,
656        parameters: &CodeParameters,
657    ) -> QECResult<LogicalEncoding> {
658        let stabilizers = Self::generate_stabilizer_operators(code, parameters)?;
659        let logical_operators = Self::generate_logical_operators(code, parameters)?;
660        let code_space = Self::construct_code_space(code, parameters)?;
661        let encoding_circuits = Self::generate_encoding_circuits(code, parameters)?;
662        let decoding_data = Self::create_decoding_data(code, parameters)?;
663
664        Ok(LogicalEncoding {
665            stabilizers,
666            logical_operators,
667            code_space,
668            encoding_circuits,
669            decoding_data,
670        })
671    }
672
673    /// Generate stabilizer operators for the code
674    fn generate_stabilizer_operators(
675        code: &ErrorCorrectionCode,
676        parameters: &CodeParameters,
677    ) -> QECResult<Vec<PauliOperator>> {
678        let mut stabilizers = Vec::new();
679
680        match code {
681            ErrorCorrectionCode::SurfaceCode => {
682                stabilizers.extend(Self::surface_code_stabilizers(parameters)?);
683            }
684            ErrorCorrectionCode::RepetitionCode => {
685                stabilizers.extend(Self::repetition_code_stabilizers(parameters)?);
686            }
687            ErrorCorrectionCode::SteaneCode => {
688                stabilizers.extend(Self::steane_code_stabilizers(parameters)?);
689            }
690            _ => {
691                return Err(QuantumErrorCorrectionError::CodeError(format!(
692                    "Stabilizer generation not implemented for {code:?}"
693                )));
694            }
695        }
696
697        Ok(stabilizers)
698    }
699
700    /// Generate surface code stabilizers
701    fn surface_code_stabilizers(parameters: &CodeParameters) -> QECResult<Vec<PauliOperator>> {
702        let d = parameters.distance;
703        let mut stabilizers = Vec::new();
704
705        // X-type stabilizers (plaquettes)
706        for row in 0..(d - 1) {
707            for col in 0..(d - 1) {
708                if (row + col) % 2 == 0 {
709                    let mut pauli_string = vec![PauliType::I; parameters.num_physical_qubits];
710                    let qubits = Self::get_plaquette_qubits(row, col, d);
711
712                    for &qubit in &qubits {
713                        if qubit < parameters.num_physical_qubits {
714                            pauli_string[qubit] = PauliType::X;
715                        }
716                    }
717
718                    stabilizers.push(PauliOperator {
719                        pauli_string,
720                        phase: 0.0,
721                        coefficient: 1.0,
722                        support: qubits,
723                    });
724                }
725            }
726        }
727
728        // Z-type stabilizers (vertices)
729        for row in 0..d {
730            for col in 0..d {
731                if (row + col) % 2 == 1 {
732                    let mut pauli_string = vec![PauliType::I; parameters.num_physical_qubits];
733                    let qubits = Self::get_vertex_qubits(row, col, d);
734
735                    for &qubit in &qubits {
736                        if qubit < parameters.num_physical_qubits {
737                            pauli_string[qubit] = PauliType::Z;
738                        }
739                    }
740
741                    stabilizers.push(PauliOperator {
742                        pauli_string,
743                        phase: 0.0,
744                        coefficient: 1.0,
745                        support: qubits,
746                    });
747                }
748            }
749        }
750
751        Ok(stabilizers)
752    }
753
754    /// Generate repetition code stabilizers
755    fn repetition_code_stabilizers(parameters: &CodeParameters) -> QECResult<Vec<PauliOperator>> {
756        let n = parameters.num_physical_qubits;
757        let mut stabilizers = Vec::new();
758
759        for i in 0..(n - 1) {
760            let mut pauli_string = vec![PauliType::I; n];
761            pauli_string[i] = PauliType::Z;
762            pauli_string[i + 1] = PauliType::Z;
763
764            stabilizers.push(PauliOperator {
765                pauli_string,
766                phase: 0.0,
767                coefficient: 1.0,
768                support: vec![i, i + 1],
769            });
770        }
771
772        Ok(stabilizers)
773    }
774
775    /// Generate Steane code stabilizers
776    fn steane_code_stabilizers(parameters: &CodeParameters) -> QECResult<Vec<PauliOperator>> {
777        let mut stabilizers = Vec::new();
778
779        // Steane code [[7,1,3]] stabilizers
780        let x_stabilizers = [vec![0, 2, 4, 6], vec![1, 2, 5, 6], vec![3, 4, 5, 6]];
781
782        let z_stabilizers = [vec![0, 1, 2, 3], vec![0, 1, 4, 5], vec![0, 2, 4, 6]];
783
784        // Add X-type stabilizers
785        for pattern in &x_stabilizers {
786            let mut pauli_string = vec![PauliType::I; 7];
787            for &qubit in pattern {
788                pauli_string[qubit] = PauliType::X;
789            }
790
791            stabilizers.push(PauliOperator {
792                pauli_string,
793                phase: 0.0,
794                coefficient: 1.0,
795                support: pattern.clone(),
796            });
797        }
798
799        // Add Z-type stabilizers
800        for pattern in &z_stabilizers {
801            let mut pauli_string = vec![PauliType::I; 7];
802            for &qubit in pattern {
803                pauli_string[qubit] = PauliType::Z;
804            }
805
806            stabilizers.push(PauliOperator {
807                pauli_string,
808                phase: 0.0,
809                coefficient: 1.0,
810                support: pattern.clone(),
811            });
812        }
813
814        Ok(stabilizers)
815    }
816
817    /// Generate logical operators
818    fn generate_logical_operators(
819        code: &ErrorCorrectionCode,
820        parameters: &CodeParameters,
821    ) -> QECResult<Vec<LogicalOperatorSet>> {
822        let mut logical_operators = Vec::new();
823
824        for logical_qubit in 0..parameters.num_logical_qubits {
825            let logical_x = Self::create_logical_x_operator(code, parameters, logical_qubit)?;
826            let logical_z = Self::create_logical_z_operator(code, parameters, logical_qubit)?;
827            let logical_y = Self::create_logical_y_operator(&logical_x, &logical_z)?;
828
829            logical_operators.push(LogicalOperatorSet {
830                logical_qubit,
831                logical_x,
832                logical_z,
833                logical_y,
834            });
835        }
836
837        Ok(logical_operators)
838    }
839
840    /// Create logical X operator
841    fn create_logical_x_operator(
842        code: &ErrorCorrectionCode,
843        parameters: &CodeParameters,
844        logical_qubit: usize,
845    ) -> QECResult<PauliOperator> {
846        if code == &ErrorCorrectionCode::RepetitionCode {
847            // For repetition code, logical X acts on all qubits
848            let pauli_string = vec![PauliType::X; parameters.num_physical_qubits];
849            let support = (0..parameters.num_physical_qubits).collect();
850
851            Ok(PauliOperator {
852                pauli_string,
853                phase: 0.0,
854                coefficient: 1.0,
855                support,
856            })
857        } else {
858            // Default implementation - would need specific implementation per code
859            let mut pauli_string = vec![PauliType::I; parameters.num_physical_qubits];
860            pauli_string[0] = PauliType::X; // Simplified
861
862            Ok(PauliOperator {
863                pauli_string,
864                phase: 0.0,
865                coefficient: 1.0,
866                support: vec![0],
867            })
868        }
869    }
870
871    /// Create logical Z operator
872    fn create_logical_z_operator(
873        code: &ErrorCorrectionCode,
874        parameters: &CodeParameters,
875        logical_qubit: usize,
876    ) -> QECResult<PauliOperator> {
877        if code == &ErrorCorrectionCode::RepetitionCode {
878            // For repetition code, logical Z acts on first qubit
879            let mut pauli_string = vec![PauliType::I; parameters.num_physical_qubits];
880            pauli_string[0] = PauliType::Z;
881
882            Ok(PauliOperator {
883                pauli_string,
884                phase: 0.0,
885                coefficient: 1.0,
886                support: vec![0],
887            })
888        } else {
889            // Default implementation
890            let mut pauli_string = vec![PauliType::I; parameters.num_physical_qubits];
891            pauli_string[0] = PauliType::Z;
892
893            Ok(PauliOperator {
894                pauli_string,
895                phase: 0.0,
896                coefficient: 1.0,
897                support: vec![0],
898            })
899        }
900    }
901
902    /// Create logical Y operator from X and Z
903    fn create_logical_y_operator(
904        logical_x: &PauliOperator,
905        logical_z: &PauliOperator,
906    ) -> QECResult<PauliOperator> {
907        // Y = iXZ (simplified implementation)
908        let mut pauli_string = vec![PauliType::I; logical_x.pauli_string.len()];
909
910        for i in 0..pauli_string.len() {
911            pauli_string[i] = match (&logical_x.pauli_string[i], &logical_z.pauli_string[i]) {
912                (PauliType::X, PauliType::I) => PauliType::X,
913                (PauliType::I, PauliType::Z) => PauliType::Z,
914                (PauliType::X, PauliType::Z) => PauliType::Y,
915                _ => PauliType::I,
916            };
917        }
918
919        let mut support = logical_x.support.clone();
920        support.extend(logical_z.support.iter());
921        support.sort_unstable();
922        support.dedup();
923
924        Ok(PauliOperator {
925            pauli_string,
926            phase: std::f64::consts::PI / 2.0, // i factor
927            coefficient: 1.0,
928            support,
929        })
930    }
931
932    /// Construct code space
933    fn construct_code_space(
934        code: &ErrorCorrectionCode,
935        parameters: &CodeParameters,
936    ) -> QECResult<CodeSpace> {
937        let dimension = 1 << parameters.num_logical_qubits; // 2^k for k logical qubits
938        let basis_states = Self::generate_logical_basis_states(parameters)?;
939        let code_projector = Self::compute_code_projector(parameters)?;
940
941        Ok(CodeSpace {
942            basis_states,
943            code_projector,
944            dimension,
945            distance: parameters.distance,
946        })
947    }
948
949    /// Generate logical basis states
950    fn generate_logical_basis_states(
951        parameters: &CodeParameters,
952    ) -> QECResult<Vec<LogicalBasisState>> {
953        let mut basis_states = Vec::new();
954
955        // For k logical qubits, generate 2^k basis states
956        let num_basis_states = 1 << parameters.num_logical_qubits;
957
958        for state_index in 0..num_basis_states {
959            let label = format!(
960                "L{:0width$b}",
961                state_index,
962                width = parameters.num_logical_qubits
963            );
964
965            // Generate physical state representation (simplified)
966            let physical_state = vec![0.0; 1 << parameters.num_physical_qubits];
967
968            // Generate stabilizer eigenvalues (all +1 for code states)
969            let stabilizer_eigenvalues =
970                vec![1i8; parameters.num_physical_qubits - parameters.num_logical_qubits];
971
972            basis_states.push(LogicalBasisState {
973                label,
974                physical_state,
975                stabilizer_eigenvalues,
976            });
977        }
978
979        Ok(basis_states)
980    }
981
982    /// Compute code projector
983    fn compute_code_projector(parameters: &CodeParameters) -> QECResult<Vec<Vec<f64>>> {
984        let dim = 1 << parameters.num_physical_qubits;
985        let mut projector = vec![vec![0.0; dim]; dim];
986
987        // Simplified identity projector
988        for i in 0..dim {
989            projector[i][i] = 1.0;
990        }
991
992        Ok(projector)
993    }
994
995    /// Generate encoding circuits
996    fn generate_encoding_circuits(
997        code: &ErrorCorrectionCode,
998        parameters: &CodeParameters,
999    ) -> QECResult<Vec<QuantumCircuit>> {
1000        match code {
1001            ErrorCorrectionCode::RepetitionCode => {
1002                Ok(vec![Self::create_repetition_encoding_circuit(parameters)?])
1003            }
1004            ErrorCorrectionCode::SteaneCode => {
1005                Ok(vec![Self::create_steane_encoding_circuit(parameters)?])
1006            }
1007            _ => {
1008                // Default empty circuit
1009                Ok(vec![QuantumCircuit {
1010                    gates: Vec::new(),
1011                    depth: 0,
1012                    num_qubits: parameters.num_physical_qubits,
1013                    classical_registers: Vec::new(),
1014                }])
1015            }
1016        }
1017    }
1018
1019    /// Create repetition code encoding circuit
1020    fn create_repetition_encoding_circuit(
1021        parameters: &CodeParameters,
1022    ) -> QECResult<QuantumCircuit> {
1023        let mut gates = Vec::new();
1024
1025        // CNOT gates to copy logical qubit to all physical qubits
1026        for i in 1..parameters.num_physical_qubits {
1027            gates.push(QuantumGate {
1028                gate_type: GateType::CNOT,
1029                target_qubits: vec![i],
1030                control_qubits: vec![0],
1031                parameters: Vec::new(),
1032                gate_time: 0.1, // microseconds
1033            });
1034        }
1035
1036        Ok(QuantumCircuit {
1037            gates,
1038            depth: parameters.num_physical_qubits - 1,
1039            num_qubits: parameters.num_physical_qubits,
1040            classical_registers: Vec::new(),
1041        })
1042    }
1043
1044    /// Create Steane code encoding circuit
1045    fn create_steane_encoding_circuit(parameters: &CodeParameters) -> QECResult<QuantumCircuit> {
1046        let mut gates = Vec::new();
1047
1048        // Simplified Steane encoding (would need full implementation)
1049        // H gates on ancilla qubits
1050        for i in 1..7 {
1051            gates.push(QuantumGate {
1052                gate_type: GateType::H,
1053                target_qubits: vec![i],
1054                control_qubits: Vec::new(),
1055                parameters: Vec::new(),
1056                gate_time: 0.05,
1057            });
1058        }
1059
1060        // CNOT pattern for Steane code
1061        let cnot_pattern = [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6)];
1062        for (control, target) in cnot_pattern {
1063            gates.push(QuantumGate {
1064                gate_type: GateType::CNOT,
1065                target_qubits: vec![target],
1066                control_qubits: vec![control],
1067                parameters: Vec::new(),
1068                gate_time: 0.1,
1069            });
1070        }
1071
1072        Ok(QuantumCircuit {
1073            gates,
1074            depth: 7,
1075            num_qubits: 7,
1076            classical_registers: Vec::new(),
1077        })
1078    }
1079
1080    /// Create decoding data
1081    fn create_decoding_data(
1082        code: &ErrorCorrectionCode,
1083        parameters: &CodeParameters,
1084    ) -> QECResult<DecodingData> {
1085        let syndrome_table = HashMap::new(); // Would be populated based on code
1086        let decoding_algorithm = DecodingAlgorithm::MinimumWeight;
1087        let decoding_performance = DecodingPerformance {
1088            logical_error_rate: 0.01,
1089            decoding_time: Duration::from_micros(100),
1090            success_probability: 0.95,
1091            threshold_estimate: 0.1,
1092        };
1093
1094        Ok(DecodingData {
1095            syndrome_table,
1096            decoding_algorithm,
1097            decoding_performance,
1098        })
1099    }
1100
1101    /// Create logical Hamiltonian from Ising problem
1102    fn create_logical_hamiltonian(&self, problem: &IsingModel) -> QECResult<LogicalHamiltonian> {
1103        let num_logical_qubits = problem.num_qubits;
1104        let mut logical_couplings = Array2::zeros((num_logical_qubits, num_logical_qubits));
1105        let mut logical_biases = Array1::zeros(num_logical_qubits);
1106
1107        // Copy coupling matrix and bias vector
1108        for i in 0..num_logical_qubits {
1109            logical_biases[i] = problem.get_bias(i).unwrap_or(0.0);
1110
1111            for j in 0..num_logical_qubits {
1112                logical_couplings[[i, j]] = problem.get_coupling(i, j).unwrap_or(0.0);
1113            }
1114        }
1115
1116        let logical_operators = self.encoding.logical_operators.clone();
1117
1118        Ok(LogicalHamiltonian {
1119            logical_couplings,
1120            logical_biases,
1121            num_logical_qubits,
1122            logical_operators,
1123        })
1124    }
1125
1126    /// Map logical Hamiltonian to physical implementation
1127    fn map_to_physical_implementation(
1128        &self,
1129        logical_hamiltonian: &LogicalHamiltonian,
1130    ) -> QECResult<PhysicalImplementation> {
1131        let num_physical_qubits = self.parameters.num_physical_qubits;
1132        let mut physical_couplings = Array2::zeros((num_physical_qubits, num_physical_qubits));
1133        let mut physical_biases = Array1::zeros(num_physical_qubits);
1134
1135        // Map logical interactions to physical qubits based on logical operators
1136        for i in 0..logical_hamiltonian.num_logical_qubits {
1137            // Map logical bias
1138            if let Some(logical_op) = logical_hamiltonian.logical_operators.get(i) {
1139                let bias_value = logical_hamiltonian.logical_biases[i];
1140
1141                // Apply bias to physical qubits according to logical Z operator
1142                for &qubit in &logical_op.logical_z.support {
1143                    if qubit < num_physical_qubits {
1144                        physical_biases[qubit] += bias_value;
1145                    }
1146                }
1147            }
1148
1149            // Map logical couplings
1150            for j in (i + 1)..logical_hamiltonian.num_logical_qubits {
1151                let coupling_value = logical_hamiltonian.logical_couplings[[i, j]];
1152
1153                if coupling_value != 0.0 {
1154                    if let (Some(logical_op_i), Some(logical_op_j)) = (
1155                        logical_hamiltonian.logical_operators.get(i),
1156                        logical_hamiltonian.logical_operators.get(j),
1157                    ) {
1158                        // Map coupling between logical qubits to physical interactions
1159                        for &qubit_i in &logical_op_i.logical_z.support {
1160                            for &qubit_j in &logical_op_j.logical_z.support {
1161                                if qubit_i < num_physical_qubits && qubit_j < num_physical_qubits {
1162                                    physical_couplings[[qubit_i, qubit_j]] += coupling_value;
1163                                    physical_couplings[[qubit_j, qubit_i]] += coupling_value;
1164                                }
1165                            }
1166                        }
1167                    }
1168                }
1169            }
1170        }
1171
1172        let ancilla_assignments = self.identify_ancilla_qubits();
1173        let measurement_schedule = self.create_measurement_schedule()?;
1174
1175        Ok(PhysicalImplementation {
1176            physical_couplings,
1177            physical_biases,
1178            num_physical_qubits,
1179            ancilla_assignments,
1180            measurement_schedule,
1181        })
1182    }
1183
1184    /// Create encoding map
1185    fn create_encoding_map(
1186        &self,
1187        logical_hamiltonian: &LogicalHamiltonian,
1188        physical_implementation: &PhysicalImplementation,
1189    ) -> QECResult<EncodingMap> {
1190        let mut logical_to_physical = HashMap::new();
1191        let mut physical_to_logical = HashMap::new();
1192        let mut code_blocks = Vec::new();
1193
1194        // Create mapping based on logical operators
1195        for (logical_qubit, logical_op_set) in
1196            logical_hamiltonian.logical_operators.iter().enumerate()
1197        {
1198            let physical_qubits = logical_op_set.logical_z.support.clone();
1199            logical_to_physical.insert(logical_qubit, physical_qubits.clone());
1200
1201            // Create code block
1202            let block = CodeBlock {
1203                logical_qubit,
1204                physical_qubits: physical_qubits.clone(),
1205                stabilizers: self.get_stabilizers_for_block(logical_qubit)?,
1206                block_type: CodeBlockType::Data,
1207            };
1208            code_blocks.push(block);
1209
1210            // Update physical to logical mapping
1211            for &physical_qubit in &physical_qubits {
1212                physical_to_logical.insert(physical_qubit, Some(logical_qubit));
1213            }
1214        }
1215
1216        // Mark ancilla qubits
1217        for &ancilla_qubit in &physical_implementation.ancilla_assignments {
1218            physical_to_logical.insert(ancilla_qubit, None);
1219        }
1220
1221        let auxiliary_mappings = HashMap::new(); // Could store additional mappings
1222
1223        Ok(EncodingMap {
1224            logical_to_physical,
1225            physical_to_logical,
1226            code_blocks,
1227            auxiliary_mappings,
1228        })
1229    }
1230
1231    /// Get stabilizers for a specific code block
1232    fn get_stabilizers_for_block(&self, logical_qubit: usize) -> QECResult<Vec<PauliOperator>> {
1233        // Return stabilizers that act on qubits in this block
1234        let stabilizers: Vec<PauliOperator> = self
1235            .encoding
1236            .stabilizers
1237            .iter()
1238            .filter(|stabilizer| {
1239                // Check if stabilizer acts on qubits in this block
1240                stabilizer.support.iter().any(|&qubit| {
1241                    // Check if this qubit belongs to the logical qubit's block
1242                    true // Simplified logic
1243                })
1244            })
1245            .cloned()
1246            .collect();
1247
1248        Ok(stabilizers)
1249    }
1250
1251    /// Calculate encoding performance metrics
1252    fn calculate_encoding_performance(
1253        &self,
1254        logical_hamiltonian: &LogicalHamiltonian,
1255        physical_implementation: &PhysicalImplementation,
1256        encoding_time: Duration,
1257    ) -> QECResult<EncodingPerformanceMetrics> {
1258        let qubit_overhead = physical_implementation.num_physical_qubits as f64
1259            / logical_hamiltonian.num_logical_qubits as f64;
1260
1261        let encoding_fidelity = 0.95; // Would be calculated based on noise model
1262        let time_overhead = encoding_time.as_secs_f64() * 1000.0; // Convert to ms
1263        let error_suppression_factor = self.parameters.distance as f64;
1264        let threshold_estimate = 0.1; // Would be calculated
1265        let encoding_depth = self.calculate_encoding_depth()?;
1266        let success_rate = 0.98; // Would be measured
1267
1268        Ok(EncodingPerformanceMetrics {
1269            qubit_overhead,
1270            encoding_fidelity,
1271            time_overhead,
1272            error_suppression_factor,
1273            threshold_estimate,
1274            encoding_depth,
1275            success_rate,
1276        })
1277    }
1278
1279    /// Calculate encoding circuit depth
1280    fn calculate_encoding_depth(&self) -> QECResult<usize> {
1281        let max_depth = self
1282            .encoding
1283            .encoding_circuits
1284            .iter()
1285            .map(|circuit| circuit.depth)
1286            .max()
1287            .unwrap_or(0);
1288
1289        Ok(max_depth)
1290    }
1291
1292    /// Identify ancilla qubits
1293    fn identify_ancilla_qubits(&self) -> Vec<usize> {
1294        let num_data_qubits = self.parameters.num_logical_qubits;
1295        let total_qubits = self.parameters.num_physical_qubits;
1296
1297        // Simple identification: last qubits are ancillas
1298        (num_data_qubits..total_qubits).collect()
1299    }
1300
1301    /// Create measurement schedule
1302    fn create_measurement_schedule(&self) -> QECResult<MeasurementSchedule> {
1303        let rounds = vec![MeasurementRound {
1304            stabilizers_to_measure: (0..self.encoding.stabilizers.len()).collect(),
1305            measurement_time: 0.1, // microseconds
1306            expected_outcomes: vec![1i8; self.encoding.stabilizers.len()],
1307        }];
1308
1309        let timing = ScheduleTiming {
1310            base_period: 1.0, // microseconds
1311            adaptive_timing: true,
1312            min_period: 0.5,
1313            max_period: 10.0,
1314        };
1315
1316        let adaptive_params = AdaptiveScheduleParams {
1317            error_threshold: 0.01,
1318            adaptation_rate: 0.1,
1319            history_window: 100,
1320        };
1321
1322        Ok(MeasurementSchedule {
1323            rounds,
1324            timing,
1325            adaptive_params,
1326        })
1327    }
1328
1329    /// Create default hardware topology
1330    fn create_default_topology(parameters: &CodeParameters) -> AnnealingTopology {
1331        let n = parameters.num_physical_qubits;
1332        let connectivity = Array2::from_shape_fn((n, n), |(i, j)| i == j); // Default to isolated qubits
1333        let coupling_strengths = Array2::zeros((n, n));
1334        let coherence_times = Array1::ones(n) * 100.0; // 100 microseconds
1335
1336        AnnealingTopology {
1337            connectivity,
1338            coupling_strengths,
1339            coherence_times,
1340            control_precision: 0.001,
1341            topology_type: TopologyType::Custom,
1342        }
1343    }
1344
1345    /// Implement logical X operation
1346    fn implement_logical_x(&self, physical_qubits: &[usize]) -> QECResult<Vec<QuantumGate>> {
1347        let mut gates = Vec::new();
1348
1349        // For repetition code, logical X is X on all qubits
1350        for &qubit in physical_qubits {
1351            gates.push(QuantumGate {
1352                gate_type: GateType::X,
1353                target_qubits: vec![qubit],
1354                control_qubits: Vec::new(),
1355                parameters: Vec::new(),
1356                gate_time: 0.05,
1357            });
1358        }
1359
1360        Ok(gates)
1361    }
1362
1363    /// Implement logical Z operation
1364    fn implement_logical_z(&self, physical_qubits: &[usize]) -> QECResult<Vec<QuantumGate>> {
1365        let mut gates = Vec::new();
1366
1367        // For repetition code, logical Z is Z on first qubit
1368        if let Some(&first_qubit) = physical_qubits.first() {
1369            gates.push(QuantumGate {
1370                gate_type: GateType::Z,
1371                target_qubits: vec![first_qubit],
1372                control_qubits: Vec::new(),
1373                parameters: Vec::new(),
1374                gate_time: 0.05,
1375            });
1376        }
1377
1378        Ok(gates)
1379    }
1380
1381    /// Implement logical measurement
1382    fn implement_logical_measurement(
1383        &self,
1384        physical_qubits: &[usize],
1385    ) -> QECResult<Vec<QuantumGate>> {
1386        let mut gates = Vec::new();
1387
1388        // Measure all qubits in the code block
1389        for &qubit in physical_qubits {
1390            gates.push(QuantumGate {
1391                gate_type: GateType::Measurement,
1392                target_qubits: vec![qubit],
1393                control_qubits: Vec::new(),
1394                parameters: Vec::new(),
1395                gate_time: 0.1,
1396            });
1397        }
1398
1399        Ok(gates)
1400    }
1401
1402    /// Get plaquette qubits for surface code
1403    fn get_plaquette_qubits(row: usize, col: usize, d: usize) -> Vec<usize> {
1404        let mut qubits = Vec::new();
1405
1406        // Calculate qubit indices for plaquette
1407        let center = row * d + col;
1408
1409        if row > 0 {
1410            qubits.push(center - d);
1411        }
1412        if col > 0 {
1413            qubits.push(center - 1);
1414        }
1415        if row < d - 1 {
1416            qubits.push(center + d);
1417        }
1418        if col < d - 1 {
1419            qubits.push(center + 1);
1420        }
1421
1422        qubits
1423    }
1424
1425    /// Get vertex qubits for surface code
1426    fn get_vertex_qubits(row: usize, col: usize, d: usize) -> Vec<usize> {
1427        // Similar to plaquette qubits
1428        Self::get_plaquette_qubits(row, col, d)
1429    }
1430}
1431
1432impl EncodingPerformanceMetrics {
1433    /// Create new performance metrics
1434    #[must_use]
1435    pub const fn new() -> Self {
1436        Self {
1437            qubit_overhead: 1.0,
1438            encoding_fidelity: 1.0,
1439            time_overhead: 0.0,
1440            error_suppression_factor: 1.0,
1441            threshold_estimate: 0.0,
1442            encoding_depth: 0,
1443            success_rate: 1.0,
1444        }
1445    }
1446}
1447
1448impl MonitoringData {
1449    /// Create new monitoring data
1450    #[must_use]
1451    pub const fn new() -> Self {
1452        Self {
1453            syndrome_measurements: Vec::new(),
1454            error_rates: Vec::new(),
1455            fidelity_history: Vec::new(),
1456            correction_events: Vec::new(),
1457        }
1458    }
1459}
1460
1461impl Default for LogicalEncoderConfig {
1462    fn default() -> Self {
1463        Self {
1464            enable_monitoring: true,
1465            target_fidelity: 0.99,
1466            max_encoding_overhead: 10.0,
1467            optimization_strategy: EncodingOptimizationStrategy::Balanced,
1468            hardware_integration: HardwareIntegrationMode::HardwareAware,
1469        }
1470    }
1471}
1472
1473#[cfg(test)]
1474mod tests {
1475    use super::*;
1476    use crate::quantum_error_correction::codes::*;
1477
1478    #[test]
1479    fn test_logical_encoder_creation() {
1480        let code = ErrorCorrectionCode::RepetitionCode;
1481        let parameters = CodeParameters {
1482            distance: 3,
1483            num_logical_qubits: 1,
1484            num_physical_qubits: 3,
1485            num_ancilla_qubits: 0,
1486            code_rate: 1.0 / 3.0,
1487            threshold_probability: 0.1,
1488        };
1489        let config = LogicalEncoderConfig::default();
1490
1491        let encoder = LogicalAnnealingEncoder::new(code, parameters, config);
1492        assert!(encoder.is_ok());
1493    }
1494
1495    #[test]
1496    fn test_ising_problem_encoding() {
1497        let mut encoder = create_test_encoder();
1498        let mut ising = IsingModel::new(2);
1499        ising.set_bias(0, 1.0).expect("failed to set bias in test");
1500        ising
1501            .set_coupling(0, 1, -0.5)
1502            .expect("failed to set coupling in test");
1503
1504        let result = encoder.encode_ising_problem(&ising);
1505        assert!(result.is_ok());
1506
1507        let encoding_result = result.expect("failed to encode ising problem in test");
1508        assert_eq!(encoding_result.logical_hamiltonian.num_logical_qubits, 2);
1509    }
1510
1511    #[test]
1512    fn test_stabilizer_generation() {
1513        let parameters = CodeParameters {
1514            distance: 3,
1515            num_logical_qubits: 1,
1516            num_physical_qubits: 3,
1517            num_ancilla_qubits: 0,
1518            code_rate: 1.0 / 3.0,
1519            threshold_probability: 0.1,
1520        };
1521
1522        let stabilizers = LogicalAnnealingEncoder::repetition_code_stabilizers(&parameters)
1523            .expect("failed to generate stabilizers in test");
1524        assert_eq!(stabilizers.len(), 2); // n-1 stabilizers for repetition code
1525    }
1526
1527    #[test]
1528    fn test_logical_operator_generation() {
1529        let code = ErrorCorrectionCode::RepetitionCode;
1530        let parameters = CodeParameters {
1531            distance: 3,
1532            num_logical_qubits: 1,
1533            num_physical_qubits: 3,
1534            num_ancilla_qubits: 0,
1535            code_rate: 1.0 / 3.0,
1536            threshold_probability: 0.1,
1537        };
1538
1539        let logical_ops = LogicalAnnealingEncoder::generate_logical_operators(&code, &parameters)
1540            .expect("failed to generate logical operators in test");
1541        assert_eq!(logical_ops.len(), 1);
1542        assert_eq!(logical_ops[0].logical_qubit, 0);
1543    }
1544
1545    #[test]
1546    fn test_encoding_circuit_generation() {
1547        let parameters = CodeParameters {
1548            distance: 3,
1549            num_logical_qubits: 1,
1550            num_physical_qubits: 3,
1551            num_ancilla_qubits: 0,
1552            code_rate: 1.0 / 3.0,
1553            threshold_probability: 0.1,
1554        };
1555
1556        let circuit = LogicalAnnealingEncoder::create_repetition_encoding_circuit(&parameters)
1557            .expect("failed to create encoding circuit in test");
1558        assert_eq!(circuit.gates.len(), 2); // 2 CNOT gates for 3-qubit repetition code
1559        assert_eq!(circuit.num_qubits, 3);
1560    }
1561
1562    fn create_test_encoder() -> LogicalAnnealingEncoder {
1563        let code = ErrorCorrectionCode::RepetitionCode;
1564        let parameters = CodeParameters {
1565            distance: 3,
1566            num_logical_qubits: 2,
1567            num_physical_qubits: 6,
1568            num_ancilla_qubits: 0,
1569            code_rate: 1.0 / 3.0,
1570            threshold_probability: 0.1,
1571        };
1572        let config = LogicalEncoderConfig::default();
1573
1574        LogicalAnnealingEncoder::new(code, parameters, config)
1575            .expect("failed to create test encoder")
1576    }
1577}