quantrs2_circuit/
validation.rs

1//! Circuit validation for different quantum backends
2//!
3//! This module provides comprehensive validation capabilities to ensure quantum circuits
4//! are compatible with specific backend requirements, constraints, and capabilities.
5use crate::builder::Circuit;
6use crate::noise_models::NoiseModel;
7use crate::routing::CouplingMap;
8use crate::transpiler::{HardwareSpec, NativeGateSet};
9use quantrs2_core::{
10    error::{QuantRS2Error, QuantRS2Result},
11    gate::GateOp,
12    qubit::QubitId,
13};
14use serde::{Deserialize, Serialize};
15use std::collections::{HashMap, HashSet};
16/// Validation rules for a quantum backend
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct ValidationRules {
19    /// Backend identifier
20    pub backend_name: String,
21    /// Maximum number of qubits
22    pub max_qubits: usize,
23    /// Qubit connectivity constraints
24    pub connectivity: ConnectivityConstraints,
25    /// Gate set restrictions
26    pub gate_restrictions: GateRestrictions,
27    /// Circuit depth limits
28    pub depth_limits: DepthLimits,
29    /// Measurement constraints
30    pub measurement_constraints: MeasurementConstraints,
31    /// Classical control flow constraints
32    pub classical_constraints: ClassicalConstraints,
33    /// Resource limits
34    pub resource_limits: ResourceLimits,
35}
36/// Connectivity constraints for qubits
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct ConnectivityConstraints {
39    /// Coupling map defining allowed connections
40    pub coupling_map: Option<CouplingMap>,
41    /// Whether all-to-all connectivity is allowed
42    pub all_to_all: bool,
43    /// Maximum distance for multi-qubit operations
44    pub max_distance: Option<usize>,
45    /// Restricted qubit pairs (forbidden connections)
46    pub forbidden_pairs: HashSet<(usize, usize)>,
47}
48/// Gate set restrictions
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct GateRestrictions {
51    /// Allowed native gates
52    pub native_gates: NativeGateSet,
53    /// Whether decomposition to native gates is required
54    pub require_native: bool,
55    /// Maximum gate parameters per gate
56    pub max_parameters: usize,
57    /// Forbidden gate combinations
58    pub forbidden_sequences: Vec<Vec<String>>,
59    /// Gate-specific qubit restrictions
60    pub gate_qubit_restrictions: HashMap<String, HashSet<usize>>,
61}
62/// Circuit depth and timing limits
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct DepthLimits {
65    /// Maximum circuit depth
66    pub max_depth: Option<usize>,
67    /// Maximum execution time in microseconds
68    pub max_execution_time: Option<f64>,
69    /// Maximum number of gates
70    pub max_gates: Option<usize>,
71    /// Depth limits by gate type
72    pub gate_type_limits: HashMap<String, usize>,
73}
74/// Measurement operation constraints
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct MeasurementConstraints {
77    /// Whether mid-circuit measurements are allowed
78    pub allow_mid_circuit: bool,
79    /// Maximum number of measurements
80    pub max_measurements: Option<usize>,
81    /// Whether measurements can be conditional
82    pub allow_conditional: bool,
83    /// Required measurement basis
84    pub required_basis: Option<String>,
85    /// Qubits that cannot be measured
86    pub non_measurable_qubits: HashSet<usize>,
87}
88/// Classical control flow constraints
89#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct ClassicalConstraints {
91    /// Whether classical control is supported
92    pub allow_classical_control: bool,
93    /// Maximum classical registers
94    pub max_classical_registers: Option<usize>,
95    /// Whether feedback is allowed
96    pub allow_feedback: bool,
97    /// Maximum conditional depth
98    pub max_conditional_depth: Option<usize>,
99}
100/// Resource usage limits
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct ResourceLimits {
103    /// Maximum memory usage in MB
104    pub max_memory_mb: Option<usize>,
105    /// Maximum execution shots
106    pub max_shots: Option<usize>,
107    /// Maximum job runtime in seconds
108    pub max_runtime_seconds: Option<usize>,
109    /// Priority constraints
110    pub priority_constraints: Option<PriorityConstraints>,
111}
112/// Job priority constraints
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct PriorityConstraints {
115    /// Minimum user priority level
116    pub min_priority: u32,
117    /// Queue position limits
118    pub max_queue_position: Option<usize>,
119    /// Time-based restrictions
120    pub time_restrictions: Option<TimeRestrictions>,
121}
122/// Time-based execution restrictions
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct TimeRestrictions {
125    /// Allowed execution hours (0-23)
126    pub allowed_hours: HashSet<u8>,
127    /// Maintenance windows (UTC)
128    pub maintenance_windows: Vec<(String, String)>,
129    /// Maximum job duration by time of day
130    pub duration_limits: HashMap<u8, usize>,
131}
132/// Circuit validation result
133#[derive(Debug, Clone)]
134pub struct ValidationResult {
135    /// Whether the circuit is valid
136    pub is_valid: bool,
137    /// Validation errors
138    pub errors: Vec<ValidationError>,
139    /// Validation warnings
140    pub warnings: Vec<ValidationWarning>,
141    /// Validation statistics
142    pub stats: ValidationStats,
143    /// Suggested fixes
144    pub suggestions: Vec<ValidationSuggestion>,
145}
146/// Validation error types
147#[derive(Debug, Clone, Serialize, Deserialize)]
148pub enum ValidationError {
149    /// Too many qubits for backend
150    ExceedsQubitLimit { required: usize, available: usize },
151    /// Gate not supported by backend
152    UnsupportedGate { gate_name: String, position: usize },
153    /// Qubit connectivity violation
154    ConnectivityViolation {
155        gate_name: String,
156        qubits: Vec<usize>,
157        position: usize,
158    },
159    /// Circuit depth exceeds limit
160    DepthLimitExceeded {
161        actual_depth: usize,
162        max_depth: usize,
163    },
164    /// Too many gates
165    GateCountExceeded {
166        actual_count: usize,
167        max_count: usize,
168    },
169    /// Measurement constraint violation
170    MeasurementViolation {
171        violation_type: String,
172        details: String,
173    },
174    /// Classical control violation
175    ClassicalControlViolation {
176        violation_type: String,
177        details: String,
178    },
179    /// Resource limit exceeded
180    ResourceLimitExceeded {
181        resource_type: String,
182        required: usize,
183        available: usize,
184    },
185    /// Invalid gate sequence
186    InvalidGateSequence {
187        sequence: Vec<String>,
188        position: usize,
189    },
190}
191/// Validation warning types
192#[derive(Debug, Clone, Serialize, Deserialize)]
193pub enum ValidationWarning {
194    /// Suboptimal gate usage
195    SuboptimalGateUsage {
196        gate_name: String,
197        suggested_alternative: String,
198        positions: Vec<usize>,
199    },
200    /// High error rate expected
201    HighErrorRate {
202        estimated_error: f64,
203        threshold: f64,
204    },
205    /// Long execution time
206    LongExecutionTime {
207        estimated_time: f64,
208        recommended_max: f64,
209    },
210    /// Resource usage warning
211    ResourceUsageWarning {
212        resource_type: String,
213        usage_percentage: f64,
214    },
215}
216/// Validation statistics
217#[derive(Debug, Clone)]
218pub struct ValidationStats {
219    /// Total validation time
220    pub validation_time: std::time::Duration,
221    /// Number of gates checked
222    pub gates_checked: usize,
223    /// Number of constraints evaluated
224    pub constraints_evaluated: usize,
225    /// Estimated circuit fidelity
226    pub estimated_fidelity: Option<f64>,
227    /// Estimated execution time
228    pub estimated_execution_time: Option<f64>,
229}
230/// Validation suggestion for fixing errors
231#[derive(Debug, Clone)]
232pub enum ValidationSuggestion {
233    /// Use transpilation to fix connectivity
234    UseTranspilation { suggested_router: String },
235    /// Decompose gates to native set
236    DecomposeGates { gates_to_decompose: Vec<String> },
237    /// Reduce circuit depth
238    ReduceDepth { suggested_passes: Vec<String> },
239    /// Split circuit into subcircuits
240    SplitCircuit { suggested_split_points: Vec<usize> },
241    /// Use different backend
242    SwitchBackend { recommended_backends: Vec<String> },
243}
244/// Circuit validator for different backends
245pub struct CircuitValidator {
246    /// Validation rules by backend
247    backend_rules: HashMap<String, ValidationRules>,
248    /// Cached validation results
249    validation_cache: HashMap<String, ValidationResult>,
250}
251impl CircuitValidator {
252    /// Create a new circuit validator
253    #[must_use]
254    pub fn new() -> Self {
255        let mut validator = Self {
256            backend_rules: HashMap::new(),
257            validation_cache: HashMap::new(),
258        };
259        validator.load_standard_backends();
260        validator
261    }
262    /// Add validation rules for a backend
263    pub fn add_backend_rules(&mut self, rules: ValidationRules) {
264        self.backend_rules.insert(rules.backend_name.clone(), rules);
265    }
266    /// Get available backends for validation
267    #[must_use]
268    pub fn available_backends(&self) -> Vec<String> {
269        self.backend_rules.keys().cloned().collect()
270    }
271    /// Validate a circuit against backend requirements
272    pub fn validate<const N: usize>(
273        &mut self,
274        circuit: &Circuit<N>,
275        backend: &str,
276        noise_model: Option<&NoiseModel>,
277    ) -> QuantRS2Result<ValidationResult> {
278        let start_time = std::time::Instant::now();
279        let rules = self
280            .backend_rules
281            .get(backend)
282            .ok_or_else(|| QuantRS2Error::InvalidInput(format!("Unknown backend: {backend}")))?;
283        let mut errors = Vec::new();
284        let mut warnings = Vec::new();
285        let mut suggestions = Vec::new();
286        if N > rules.max_qubits {
287            errors.push(ValidationError::ExceedsQubitLimit {
288                required: N,
289                available: rules.max_qubits,
290            });
291            suggestions.push(ValidationSuggestion::SwitchBackend {
292                recommended_backends: self.find_backends_with_qubits(N),
293            });
294        }
295        Self::validate_gate_set(circuit, rules, &mut errors, &warnings, &mut suggestions)?;
296        Self::validate_connectivity(circuit, rules, &mut errors, &mut suggestions)?;
297        self.validate_depth_limits(circuit, rules, &mut errors, &mut warnings, &mut suggestions)?;
298        Self::validate_measurements(circuit, rules, &errors, &warnings)?;
299        self.validate_resources(circuit, rules, &mut errors, &mut warnings)?;
300        let estimated_fidelity = if let Some(noise) = noise_model {
301            Some(Self::estimate_fidelity(circuit, noise)?)
302        } else {
303            None
304        };
305        let validation_time = start_time.elapsed();
306        let is_valid = errors.is_empty();
307        let result = ValidationResult {
308            is_valid,
309            errors,
310            warnings,
311            stats: ValidationStats {
312                validation_time,
313                gates_checked: circuit.gates().len(),
314                constraints_evaluated: Self::count_constraints(rules),
315                estimated_fidelity,
316                estimated_execution_time: Some(Self::estimate_execution_time(circuit, rules)),
317            },
318            suggestions,
319        };
320        Ok(result)
321    }
322    /// Validate gate set compliance
323    fn validate_gate_set<const N: usize>(
324        circuit: &Circuit<N>,
325        rules: &ValidationRules,
326        errors: &mut Vec<ValidationError>,
327        warnings: &[ValidationWarning],
328        suggestions: &mut Vec<ValidationSuggestion>,
329    ) -> QuantRS2Result<()> {
330        let mut non_native_gates = Vec::new();
331        let mut invalid_sequences: Vec<String> = Vec::new();
332        for (i, gate) in circuit.gates().iter().enumerate() {
333            let gate_name = gate.name();
334            let qubit_count = gate.qubits().len();
335            let is_native = match qubit_count {
336                1 => rules
337                    .gate_restrictions
338                    .native_gates
339                    .single_qubit
340                    .contains(gate_name),
341                2 => rules
342                    .gate_restrictions
343                    .native_gates
344                    .two_qubit
345                    .contains(gate_name),
346                _ => rules
347                    .gate_restrictions
348                    .native_gates
349                    .multi_qubit
350                    .contains(gate_name),
351            };
352            if !is_native {
353                if rules.gate_restrictions.require_native {
354                    errors.push(ValidationError::UnsupportedGate {
355                        gate_name: gate_name.to_string(),
356                        position: i,
357                    });
358                } else {
359                    non_native_gates.push(gate_name.to_string());
360                }
361            }
362            if let Some(allowed_qubits) = rules
363                .gate_restrictions
364                .gate_qubit_restrictions
365                .get(gate_name)
366            {
367                for qubit in gate.qubits() {
368                    let qubit_id = qubit.id() as usize;
369                    if !allowed_qubits.contains(&qubit_id) {
370                        errors.push(ValidationError::ConnectivityViolation {
371                            gate_name: gate_name.to_string(),
372                            qubits: vec![qubit_id],
373                            position: i,
374                        });
375                    }
376                }
377            }
378        }
379        if !non_native_gates.is_empty() {
380            suggestions.push(ValidationSuggestion::DecomposeGates {
381                gates_to_decompose: non_native_gates,
382            });
383        }
384        Ok(())
385    }
386    /// Validate qubit connectivity constraints
387    fn validate_connectivity<const N: usize>(
388        circuit: &Circuit<N>,
389        rules: &ValidationRules,
390        errors: &mut Vec<ValidationError>,
391        suggestions: &mut Vec<ValidationSuggestion>,
392    ) -> QuantRS2Result<()> {
393        if rules.connectivity.all_to_all {
394            return Ok(());
395        }
396        let coupling_map = rules.connectivity.coupling_map.as_ref();
397        let mut connectivity_violations = false;
398        for (i, gate) in circuit.gates().iter().enumerate() {
399            if gate.qubits().len() >= 2 {
400                let qubits: Vec<usize> = gate.qubits().iter().map(|q| q.id() as usize).collect();
401                if gate.qubits().len() == 2 {
402                    let q1 = qubits[0];
403                    let q2 = qubits[1];
404                    if rules.connectivity.forbidden_pairs.contains(&(q1, q2))
405                        || rules.connectivity.forbidden_pairs.contains(&(q2, q1))
406                    {
407                        errors.push(ValidationError::ConnectivityViolation {
408                            gate_name: gate.name().to_string(),
409                            qubits: vec![q1, q2],
410                            position: i,
411                        });
412                        connectivity_violations = true;
413                    }
414                    if let Some(coupling) = coupling_map {
415                        if !coupling.are_connected(q1, q2) {
416                            errors.push(ValidationError::ConnectivityViolation {
417                                gate_name: gate.name().to_string(),
418                                qubits: vec![q1, q2],
419                                position: i,
420                            });
421                            connectivity_violations = true;
422                        }
423                    }
424                }
425                if let Some(max_dist) = rules.connectivity.max_distance {
426                    if let Some(coupling) = coupling_map {
427                        for i in 0..qubits.len() {
428                            for j in i + 1..qubits.len() {
429                                let distance = coupling.distance(qubits[i], qubits[j]);
430                                if distance > max_dist {
431                                    errors.push(ValidationError::ConnectivityViolation {
432                                        gate_name: gate.name().to_string(),
433                                        qubits: vec![qubits[i], qubits[j]],
434                                        position: i,
435                                    });
436                                    connectivity_violations = true;
437                                }
438                            }
439                        }
440                    }
441                }
442            }
443        }
444        if connectivity_violations {
445            suggestions.push(ValidationSuggestion::UseTranspilation {
446                suggested_router: "SABRE".to_string(),
447            });
448        }
449        Ok(())
450    }
451    /// Validate circuit depth and timing limits
452    fn validate_depth_limits<const N: usize>(
453        &self,
454        circuit: &Circuit<N>,
455        rules: &ValidationRules,
456        errors: &mut Vec<ValidationError>,
457        warnings: &mut Vec<ValidationWarning>,
458        suggestions: &mut Vec<ValidationSuggestion>,
459    ) -> QuantRS2Result<()> {
460        let circuit_depth = Self::calculate_circuit_depth(circuit);
461        let gate_count = circuit.gates().len();
462        if let Some(max_depth) = rules.depth_limits.max_depth {
463            if circuit_depth > max_depth {
464                errors.push(ValidationError::DepthLimitExceeded {
465                    actual_depth: circuit_depth,
466                    max_depth,
467                });
468                suggestions.push(ValidationSuggestion::ReduceDepth {
469                    suggested_passes: vec![
470                        "GateCommutation".to_string(),
471                        "GateCancellation".to_string(),
472                    ],
473                });
474            }
475        }
476        if let Some(max_gates) = rules.depth_limits.max_gates {
477            if gate_count > max_gates {
478                errors.push(ValidationError::GateCountExceeded {
479                    actual_count: gate_count,
480                    max_count: max_gates,
481                });
482                suggestions.push(ValidationSuggestion::SplitCircuit {
483                    suggested_split_points: vec![max_gates / 2],
484                });
485            }
486        }
487        if let Some(max_time) = rules.depth_limits.max_execution_time {
488            let estimated_time = Self::estimate_execution_time(circuit, rules);
489            if estimated_time > max_time {
490                warnings.push(ValidationWarning::LongExecutionTime {
491                    estimated_time,
492                    recommended_max: max_time,
493                });
494            }
495        }
496        Ok(())
497    }
498    /// Validate measurement constraints
499    const fn validate_measurements<const N: usize>(
500        circuit: &Circuit<N>,
501        rules: &ValidationRules,
502        errors: &[ValidationError],
503        warnings: &[ValidationWarning],
504    ) -> QuantRS2Result<()> {
505        Ok(())
506    }
507    /// Validate resource requirements
508    fn validate_resources<const N: usize>(
509        &self,
510        circuit: &Circuit<N>,
511        rules: &ValidationRules,
512        errors: &mut Vec<ValidationError>,
513        warnings: &mut Vec<ValidationWarning>,
514    ) -> QuantRS2Result<()> {
515        let estimated_memory = Self::estimate_memory_usage(circuit);
516        if let Some(max_memory) = rules.resource_limits.max_memory_mb {
517            let estimated_memory_mb = estimated_memory / (1024 * 1024);
518            if estimated_memory_mb > max_memory {
519                errors.push(ValidationError::ResourceLimitExceeded {
520                    resource_type: "memory".to_string(),
521                    required: estimated_memory_mb,
522                    available: max_memory,
523                });
524            } else if estimated_memory_mb as f64 > max_memory as f64 * 0.8 {
525                warnings.push(ValidationWarning::ResourceUsageWarning {
526                    resource_type: "memory".to_string(),
527                    usage_percentage: (estimated_memory_mb as f64 / max_memory as f64) * 100.0,
528                });
529            }
530        }
531        Ok(())
532    }
533    /// Calculate circuit depth
534    fn calculate_circuit_depth<const N: usize>(circuit: &Circuit<N>) -> usize {
535        circuit.gates().len()
536    }
537    /// Estimate execution time
538    fn estimate_execution_time<const N: usize>(
539        circuit: &Circuit<N>,
540        rules: &ValidationRules,
541    ) -> f64 {
542        circuit.gates().len() as f64 * 0.1
543    }
544    /// Estimate memory usage
545    const fn estimate_memory_usage<const N: usize>(circuit: &Circuit<N>) -> usize {
546        if N <= 30 {
547            (1usize << N) * 16
548        } else {
549            usize::MAX
550        }
551    }
552    /// Estimate circuit fidelity
553    fn estimate_fidelity<const N: usize>(
554        circuit: &Circuit<N>,
555        noise_model: &NoiseModel,
556    ) -> QuantRS2Result<f64> {
557        let mut total_error = 0.0;
558        for gate in circuit.gates() {
559            let gate_name = gate.name();
560            let error = match gate.qubits().len() {
561                1 => noise_model
562                    .single_qubit_errors
563                    .get(gate_name)
564                    .map_or(0.001, |e| {
565                        e.depolarizing + e.amplitude_damping + e.phase_damping
566                    }),
567                2 => noise_model
568                    .two_qubit_errors
569                    .get(gate_name)
570                    .map_or(0.01, |e| e.depolarizing),
571                _ => 0.05,
572            };
573            total_error += error;
574        }
575        Ok((1.0 - total_error).max(0.0))
576    }
577    /// Count validation constraints
578    fn count_constraints(rules: &ValidationRules) -> usize {
579        let mut count = 0;
580        count += 1;
581        count += rules.gate_restrictions.native_gates.single_qubit.len();
582        count += rules.gate_restrictions.native_gates.two_qubit.len();
583        count += rules.gate_restrictions.native_gates.multi_qubit.len();
584        if rules.depth_limits.max_depth.is_some() {
585            count += 1;
586        }
587        if rules.depth_limits.max_gates.is_some() {
588            count += 1;
589        }
590        if rules.depth_limits.max_execution_time.is_some() {
591            count += 1;
592        }
593        count
594    }
595    /// Find backends that support the required number of qubits
596    fn find_backends_with_qubits(&self, required_qubits: usize) -> Vec<String> {
597        self.backend_rules
598            .iter()
599            .filter(|(_, rules)| rules.max_qubits >= required_qubits)
600            .map(|(name, _)| name.clone())
601            .collect()
602    }
603    /// Load standard backend validation rules
604    fn load_standard_backends(&mut self) {
605        self.add_backend_rules(ValidationRules::ibm_quantum());
606        self.add_backend_rules(ValidationRules::google_quantum());
607        self.add_backend_rules(ValidationRules::aws_braket());
608        self.add_backend_rules(ValidationRules::simulator());
609    }
610}
611impl ValidationRules {
612    /// IBM Quantum validation rules
613    #[must_use]
614    pub fn ibm_quantum() -> Self {
615        let native_gates = NativeGateSet {
616            single_qubit: ["X", "Y", "Z", "H", "S", "T", "RZ", "RX", "RY"]
617                .iter()
618                .map(|s| (*s).to_string())
619                .collect(),
620            two_qubit: ["CNOT", "CZ"].iter().map(|s| (*s).to_string()).collect(),
621            multi_qubit: HashSet::new(),
622            parameterized: [("RZ", 1), ("RX", 1), ("RY", 1)]
623                .iter()
624                .map(|(k, v)| ((*k).to_string(), *v))
625                .collect(),
626        };
627        Self {
628            backend_name: "ibm_quantum".to_string(),
629            max_qubits: 127,
630            connectivity: ConnectivityConstraints {
631                coupling_map: Some(CouplingMap::grid(11, 12)),
632                all_to_all: false,
633                max_distance: Some(10),
634                forbidden_pairs: HashSet::new(),
635            },
636            gate_restrictions: GateRestrictions {
637                native_gates,
638                require_native: true,
639                max_parameters: 3,
640                forbidden_sequences: Vec::new(),
641                gate_qubit_restrictions: HashMap::new(),
642            },
643            depth_limits: DepthLimits {
644                max_depth: Some(10_000),
645                max_execution_time: Some(100_000.0),
646                max_gates: Some(50_000),
647                gate_type_limits: HashMap::new(),
648            },
649            measurement_constraints: MeasurementConstraints {
650                allow_mid_circuit: true,
651                max_measurements: Some(1_000),
652                allow_conditional: true,
653                required_basis: None,
654                non_measurable_qubits: HashSet::new(),
655            },
656            classical_constraints: ClassicalConstraints {
657                allow_classical_control: true,
658                max_classical_registers: Some(100),
659                allow_feedback: true,
660                max_conditional_depth: Some(100),
661            },
662            resource_limits: ResourceLimits {
663                max_memory_mb: Some(8_192),
664                max_shots: Some(100_000),
665                max_runtime_seconds: Some(3_600),
666                priority_constraints: None,
667            },
668        }
669    }
670    /// Google Quantum AI validation rules
671    #[must_use]
672    pub fn google_quantum() -> Self {
673        let native_gates = NativeGateSet {
674            single_qubit: ["X", "Y", "Z", "H", "RZ", "SQRT_X"]
675                .iter()
676                .map(|s| (*s).to_string())
677                .collect(),
678            two_qubit: ["CZ", "ISWAP"].iter().map(|s| (*s).to_string()).collect(),
679            multi_qubit: HashSet::new(),
680            parameterized: [("RZ", 1)]
681                .iter()
682                .map(|(k, v)| ((*k).to_string(), *v))
683                .collect(),
684        };
685        Self {
686            backend_name: "google_quantum".to_string(),
687            max_qubits: 70,
688            connectivity: ConnectivityConstraints {
689                coupling_map: Some(CouplingMap::grid(8, 9)),
690                all_to_all: false,
691                max_distance: Some(5),
692                forbidden_pairs: HashSet::new(),
693            },
694            gate_restrictions: GateRestrictions {
695                native_gates,
696                require_native: true,
697                max_parameters: 1,
698                forbidden_sequences: Vec::new(),
699                gate_qubit_restrictions: HashMap::new(),
700            },
701            depth_limits: DepthLimits {
702                max_depth: Some(5_000),
703                max_execution_time: Some(50_000.0),
704                max_gates: Some(20_000),
705                gate_type_limits: HashMap::new(),
706            },
707            measurement_constraints: MeasurementConstraints {
708                allow_mid_circuit: false,
709                max_measurements: Some(70),
710                allow_conditional: false,
711                required_basis: Some("Z".to_string()),
712                non_measurable_qubits: HashSet::new(),
713            },
714            classical_constraints: ClassicalConstraints {
715                allow_classical_control: false,
716                max_classical_registers: Some(10),
717                allow_feedback: false,
718                max_conditional_depth: None,
719            },
720            resource_limits: ResourceLimits {
721                max_memory_mb: Some(4_096),
722                max_shots: Some(50_000),
723                max_runtime_seconds: Some(1_800),
724                priority_constraints: None,
725            },
726        }
727    }
728    /// AWS Braket validation rules
729    #[must_use]
730    pub fn aws_braket() -> Self {
731        let native_gates = NativeGateSet {
732            single_qubit: ["X", "Y", "Z", "H", "RZ", "RX", "RY"]
733                .iter()
734                .map(|s| (*s).to_string())
735                .collect(),
736            two_qubit: ["CNOT", "CZ", "ISWAP"]
737                .iter()
738                .map(|s| (*s).to_string())
739                .collect(),
740            multi_qubit: HashSet::new(),
741            parameterized: [("RZ", 1), ("RX", 1), ("RY", 1)]
742                .iter()
743                .map(|(k, v)| ((*k).to_string(), *v))
744                .collect(),
745        };
746        Self {
747            backend_name: "aws_braket".to_string(),
748            max_qubits: 100,
749            connectivity: ConnectivityConstraints {
750                coupling_map: None,
751                all_to_all: true,
752                max_distance: None,
753                forbidden_pairs: HashSet::new(),
754            },
755            gate_restrictions: GateRestrictions {
756                native_gates,
757                require_native: false,
758                max_parameters: 5,
759                forbidden_sequences: Vec::new(),
760                gate_qubit_restrictions: HashMap::new(),
761            },
762            depth_limits: DepthLimits {
763                max_depth: None,
764                max_execution_time: Some(200_000.0),
765                max_gates: None,
766                gate_type_limits: HashMap::new(),
767            },
768            measurement_constraints: MeasurementConstraints {
769                allow_mid_circuit: true,
770                max_measurements: None,
771                allow_conditional: true,
772                required_basis: None,
773                non_measurable_qubits: HashSet::new(),
774            },
775            classical_constraints: ClassicalConstraints {
776                allow_classical_control: true,
777                max_classical_registers: None,
778                allow_feedback: true,
779                max_conditional_depth: None,
780            },
781            resource_limits: ResourceLimits {
782                max_memory_mb: Some(16_384),
783                max_shots: Some(1_000_000),
784                max_runtime_seconds: Some(7_200),
785                priority_constraints: None,
786            },
787        }
788    }
789    /// Simulator validation rules
790    #[must_use]
791    pub fn simulator() -> Self {
792        let native_gates = NativeGateSet {
793            single_qubit: ["X", "Y", "Z", "H", "S", "T", "RZ", "RX", "RY", "U"]
794                .iter()
795                .map(|s| (*s).to_string())
796                .collect(),
797            two_qubit: ["CNOT", "CZ", "ISWAP", "SWAP", "CX"]
798                .iter()
799                .map(|s| (*s).to_string())
800                .collect(),
801            multi_qubit: ["Toffoli", "Fredkin"]
802                .iter()
803                .map(|s| (*s).to_string())
804                .collect(),
805            parameterized: [("RZ", 1), ("RX", 1), ("RY", 1), ("U", 3)]
806                .iter()
807                .map(|(k, v)| ((*k).to_string(), *v))
808                .collect(),
809        };
810        Self {
811            backend_name: "simulator".to_string(),
812            max_qubits: 30,
813            connectivity: ConnectivityConstraints {
814                coupling_map: None,
815                all_to_all: true,
816                max_distance: None,
817                forbidden_pairs: HashSet::new(),
818            },
819            gate_restrictions: GateRestrictions {
820                native_gates,
821                require_native: false,
822                max_parameters: 10,
823                forbidden_sequences: Vec::new(),
824                gate_qubit_restrictions: HashMap::new(),
825            },
826            depth_limits: DepthLimits {
827                max_depth: None,
828                max_execution_time: None,
829                max_gates: None,
830                gate_type_limits: HashMap::new(),
831            },
832            measurement_constraints: MeasurementConstraints {
833                allow_mid_circuit: true,
834                max_measurements: None,
835                allow_conditional: true,
836                required_basis: None,
837                non_measurable_qubits: HashSet::new(),
838            },
839            classical_constraints: ClassicalConstraints {
840                allow_classical_control: true,
841                max_classical_registers: None,
842                allow_feedback: true,
843                max_conditional_depth: None,
844            },
845            resource_limits: ResourceLimits {
846                max_memory_mb: None,
847                max_shots: None,
848                max_runtime_seconds: None,
849                priority_constraints: None,
850            },
851        }
852    }
853}
854impl Default for CircuitValidator {
855    fn default() -> Self {
856        Self::new()
857    }
858}
859#[cfg(test)]
860mod tests {
861    use super::*;
862    use quantrs2_core::gate::multi::CNOT;
863    use quantrs2_core::gate::single::Hadamard;
864    #[test]
865    fn test_validator_creation() {
866        let validator = CircuitValidator::new();
867        assert!(!validator.available_backends().is_empty());
868    }
869    #[test]
870    fn test_validation_rules_creation() {
871        let rules = ValidationRules::ibm_quantum();
872        assert_eq!(rules.backend_name, "ibm_quantum");
873        assert_eq!(rules.max_qubits, 127);
874    }
875    #[test]
876    fn test_simple_circuit_validation() {
877        let mut validator = CircuitValidator::new();
878        let mut circuit = Circuit::<2>::new();
879        circuit
880            .add_gate(Hadamard { target: QubitId(0) })
881            .expect("Failed to add Hadamard gate");
882        let result = validator
883            .validate(&circuit, "simulator", None)
884            .expect("Validation should succeed for simple circuit");
885        assert!(result.is_valid);
886    }
887    #[test]
888    fn test_qubit_limit_validation() {
889        let mut validator = CircuitValidator::new();
890        let circuit = Circuit::<200>::new();
891        let result = validator
892            .validate(&circuit, "ibm_quantum", None)
893            .expect("Validation should return result even for exceeding qubit limit");
894        assert!(!result.is_valid);
895        assert!(!result.errors.is_empty());
896    }
897    #[test]
898    fn test_connectivity_validation() {
899        let mut validator = CircuitValidator::new();
900        let mut circuit = Circuit::<3>::new();
901        circuit
902            .add_gate(CNOT {
903                control: QubitId(0),
904                target: QubitId(1),
905            })
906            .expect("Failed to add CNOT gate");
907        let result = validator
908            .validate(&circuit, "ibm_quantum", None)
909            .expect("Validation should return result for connectivity test");
910    }
911}