1use crate::gate_translation::GateType;
7use crate::buffer_pool::BufferPool;
9use crate::parallel_ops_stubs::*;
11
12#[derive(Debug, Clone)]
14pub struct QuantumGate {
15 gate_type: GateType,
16 target_qubits: Vec<usize>,
17 control_qubits: Option<Vec<usize>>,
18}
19
20impl QuantumGate {
21 pub const fn new(
22 gate_type: GateType,
23 target_qubits: Vec<usize>,
24 control_qubits: Option<Vec<usize>>,
25 ) -> Self {
26 Self {
27 gate_type,
28 target_qubits,
29 control_qubits,
30 }
31 }
32
33 pub const fn gate_type(&self) -> &GateType {
34 &self.gate_type
35 }
36
37 pub fn target_qubits(&self) -> &[usize] {
38 &self.target_qubits
39 }
40
41 pub fn control_qubits(&self) -> Option<&[usize]> {
42 self.control_qubits.as_deref()
43 }
44}
45use crate::error::QuantRS2Error;
46use std::collections::HashMap;
47
48#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
50pub struct ResourceEstimationConfig {
51 pub error_correction_code: ErrorCorrectionCode,
53 pub physical_error_rate: f64,
55 pub target_logical_error_rate: f64,
57 pub estimation_mode: EstimationMode,
59 pub include_hardware_overhead: bool,
61 pub hardware_platform: HardwarePlatform,
63 pub detailed_analysis: bool,
65}
66
67impl Default for ResourceEstimationConfig {
68 fn default() -> Self {
69 Self {
70 error_correction_code: ErrorCorrectionCode::SurfaceCode,
71 physical_error_rate: 1e-3,
72 target_logical_error_rate: 1e-12,
73 estimation_mode: EstimationMode::Realistic,
74 include_hardware_overhead: true,
75 hardware_platform: HardwarePlatform::Superconducting,
76 detailed_analysis: true,
77 }
78 }
79}
80
81#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
83pub enum ErrorCorrectionCode {
84 SurfaceCode,
85 ColorCode,
86 ToricCode,
87 ShorCode,
88 StabilizerCode(usize), }
90
91#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
93pub enum EstimationMode {
94 Conservative, Optimistic, Realistic, }
98
99#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
101pub enum HardwarePlatform {
102 Superconducting,
103 TrappedIon,
104 Photonic,
105 NeutralAtom,
106 SiliconQuantumDots,
107 TopologicalQubits,
108}
109
110pub struct ResourceEstimator {
112 config: ResourceEstimationConfig,
113 buffer_pool: Option<BufferPool<f64>>,
114}
115
116impl ResourceEstimator {
117 pub fn new() -> Self {
119 let config = ResourceEstimationConfig::default();
120 Self::with_config(config)
121 }
122
123 pub const fn with_config(config: ResourceEstimationConfig) -> Self {
125 let buffer_pool = if config.include_hardware_overhead {
126 Some(BufferPool::<f64>::new())
127 } else {
128 None
129 };
130
131 Self {
132 config,
133 buffer_pool,
134 }
135 }
136
137 pub fn estimate_resources(
139 &self,
140 circuit: &[QuantumGate],
141 num_qubits: usize,
142 ) -> Result<ResourceEstimate, QuantRS2Error> {
143 let gate_analysis = self.analyze_gates(circuit)?;
144 let logical_analysis = self.analyze_logical_requirements(&gate_analysis, num_qubits)?;
145 let physical_analysis = self.analyze_physical_requirements(&logical_analysis)?;
146 let time_analysis = self.analyze_execution_time(&gate_analysis)?;
147
148 let detailed_analysis = if self.config.detailed_analysis {
149 Some(DetailedAnalysis {
150 bottlenecks: self.identify_bottlenecks(&gate_analysis)?,
151 optimization_suggestions: self.generate_optimization_suggestions(&gate_analysis)?,
152 scaling_analysis: self.analyze_scaling(&gate_analysis, num_qubits)?,
153 error_analysis: self.analyze_error_propagation(&gate_analysis)?,
154 })
155 } else {
156 None
157 };
158
159 Ok(ResourceEstimate {
160 logical_qubits: logical_analysis.logical_qubits,
161 physical_qubits: physical_analysis.physical_qubits,
162 total_gates: gate_analysis.total_gates,
163 gate_breakdown: gate_analysis.gate_breakdown.clone(),
164 circuit_depth: gate_analysis.circuit_depth,
165 execution_time: time_analysis.total_time,
166 time_breakdown: time_analysis.time_breakdown,
167 error_budget: physical_analysis.error_budget,
168 overhead_factor: physical_analysis.overhead_factor,
169 magic_states: logical_analysis.magic_states,
170 distillation_overhead: logical_analysis.distillation_overhead,
171 spatial_overhead: physical_analysis.spatial_overhead,
172 temporal_overhead: time_analysis.temporal_overhead,
173 detailed_analysis,
174 })
175 }
176
177 fn analyze_gates(&self, circuit: &[QuantumGate]) -> Result<GateAnalysis, QuantRS2Error> {
179 let mut gate_breakdown = HashMap::new();
180 let mut depth_counter = HashMap::new();
181 let mut max_depth = 0;
182
183 if circuit.len() > 1000 {
185 let gate_counts: HashMap<String, usize> = circuit
187 .par_iter()
188 .map(|gate| format!("{:?}", gate.gate_type()))
189 .fold(HashMap::new, |mut acc, gate_type| {
190 *acc.entry(gate_type).or_insert(0) += 1;
191 acc
192 })
193 .reduce(HashMap::new, |mut acc1, acc2| {
194 for (key, value) in acc2 {
195 *acc1.entry(key).or_insert(0) += value;
196 }
197 acc1
198 });
199 gate_breakdown = gate_counts;
200 } else {
201 for gate in circuit {
203 let gate_type = format!("{:?}", gate.gate_type());
204 *gate_breakdown.entry(gate_type).or_insert(0) += 1;
205 }
206 }
207
208 for gate in circuit {
210 for &qubit in gate.target_qubits() {
211 let qubit_depth = depth_counter.entry(qubit).or_insert(0);
212 *qubit_depth += 1;
213 max_depth = max_depth.max(*qubit_depth);
214 }
215 }
216
217 let two_qubit_count = self.count_two_qubit_gates(circuit);
219 let _complexity_score =
220 self.calculate_complexity_score(circuit.len(), max_depth, two_qubit_count);
221
222 Ok(GateAnalysis {
223 total_gates: circuit.len(),
224 gate_breakdown,
225 circuit_depth: max_depth,
226 clifford_gates: self.count_clifford_gates(circuit),
227 non_clifford_gates: self.count_non_clifford_gates(circuit),
228 two_qubit_gates: self.count_two_qubit_gates(circuit),
229 measurement_gates: self.count_measurement_gates(circuit),
230 })
231 }
232
233 fn count_clifford_gates(&self, circuit: &[QuantumGate]) -> usize {
235 use crate::gate_translation::GateType;
236
237 circuit
238 .iter()
239 .filter(|gate| {
240 matches!(
241 gate.gate_type(),
242 GateType::X
243 | GateType::Y
244 | GateType::Z
245 | GateType::H
246 | GateType::CNOT
247 | GateType::CZ
248 | GateType::S
249 )
250 })
251 .count()
252 }
253
254 fn count_non_clifford_gates(&self, circuit: &[QuantumGate]) -> usize {
256 use crate::gate_translation::GateType;
257
258 circuit
259 .iter()
260 .filter(|gate| {
261 matches!(
262 gate.gate_type(),
263 GateType::T
264 | GateType::Phase(_)
265 | GateType::Rx(_)
266 | GateType::Ry(_)
267 | GateType::Rz(_)
268 )
269 })
270 .count()
271 }
272
273 fn count_two_qubit_gates(&self, circuit: &[QuantumGate]) -> usize {
275 circuit
276 .iter()
277 .filter(|gate| gate.target_qubits().len() >= 2)
278 .count()
279 }
280
281 fn count_measurement_gates(&self, circuit: &[QuantumGate]) -> usize {
283 use crate::gate_translation::GateType;
284
285 circuit
286 .iter()
287 .filter(
288 |gate| matches!(gate.gate_type(), GateType::Custom(ref name) if name == "Measure"),
289 )
290 .count()
291 }
292
293 fn analyze_logical_requirements(
295 &self,
296 gate_analysis: &GateAnalysis,
297 num_qubits: usize,
298 ) -> Result<LogicalAnalysis, QuantRS2Error> {
299 let magic_states = self.estimate_magic_states(gate_analysis)?;
300 let distillation_overhead = self.calculate_distillation_overhead(magic_states)?;
301
302 Ok(LogicalAnalysis {
303 logical_qubits: num_qubits,
304 magic_states,
305 distillation_overhead,
306 ancilla_qubits: self.estimate_ancilla_qubits(gate_analysis)?,
307 workspace_qubits: self.estimate_workspace_qubits(gate_analysis)?,
308 })
309 }
310
311 fn estimate_magic_states(&self, gate_analysis: &GateAnalysis) -> Result<usize, QuantRS2Error> {
313 let t_gates = gate_analysis.non_clifford_gates;
315
316 let additional = match self.config.estimation_mode {
318 EstimationMode::Conservative => (t_gates as f64 * 1.5) as usize,
319 EstimationMode::Optimistic => t_gates,
320 EstimationMode::Realistic => (t_gates as f64 * 1.2) as usize,
321 };
322
323 Ok(additional)
324 }
325
326 fn calculate_distillation_overhead(&self, magic_states: usize) -> Result<f64, QuantRS2Error> {
328 if magic_states == 0 {
329 return Ok(1.0);
330 }
331
332 let base_ratio = match self.config.error_correction_code {
334 ErrorCorrectionCode::ColorCode => 12.0,
335 ErrorCorrectionCode::ShorCode => 20.0,
336 ErrorCorrectionCode::SurfaceCode
337 | ErrorCorrectionCode::ToricCode
338 | ErrorCorrectionCode::StabilizerCode(_) => 15.0, };
340
341 let error_factor = (-self.config.target_logical_error_rate.log10() / 3.0).max(1.0);
342
343 Ok(base_ratio * error_factor)
344 }
345
346 fn estimate_ancilla_qubits(
348 &self,
349 gate_analysis: &GateAnalysis,
350 ) -> Result<usize, QuantRS2Error> {
351 let syndrome_qubits = match self.config.error_correction_code {
353 ErrorCorrectionCode::SurfaceCode => gate_analysis.total_gates / 10,
354 ErrorCorrectionCode::ColorCode => gate_analysis.total_gates / 12,
355 _ => gate_analysis.total_gates / 15,
356 };
357
358 Ok(syndrome_qubits.max(10)) }
360
361 fn estimate_workspace_qubits(
363 &self,
364 gate_analysis: &GateAnalysis,
365 ) -> Result<usize, QuantRS2Error> {
366 let workspace = gate_analysis.two_qubit_gates / 5;
368
369 Ok(workspace.max(5)) }
371
372 fn analyze_physical_requirements(
374 &self,
375 logical_analysis: &LogicalAnalysis,
376 ) -> Result<PhysicalAnalysis, QuantRS2Error> {
377 let code_distance = self.calculate_code_distance()?;
378 let qubits_per_logical = self.calculate_qubits_per_logical(code_distance)?;
379
380 let total_logical = logical_analysis.logical_qubits
381 + logical_analysis.ancilla_qubits
382 + logical_analysis.workspace_qubits;
383
384 let physical_qubits = total_logical * qubits_per_logical;
385
386 let overhead_factor = physical_qubits as f64 / logical_analysis.logical_qubits as f64;
387
388 Ok(PhysicalAnalysis {
389 physical_qubits,
390 code_distance,
391 qubits_per_logical,
392 overhead_factor,
393 spatial_overhead: self.calculate_spatial_overhead(physical_qubits)?,
394 error_budget: self.calculate_error_budget()?,
395 })
396 }
397
398 fn calculate_code_distance(&self) -> Result<usize, QuantRS2Error> {
400 let p = self.config.physical_error_rate;
401 let p_target = self.config.target_logical_error_rate;
402
403 let threshold = match self.config.error_correction_code {
405 ErrorCorrectionCode::ColorCode => 8e-3,
406 ErrorCorrectionCode::SurfaceCode | _ => 1e-2,
407 };
408
409 if p > threshold {
410 return Err(QuantRS2Error::UnsupportedOperation(
411 "Physical error rate exceeds threshold".into(),
412 ));
413 }
414
415 let ratio = p / threshold;
417 let distance = (-p_target.log10() / ratio.log10()).ceil() as usize;
418
419 Ok(if distance % 2 == 0 {
421 distance + 1
422 } else {
423 distance
424 }
425 .max(3))
426 }
427
428 const fn calculate_qubits_per_logical(&self, distance: usize) -> Result<usize, QuantRS2Error> {
430 match self.config.error_correction_code {
431 ErrorCorrectionCode::SurfaceCode => Ok(2 * distance * distance - 2 * distance + 1),
432 ErrorCorrectionCode::ColorCode => Ok(3 * distance * distance),
433 ErrorCorrectionCode::ToricCode => Ok(2 * distance * distance),
434 ErrorCorrectionCode::ShorCode => Ok(9),
435 ErrorCorrectionCode::StabilizerCode(d) => Ok(d * d),
436 }
437 }
438
439 fn calculate_spatial_overhead(&self, physical_qubits: usize) -> Result<f64, QuantRS2Error> {
441 let base_overhead = match self.config.hardware_platform {
442 HardwarePlatform::Superconducting => 1.5,
443 HardwarePlatform::TrappedIon => 2.0,
444 HardwarePlatform::Photonic => 3.0,
445 HardwarePlatform::NeutralAtom => 1.8,
446 HardwarePlatform::SiliconQuantumDots => 2.5,
447 HardwarePlatform::TopologicalQubits => 1.2,
448 };
449
450 let scaling_factor = (physical_qubits as f64).log10().mul_add(0.1, 1.0);
452
453 Ok(base_overhead * scaling_factor)
454 }
455
456 fn calculate_error_budget(&self) -> Result<ErrorBudget, QuantRS2Error> {
458 let total_budget = self.config.target_logical_error_rate;
459
460 let gate_errors = total_budget * 0.4;
462 let measurement_errors = total_budget * 0.2;
463 let memory_errors = total_budget * 0.3;
464 let correction_errors = total_budget * 0.1;
465
466 Ok(ErrorBudget {
467 total: total_budget,
468 gate_errors,
469 measurement_errors,
470 memory_errors,
471 correction_errors,
472 })
473 }
474
475 fn analyze_execution_time(
477 &self,
478 gate_analysis: &GateAnalysis,
479 ) -> Result<TimeAnalysis, QuantRS2Error> {
480 let gate_times = self.get_gate_timing_parameters()?;
481
482 let mut time_breakdown = HashMap::new();
483 let mut total_time = 0.0;
484
485 for (gate_type, count) in &gate_analysis.gate_breakdown {
486 let gate_time = gate_times.get(gate_type).unwrap_or(&1e-6); let total_gate_time = *gate_time * (*count as f64);
488 time_breakdown.insert(gate_type.clone(), total_gate_time);
489 total_time += total_gate_time;
490 }
491
492 let correction_overhead = total_time * 0.5; total_time += correction_overhead;
495
496 let temporal_overhead = self.calculate_temporal_overhead(total_time)?;
497
498 Ok(TimeAnalysis {
499 total_time,
500 time_breakdown,
501 correction_overhead,
502 temporal_overhead,
503 })
504 }
505
506 fn get_gate_timing_parameters(&self) -> Result<HashMap<String, f64>, QuantRS2Error> {
508 let mut timings = HashMap::new();
509
510 match self.config.hardware_platform {
511 HardwarePlatform::Superconducting => {
512 timings.insert("X".to_string(), 20e-9);
513 timings.insert("Y".to_string(), 20e-9);
514 timings.insert("Z".to_string(), 1e-9);
515 timings.insert("H".to_string(), 20e-9);
516 timings.insert("CNOT".to_string(), 40e-9);
517 timings.insert("T".to_string(), 20e-9);
518 timings.insert("Measure".to_string(), 300e-9);
519 }
520 HardwarePlatform::TrappedIon => {
521 timings.insert("X".to_string(), 10e-6);
522 timings.insert("Y".to_string(), 10e-6);
523 timings.insert("Z".to_string(), 1e-6);
524 timings.insert("H".to_string(), 10e-6);
525 timings.insert("CNOT".to_string(), 100e-6);
526 timings.insert("T".to_string(), 10e-6);
527 timings.insert("Measure".to_string(), 100e-6);
528 }
529 HardwarePlatform::Photonic => {
530 timings.insert("X".to_string(), 1e-9);
531 timings.insert("Y".to_string(), 1e-9);
532 timings.insert("Z".to_string(), 1e-9);
533 timings.insert("H".to_string(), 1e-9);
534 timings.insert("CNOT".to_string(), 10e-9);
535 timings.insert("T".to_string(), 1e-9);
536 timings.insert("Measure".to_string(), 1e-9);
537 }
538 _ => {
539 timings.insert("X".to_string(), 1e-6);
541 timings.insert("Y".to_string(), 1e-6);
542 timings.insert("Z".to_string(), 1e-6);
543 timings.insert("H".to_string(), 1e-6);
544 timings.insert("CNOT".to_string(), 2e-6);
545 timings.insert("T".to_string(), 1e-6);
546 timings.insert("Measure".to_string(), 10e-6);
547 }
548 }
549
550 Ok(timings)
551 }
552
553 const fn calculate_temporal_overhead(&self, _base_time: f64) -> Result<f64, QuantRS2Error> {
555 let overhead = match self.config.hardware_platform {
556 HardwarePlatform::Superconducting => 1.3,
557 HardwarePlatform::TrappedIon => 1.8,
558 HardwarePlatform::Photonic | HardwarePlatform::TopologicalQubits => 1.1,
559 HardwarePlatform::NeutralAtom => 1.5,
560 HardwarePlatform::SiliconQuantumDots => 2.0,
561 };
562
563 Ok(overhead)
564 }
565
566 fn identify_bottlenecks(
568 &self,
569 gate_analysis: &GateAnalysis,
570 ) -> Result<Vec<String>, QuantRS2Error> {
571 let mut bottlenecks = Vec::new();
572
573 if gate_analysis.circuit_depth > 1000 {
574 bottlenecks.push("High circuit depth may lead to decoherence issues".to_string());
575 }
576
577 if gate_analysis.two_qubit_gates > gate_analysis.total_gates / 2 {
578 bottlenecks.push("High ratio of two-qubit gates increases error rates".to_string());
579 }
580
581 if gate_analysis.non_clifford_gates > 100 {
582 bottlenecks
583 .push("Large number of non-Clifford gates requires many magic states".to_string());
584 }
585
586 Ok(bottlenecks)
587 }
588
589 fn calculate_complexity_score(
591 &self,
592 total_gates: usize,
593 depth: usize,
594 two_qubit_gates: usize,
595 ) -> f64 {
596 let gate_complexity = total_gates as f64;
598 let depth_complexity = depth as f64 * 1.5; let two_qubit_complexity = two_qubit_gates as f64 * 2.0; (gate_complexity + depth_complexity + two_qubit_complexity) / (total_gates as f64 + 1.0)
602 }
603
604 fn generate_optimization_suggestions(
606 &self,
607 gate_analysis: &GateAnalysis,
608 ) -> Result<Vec<String>, QuantRS2Error> {
609 let mut suggestions = Vec::new();
610
611 let complexity_score = self.calculate_complexity_score(
613 gate_analysis.total_gates,
614 gate_analysis.circuit_depth,
615 gate_analysis.two_qubit_gates,
616 );
617
618 if gate_analysis.circuit_depth > 500 {
619 suggestions.push("Consider circuit parallelization to reduce depth".to_string());
620 if complexity_score > 3.0 {
621 suggestions.push(
622 "Use SciRS2 parallel gate scheduling for improved performance".to_string(),
623 );
624 }
625 }
626
627 if gate_analysis.non_clifford_gates > 50 {
628 suggestions.push("Apply Clifford+T optimization to reduce T-gate count".to_string());
629 if self.config.detailed_analysis {
630 suggestions.push("Consider SciRS2 magic state optimization algorithms".to_string());
631 }
632 }
633
634 if gate_analysis.two_qubit_gates > gate_analysis.total_gates / 3 {
635 suggestions.push(
636 "High two-qubit gate ratio detected - consider gate fusion optimization"
637 .to_string(),
638 );
639 }
640
641 match self.config.hardware_platform {
643 HardwarePlatform::Superconducting => {
644 suggestions.push("Optimize for superconducting hardware connectivity".to_string());
645 }
646 HardwarePlatform::TrappedIon => {
647 suggestions
648 .push("Leverage all-to-all connectivity for trapped ion systems".to_string());
649 }
650 _ => {
651 suggestions.push("Consider hardware-specific gate set optimization".to_string());
652 }
653 }
654
655 suggestions.push("Consider using error mitigation techniques".to_string());
656 suggestions.push("Apply SciRS2 memory-efficient state vector simulation".to_string());
657
658 Ok(suggestions)
659 }
660
661 fn analyze_scaling(
663 &self,
664 gate_analysis: &GateAnalysis,
665 num_qubits: usize,
666 ) -> Result<ScalingAnalysis, QuantRS2Error> {
667 let time_complexity = if gate_analysis.two_qubit_gates > 0 {
668 format!(
669 "O(n^{})",
670 (gate_analysis.two_qubit_gates as f64 / num_qubits as f64)
671 .log2()
672 .ceil()
673 )
674 } else {
675 "O(n)".to_string()
676 };
677
678 let space_complexity = "O(2^n)".to_string(); Ok(ScalingAnalysis {
681 time_complexity,
682 space_complexity,
683 predicted_scaling: self.predict_scaling_factors(num_qubits)?,
684 })
685 }
686
687 fn predict_scaling_factors(
689 &self,
690 _num_qubits: usize,
691 ) -> Result<HashMap<String, f64>, QuantRS2Error> {
692 let mut factors = HashMap::new();
693
694 factors.insert("10_qubits".to_string(), 1.0);
695 factors.insert("20_qubits".to_string(), 4.0);
696 factors.insert("50_qubits".to_string(), 100.0);
697 factors.insert("100_qubits".to_string(), 10000.0);
698
699 Ok(factors)
700 }
701
702 fn analyze_error_propagation(
704 &self,
705 gate_analysis: &GateAnalysis,
706 ) -> Result<ErrorPropagationAnalysis, QuantRS2Error> {
707 let error_accumulation = gate_analysis.total_gates as f64 * self.config.physical_error_rate;
708 let error_amplification = (gate_analysis.two_qubit_gates as f64).mul_add(0.1, 1.0);
709
710 Ok(ErrorPropagationAnalysis {
711 error_accumulation,
712 error_amplification,
713 critical_paths: vec!["Long sequences of two-qubit gates".to_string()],
714 })
715 }
716}
717
718#[derive(Debug, Clone)]
720pub struct ResourceEstimate {
721 pub logical_qubits: usize,
723 pub physical_qubits: usize,
725 pub total_gates: usize,
727 pub gate_breakdown: HashMap<String, usize>,
729 pub circuit_depth: usize,
731 pub execution_time: f64,
733 pub time_breakdown: HashMap<String, f64>,
735 pub error_budget: ErrorBudget,
737 pub overhead_factor: f64,
739 pub magic_states: usize,
741 pub distillation_overhead: f64,
743 pub spatial_overhead: f64,
745 pub temporal_overhead: f64,
747 pub detailed_analysis: Option<DetailedAnalysis>,
749}
750
751#[derive(Debug, Clone)]
753struct GateAnalysis {
754 total_gates: usize,
755 gate_breakdown: HashMap<String, usize>,
756 circuit_depth: usize,
757 clifford_gates: usize,
758 non_clifford_gates: usize,
759 two_qubit_gates: usize,
760 measurement_gates: usize,
761}
762
763#[derive(Debug, Clone)]
765struct LogicalAnalysis {
766 logical_qubits: usize,
767 magic_states: usize,
768 distillation_overhead: f64,
769 ancilla_qubits: usize,
770 workspace_qubits: usize,
771}
772
773#[derive(Debug, Clone)]
775struct PhysicalAnalysis {
776 physical_qubits: usize,
777 code_distance: usize,
778 qubits_per_logical: usize,
779 overhead_factor: f64,
780 spatial_overhead: f64,
781 error_budget: ErrorBudget,
782}
783
784#[derive(Debug, Clone)]
786struct TimeAnalysis {
787 total_time: f64,
788 time_breakdown: HashMap<String, f64>,
789 correction_overhead: f64,
790 temporal_overhead: f64,
791}
792
793#[derive(Debug, Clone)]
795pub struct ErrorBudget {
796 pub total: f64,
797 pub gate_errors: f64,
798 pub measurement_errors: f64,
799 pub memory_errors: f64,
800 pub correction_errors: f64,
801}
802
803#[derive(Debug, Clone)]
805pub struct DetailedAnalysis {
806 pub bottlenecks: Vec<String>,
807 pub optimization_suggestions: Vec<String>,
808 pub scaling_analysis: ScalingAnalysis,
809 pub error_analysis: ErrorPropagationAnalysis,
810}
811
812#[derive(Debug, Clone)]
814pub struct ScalingAnalysis {
815 pub time_complexity: String,
816 pub space_complexity: String,
817 pub predicted_scaling: HashMap<String, f64>,
818}
819
820#[derive(Debug, Clone)]
822pub struct ErrorPropagationAnalysis {
823 pub error_accumulation: f64,
824 pub error_amplification: f64,
825 pub critical_paths: Vec<String>,
826}
827
828#[cfg(test)]
829mod tests {
830 use super::*;
831 use super::{GateType, QuantumGate};
832
833 #[test]
834 fn test_resource_estimator_creation() {
835 let estimator = ResourceEstimator::new();
836 assert!(matches!(
837 estimator.config.error_correction_code,
838 ErrorCorrectionCode::SurfaceCode
839 ));
840 }
841
842 #[test]
843 fn test_gate_analysis() {
844 let estimator = ResourceEstimator::new();
845 let circuit = vec![
846 QuantumGate::new(GateType::H, vec![0], None),
847 QuantumGate::new(GateType::CNOT, vec![0, 1], None),
848 QuantumGate::new(GateType::T, vec![0], None),
849 ];
850
851 let analysis = estimator
852 .analyze_gates(&circuit)
853 .expect("Gate analysis should succeed");
854 assert_eq!(analysis.total_gates, 3);
855 assert_eq!(analysis.clifford_gates, 2);
856 assert_eq!(analysis.non_clifford_gates, 1);
857 }
858
859 #[test]
860 fn test_magic_state_estimation() {
861 let estimator = ResourceEstimator::new();
862 let gate_analysis = GateAnalysis {
863 total_gates: 10,
864 gate_breakdown: HashMap::new(),
865 circuit_depth: 5,
866 clifford_gates: 7,
867 non_clifford_gates: 3,
868 two_qubit_gates: 2,
869 measurement_gates: 0,
870 };
871
872 let magic_states = estimator
873 .estimate_magic_states(&gate_analysis)
874 .expect("Magic state estimation should succeed");
875 assert!(magic_states >= 3); }
877
878 #[test]
879 fn test_code_distance_calculation() {
880 let mut config = ResourceEstimationConfig::default();
881 config.physical_error_rate = 1e-3;
882 config.target_logical_error_rate = 1e-12;
883
884 let estimator = ResourceEstimator::with_config(config);
885 let distance = estimator
886 .calculate_code_distance()
887 .expect("Code distance calculation should succeed");
888 assert!(distance >= 3);
889 assert!(distance % 2 == 1); }
891
892 #[test]
893 fn test_resource_estimation_small_circuit() {
894 let estimator = ResourceEstimator::new();
895 let circuit = vec![
896 QuantumGate::new(GateType::H, vec![0], None),
897 QuantumGate::new(GateType::CNOT, vec![0, 1], None),
898 ];
899
900 let estimate = estimator
901 .estimate_resources(&circuit, 2)
902 .expect("Resource estimation should succeed");
903 assert!(estimate.logical_qubits > 0);
904 assert!(estimate.physical_qubits > estimate.logical_qubits);
905 assert!(estimate.execution_time > 0.0);
906 }
907}