quantrs2_ml/
benchmarking.rs

1//! Unified benchmarking framework for quantum machine learning
2//!
3//! This module provides comprehensive benchmarking capabilities for quantum ML
4//! algorithms, including performance metrics, scalability analysis, and
5//! quantum advantage assessment.
6
7use crate::circuit_integration::QuantumMLExecutor;
8use crate::error::{MLError, Result};
9use crate::simulator_backends::{Backend, BackendCapabilities, SimulatorBackend};
10use quantrs2_core::prelude::*;
11use scirs2_core::ndarray::{Array1, Array2};
12use std::collections::HashMap;
13use std::time::{Duration, Instant};
14
15/// Comprehensive benchmarking framework
16pub struct BenchmarkFramework {
17    /// Registered benchmarks
18    benchmarks: HashMap<String, Box<dyn Benchmark>>,
19    /// Results storage
20    results: BenchmarkResults,
21    /// Configuration
22    config: BenchmarkConfig,
23}
24
25/// Benchmark configuration
26#[derive(Debug, Clone)]
27pub struct BenchmarkConfig {
28    /// Number of repetitions per benchmark
29    pub repetitions: usize,
30    /// Warm-up runs before timing
31    pub warmup_runs: usize,
32    /// Maximum time per benchmark (seconds)
33    pub max_time_per_benchmark: f64,
34    /// Include memory profiling
35    pub profile_memory: bool,
36    /// Include convergence analysis
37    pub analyze_convergence: bool,
38    /// Statistical confidence level
39    pub confidence_level: f64,
40    /// Output directory for benchmark results
41    pub output_directory: String,
42}
43
44impl Default for BenchmarkConfig {
45    fn default() -> Self {
46        Self {
47            repetitions: 10,
48            warmup_runs: 3,
49            max_time_per_benchmark: 300.0, // 5 minutes
50            profile_memory: true,
51            analyze_convergence: true,
52            confidence_level: 0.95,
53            output_directory: "/tmp/quantum_ml_benchmarks".to_string(),
54        }
55    }
56}
57
58/// Benchmark trait
59pub trait Benchmark: Send + Sync {
60    /// Get benchmark name
61    fn name(&self) -> &str;
62
63    /// Get benchmark description
64    fn description(&self) -> &str;
65
66    /// Setup benchmark (called once before all runs)
67    fn setup(&mut self) -> Result<()>;
68
69    /// Run single benchmark iteration
70    fn run(&mut self, backend: &Backend) -> Result<BenchmarkRunResult>;
71
72    /// Cleanup after benchmark
73    fn cleanup(&mut self) -> Result<()>;
74
75    /// Get expected scaling behavior
76    fn expected_scaling(&self) -> ScalingType;
77
78    /// Get benchmark category
79    fn category(&self) -> BenchmarkCategory;
80}
81
82/// Benchmark run result
83#[derive(Debug, Clone)]
84pub struct BenchmarkRunResult {
85    /// Execution time
86    pub execution_time: Duration,
87    /// Memory usage (bytes)
88    pub memory_usage: Option<usize>,
89    /// Algorithm-specific metrics
90    pub metrics: HashMap<String, f64>,
91    /// Final result value
92    pub result_value: Option<f64>,
93    /// Success flag
94    pub success: bool,
95    /// Error message if failed
96    pub error_message: Option<String>,
97}
98
99/// Scaling behavior types
100#[derive(Debug, Clone, Copy)]
101pub enum ScalingType {
102    /// Polynomial scaling O(n^k)
103    Polynomial(f64),
104    /// Exponential scaling O(2^n)
105    Exponential,
106    /// Logarithmic scaling O(log n)
107    Logarithmic,
108    /// Linear scaling O(n)
109    Linear,
110    /// Constant time O(1)
111    Constant,
112}
113
114/// Benchmark categories
115#[derive(Debug, Clone, Copy)]
116pub enum BenchmarkCategory {
117    /// Algorithm performance
118    Algorithm,
119    /// Hardware simulation
120    Hardware,
121    /// Memory usage
122    Memory,
123    /// Scalability
124    Scalability,
125    /// Accuracy
126    Accuracy,
127    /// Quantum advantage
128    QuantumAdvantage,
129}
130
131/// Aggregated benchmark results
132#[derive(Debug, Clone)]
133pub struct BenchmarkResults {
134    /// Results by benchmark name
135    results: HashMap<String, Vec<BenchmarkRunResult>>,
136    /// Statistical summaries
137    summaries: HashMap<String, BenchmarkSummary>,
138    /// Metadata
139    metadata: BenchmarkMetadata,
140}
141
142/// Statistical summary of benchmark runs
143#[derive(Debug, Clone)]
144pub struct BenchmarkSummary {
145    /// Mean execution time
146    pub mean_time: Duration,
147    /// Standard deviation of execution time
148    pub std_time: Duration,
149    /// Minimum execution time
150    pub min_time: Duration,
151    /// Maximum execution time
152    pub max_time: Duration,
153    /// Mean memory usage
154    pub mean_memory: Option<usize>,
155    /// Success rate
156    pub success_rate: f64,
157    /// Confidence interval for mean time
158    pub confidence_interval: (Duration, Duration),
159}
160
161/// Benchmark metadata
162#[derive(Debug, Clone)]
163pub struct BenchmarkMetadata {
164    /// System information
165    pub system_info: SystemInfo,
166    /// Timestamp
167    pub timestamp: std::time::SystemTime,
168    /// Configuration used
169    pub config: BenchmarkConfig,
170}
171
172/// System information
173#[derive(Debug, Clone)]
174pub struct SystemInfo {
175    /// Number of CPU cores
176    pub cpu_cores: usize,
177    /// Available memory (bytes)
178    pub available_memory: usize,
179    /// Operating system
180    pub os: String,
181    /// Architecture
182    pub arch: String,
183}
184
185impl BenchmarkFramework {
186    /// Create new benchmark framework
187    pub fn new() -> Self {
188        Self {
189            benchmarks: HashMap::new(),
190            results: BenchmarkResults {
191                results: HashMap::new(),
192                summaries: HashMap::new(),
193                metadata: BenchmarkMetadata {
194                    system_info: SystemInfo::collect(),
195                    timestamp: std::time::SystemTime::now(),
196                    config: BenchmarkConfig::default(),
197                },
198            },
199            config: BenchmarkConfig::default(),
200        }
201    }
202
203    /// Set benchmark configuration
204    pub fn with_config(mut self, config: BenchmarkConfig) -> Self {
205        self.config = config.clone();
206        self.results.metadata.config = config;
207        self
208    }
209
210    /// Register a benchmark
211    pub fn register_benchmark(&mut self, name: impl Into<String>, benchmark: Box<dyn Benchmark>) {
212        self.benchmarks.insert(name.into(), benchmark);
213    }
214
215    /// Run all benchmarks
216    pub fn run_all_benchmarks(&mut self, backends: &[&Backend]) -> Result<&BenchmarkResults> {
217        // Collect benchmark names first to avoid borrow conflicts
218        let benchmark_names: Vec<String> = self.benchmarks.keys().cloned().collect();
219        for name in benchmark_names {
220            println!("Running benchmark: {}", name);
221
222            // Extract benchmark temporarily to avoid borrow conflicts
223            if let Some(mut benchmark) = self.benchmarks.remove(&name) {
224                self.run_benchmark(&name, benchmark.as_mut(), backends)?;
225                self.benchmarks.insert(name, benchmark);
226            }
227        }
228
229        self.compute_summaries()?;
230        Ok(&self.results)
231    }
232
233    /// Run specific benchmark
234    pub fn run_benchmark(
235        &mut self,
236        name: &str,
237        benchmark: &mut dyn Benchmark,
238        backends: &[&Backend],
239    ) -> Result<()> {
240        benchmark.setup()?;
241
242        for backend in backends {
243            let backend_name = format!("{}_{}", name, backend.name());
244            let mut runs = Vec::new();
245
246            // Warm-up runs
247            for _ in 0..self.config.warmup_runs {
248                let _ = benchmark.run(*backend);
249            }
250
251            // Actual benchmark runs
252            for run_idx in 0..self.config.repetitions {
253                let start_time = Instant::now();
254
255                let result = match benchmark.run(*backend) {
256                    Ok(mut result) => {
257                        result.execution_time = start_time.elapsed();
258                        result
259                    }
260                    Err(e) => BenchmarkRunResult {
261                        execution_time: start_time.elapsed(),
262                        memory_usage: None,
263                        metrics: HashMap::new(),
264                        result_value: None,
265                        success: false,
266                        error_message: Some(e.to_string()),
267                    },
268                };
269
270                runs.push(result);
271
272                // Check timeout
273                if start_time.elapsed().as_secs_f64() > self.config.max_time_per_benchmark {
274                    println!(
275                        "Benchmark {} timed out after {} runs",
276                        backend_name,
277                        run_idx + 1
278                    );
279                    break;
280                }
281            }
282
283            self.results.results.insert(backend_name, runs);
284        }
285
286        benchmark.cleanup()?;
287        Ok(())
288    }
289
290    /// Compute statistical summaries
291    fn compute_summaries(&mut self) -> Result<()> {
292        for (name, runs) in &self.results.results {
293            let summary = self.compute_summary(runs)?;
294            self.results.summaries.insert(name.clone(), summary);
295        }
296        Ok(())
297    }
298
299    /// Compute summary statistics for benchmark runs
300    fn compute_summary(&self, runs: &[BenchmarkRunResult]) -> Result<BenchmarkSummary> {
301        if runs.is_empty() {
302            return Err(MLError::InvalidConfiguration(
303                "No benchmark runs".to_string(),
304            ));
305        }
306
307        let successful_runs: Vec<_> = runs.iter().filter(|r| r.success).collect();
308        let success_rate = successful_runs.len() as f64 / runs.len() as f64;
309
310        if successful_runs.is_empty() {
311            return Ok(BenchmarkSummary {
312                mean_time: Duration::from_secs(0),
313                std_time: Duration::from_secs(0),
314                min_time: Duration::from_secs(0),
315                max_time: Duration::from_secs(0),
316                mean_memory: None,
317                success_rate,
318                confidence_interval: (Duration::from_secs(0), Duration::from_secs(0)),
319            });
320        }
321
322        let times: Vec<f64> = successful_runs
323            .iter()
324            .map(|r| r.execution_time.as_secs_f64())
325            .collect();
326
327        let mean_time_secs = times.iter().sum::<f64>() / times.len() as f64;
328        let variance = times
329            .iter()
330            .map(|t| (t - mean_time_secs).powi(2))
331            .sum::<f64>()
332            / times.len() as f64;
333        let std_time_secs = variance.sqrt();
334
335        let min_time_secs = times.iter().fold(f64::INFINITY, |a, &b| a.min(b));
336        let max_time_secs = times.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
337
338        // Compute confidence interval (assuming normal distribution)
339        let z_score = 1.96; // 95% confidence
340        let margin = z_score * std_time_secs / (times.len() as f64).sqrt();
341        let ci_lower = (mean_time_secs - margin).max(0.0);
342        let ci_upper = mean_time_secs + margin;
343
344        // Memory statistics
345        let memories: Vec<usize> = successful_runs
346            .iter()
347            .filter_map(|r| r.memory_usage)
348            .collect();
349        let mean_memory = if memories.is_empty() {
350            None
351        } else {
352            Some(memories.iter().sum::<usize>() / memories.len())
353        };
354
355        Ok(BenchmarkSummary {
356            mean_time: Duration::from_secs_f64(mean_time_secs),
357            std_time: Duration::from_secs_f64(std_time_secs),
358            min_time: Duration::from_secs_f64(min_time_secs),
359            max_time: Duration::from_secs_f64(max_time_secs),
360            mean_memory,
361            success_rate,
362            confidence_interval: (
363                Duration::from_secs_f64(ci_lower),
364                Duration::from_secs_f64(ci_upper),
365            ),
366        })
367    }
368
369    /// Generate benchmark report
370    pub fn generate_report(&self) -> BenchmarkReport {
371        BenchmarkReport::new(&self.results)
372    }
373}
374
375impl BenchmarkResults {
376    /// Get summaries
377    pub fn summaries(&self) -> &HashMap<String, BenchmarkSummary> {
378        &self.summaries
379    }
380
381    /// Get results
382    pub fn results(&self) -> &HashMap<String, Vec<BenchmarkRunResult>> {
383        &self.results
384    }
385
386    /// Get metadata
387    pub fn metadata(&self) -> &BenchmarkMetadata {
388        &self.metadata
389    }
390}
391
392/// System information collector
393impl SystemInfo {
394    fn collect() -> Self {
395        Self {
396            cpu_cores: num_cpus::get(),
397            available_memory: Self::get_available_memory(),
398            os: std::env::consts::OS.to_string(),
399            arch: std::env::consts::ARCH.to_string(),
400        }
401    }
402
403    fn get_available_memory() -> usize {
404        // Simplified - would use proper system calls
405        8 * 1024 * 1024 * 1024 // 8 GB default
406    }
407}
408
409/// Quantum ML algorithm benchmarks
410pub mod algorithm_benchmarks {
411    use super::*;
412    use crate::qnn::QuantumNeuralNetwork;
413    use crate::variational::VariationalCircuit;
414
415    /// VQE benchmark
416    pub struct VQEBenchmark {
417        num_qubits: usize,
418        num_parameters: usize,
419        circuit: Option<VariationalCircuit>,
420    }
421
422    impl VQEBenchmark {
423        pub fn new(num_qubits: usize, num_parameters: usize) -> Self {
424            Self {
425                num_qubits,
426                num_parameters,
427                circuit: None,
428            }
429        }
430    }
431
432    impl Benchmark for VQEBenchmark {
433        fn name(&self) -> &str {
434            "VQE"
435        }
436
437        fn description(&self) -> &str {
438            "Variational Quantum Eigensolver benchmark"
439        }
440
441        fn setup(&mut self) -> Result<()> {
442            // Setup VQE circuit
443            self.circuit = Some(VariationalCircuit::new(
444                self.num_qubits,
445                2 * self.num_qubits, // Default number of parameters
446                2,                   // Default number of layers
447                crate::variational::AnsatzType::HardwareEfficient,
448            )?);
449            Ok(())
450        }
451
452        fn run(&mut self, backend: &Backend) -> Result<BenchmarkRunResult> {
453            let start = Instant::now();
454            let parameters: Array1<f64> = Array1::zeros(self.num_parameters);
455
456            // Simulate VQE optimization step
457            let mut metrics = HashMap::new();
458            metrics.insert("num_qubits".to_string(), self.num_qubits as f64);
459            metrics.insert("num_parameters".to_string(), self.num_parameters as f64);
460
461            // Would run actual VQE here
462            let result_value = Some(fastrand::f64() - 0.5); // Placeholder energy
463
464            Ok(BenchmarkRunResult {
465                execution_time: start.elapsed(),
466                memory_usage: Some(self.estimate_memory_usage()),
467                metrics,
468                result_value,
469                success: true,
470                error_message: None,
471            })
472        }
473
474        fn cleanup(&mut self) -> Result<()> {
475            self.circuit = None;
476            Ok(())
477        }
478
479        fn expected_scaling(&self) -> ScalingType {
480            ScalingType::Exponential
481        }
482
483        fn category(&self) -> BenchmarkCategory {
484            BenchmarkCategory::Algorithm
485        }
486    }
487
488    impl VQEBenchmark {
489        fn estimate_memory_usage(&self) -> usize {
490            // Rough estimate: 2^n * 16 bytes for statevector
491            2_usize.pow(self.num_qubits as u32) * 16
492        }
493    }
494
495    /// QAOA benchmark
496    pub struct QAOABenchmark {
497        num_qubits: usize,
498        num_layers: usize,
499        problem_size: usize,
500    }
501
502    impl QAOABenchmark {
503        pub fn new(num_qubits: usize, num_layers: usize, problem_size: usize) -> Self {
504            Self {
505                num_qubits,
506                num_layers,
507                problem_size,
508            }
509        }
510    }
511
512    impl Benchmark for QAOABenchmark {
513        fn name(&self) -> &str {
514            "QAOA"
515        }
516
517        fn description(&self) -> &str {
518            "Quantum Approximate Optimization Algorithm benchmark"
519        }
520
521        fn setup(&mut self) -> Result<()> {
522            Ok(())
523        }
524
525        fn run(&mut self, _backend: &Backend) -> Result<BenchmarkRunResult> {
526            let start = Instant::now();
527
528            let mut metrics = HashMap::new();
529            metrics.insert("num_qubits".to_string(), self.num_qubits as f64);
530            metrics.insert("num_layers".to_string(), self.num_layers as f64);
531            metrics.insert("problem_size".to_string(), self.problem_size as f64);
532
533            // Simulate QAOA execution
534            let result_value = Some(fastrand::f64()); // Placeholder approximation ratio
535
536            Ok(BenchmarkRunResult {
537                execution_time: start.elapsed(),
538                memory_usage: Some(2_usize.pow(self.num_qubits as u32) * 16),
539                metrics,
540                result_value,
541                success: true,
542                error_message: None,
543            })
544        }
545
546        fn cleanup(&mut self) -> Result<()> {
547            Ok(())
548        }
549
550        fn expected_scaling(&self) -> ScalingType {
551            ScalingType::Polynomial(2.0)
552        }
553
554        fn category(&self) -> BenchmarkCategory {
555            BenchmarkCategory::Algorithm
556        }
557    }
558
559    /// Quantum Neural Network benchmark
560    pub struct QNNBenchmark {
561        num_qubits: usize,
562        num_layers: usize,
563        training_samples: usize,
564    }
565
566    impl QNNBenchmark {
567        pub fn new(num_qubits: usize, num_layers: usize, training_samples: usize) -> Self {
568            Self {
569                num_qubits,
570                num_layers,
571                training_samples,
572            }
573        }
574    }
575
576    impl Benchmark for QNNBenchmark {
577        fn name(&self) -> &str {
578            "QNN"
579        }
580
581        fn description(&self) -> &str {
582            "Quantum Neural Network training benchmark"
583        }
584
585        fn setup(&mut self) -> Result<()> {
586            Ok(())
587        }
588
589        fn run(&mut self, _backend: &Backend) -> Result<BenchmarkRunResult> {
590            let start = Instant::now();
591
592            let mut metrics = HashMap::new();
593            metrics.insert("num_qubits".to_string(), self.num_qubits as f64);
594            metrics.insert("num_layers".to_string(), self.num_layers as f64);
595            metrics.insert("training_samples".to_string(), self.training_samples as f64);
596
597            // Simulate QNN training
598            let result_value = Some(1.0 - fastrand::f64() * 0.3); // Placeholder accuracy
599
600            Ok(BenchmarkRunResult {
601                execution_time: start.elapsed(),
602                memory_usage: Some(2_usize.pow(self.num_qubits as u32) * 16),
603                metrics,
604                result_value,
605                success: true,
606                error_message: None,
607            })
608        }
609
610        fn cleanup(&mut self) -> Result<()> {
611            Ok(())
612        }
613
614        fn expected_scaling(&self) -> ScalingType {
615            ScalingType::Polynomial(3.0)
616        }
617
618        fn category(&self) -> BenchmarkCategory {
619            BenchmarkCategory::Algorithm
620        }
621    }
622}
623
624/// Benchmark report generation
625#[derive(Debug, Clone)]
626pub struct BenchmarkReport {
627    /// Summary statistics
628    summaries: HashMap<String, BenchmarkSummary>,
629    /// Comparative analysis
630    comparisons: Vec<BenchmarkComparison>,
631    /// Scaling analysis
632    scaling_analysis: HashMap<String, ScalingAnalysis>,
633    /// Recommendations
634    recommendations: Vec<String>,
635}
636
637/// Benchmark comparison
638#[derive(Debug, Clone)]
639pub struct BenchmarkComparison {
640    /// Benchmark names being compared
641    benchmarks: Vec<String>,
642    /// Comparison metrics
643    metrics: HashMap<String, f64>,
644    /// Winner (if applicable)
645    winner: Option<String>,
646}
647
648/// Scaling analysis result
649#[derive(Debug, Clone)]
650pub struct ScalingAnalysis {
651    /// Observed scaling type
652    observed_scaling: ScalingType,
653    /// Expected scaling type
654    expected_scaling: ScalingType,
655    /// Scaling coefficient
656    scaling_coefficient: f64,
657    /// R-squared for fit
658    r_squared: f64,
659}
660
661impl BenchmarkReport {
662    /// Create new benchmark report
663    pub fn new(results: &BenchmarkResults) -> Self {
664        let mut report = Self {
665            summaries: results.summaries.clone(),
666            comparisons: Vec::new(),
667            scaling_analysis: HashMap::new(),
668            recommendations: Vec::new(),
669        };
670
671        report.analyze_comparisons();
672        report.analyze_scaling();
673        report.generate_recommendations();
674
675        report
676    }
677
678    /// Analyze benchmark comparisons
679    fn analyze_comparisons(&mut self) {
680        // Group benchmarks by algorithm type and compare across backends
681        let mut algorithm_groups: HashMap<String, Vec<String>> = HashMap::new();
682
683        for benchmark_name in self.summaries.keys() {
684            let algorithm = benchmark_name.split('_').next().unwrap_or(benchmark_name);
685            algorithm_groups
686                .entry(algorithm.to_string())
687                .or_insert_with(Vec::new)
688                .push(benchmark_name.clone());
689        }
690
691        for (algorithm, benchmarks) in algorithm_groups {
692            if benchmarks.len() > 1 {
693                let comparison = self.compare_benchmarks(&benchmarks);
694                self.comparisons.push(comparison);
695            }
696        }
697    }
698
699    /// Compare benchmarks
700    fn compare_benchmarks(&self, benchmark_names: &[String]) -> BenchmarkComparison {
701        let mut metrics = HashMap::new();
702        let mut winner = None;
703        let mut best_time = Duration::from_secs(u64::MAX);
704
705        for name in benchmark_names {
706            if let Some(summary) = self.summaries.get(name) {
707                metrics.insert(
708                    format!("{}_mean_time", name),
709                    summary.mean_time.as_secs_f64(),
710                );
711                metrics.insert(format!("{}_success_rate", name), summary.success_rate);
712
713                if summary.mean_time < best_time && summary.success_rate > 0.8 {
714                    best_time = summary.mean_time;
715                    winner = Some(name.clone());
716                }
717            }
718        }
719
720        BenchmarkComparison {
721            benchmarks: benchmark_names.to_vec(),
722            metrics,
723            winner,
724        }
725    }
726
727    /// Analyze scaling behavior
728    fn analyze_scaling(&mut self) {
729        // Placeholder - would implement actual scaling analysis
730        for benchmark_name in self.summaries.keys() {
731            let analysis = ScalingAnalysis {
732                observed_scaling: ScalingType::Exponential,
733                expected_scaling: ScalingType::Exponential,
734                scaling_coefficient: 2.0,
735                r_squared: 0.95,
736            };
737            self.scaling_analysis
738                .insert(benchmark_name.clone(), analysis);
739        }
740    }
741
742    /// Generate recommendations
743    fn generate_recommendations(&mut self) {
744        // Analyze results and generate recommendations
745        for comparison in &self.comparisons {
746            if let Some(ref winner) = comparison.winner {
747                self.recommendations.push(format!(
748                    "For {} algorithms, {} backend shows best performance",
749                    comparison.benchmarks[0].split('_').next().unwrap_or(""),
750                    winner.split('_').last().unwrap_or("")
751                ));
752            }
753        }
754
755        // Add general recommendations
756        self.recommendations
757            .push("Use statevector backend for small circuits (<20 qubits)".to_string());
758        self.recommendations
759            .push("Use MPS backend for large circuits with limited entanglement".to_string());
760        self.recommendations
761            .push("Consider GPU acceleration for repeated circuit evaluations".to_string());
762    }
763
764    /// Export report to string
765    pub fn to_string(&self) -> String {
766        let mut report = String::new();
767
768        report.push_str("# Quantum ML Benchmark Report\n\n");
769
770        // Summary statistics
771        report.push_str("## Summary Statistics\n\n");
772        for (name, summary) in &self.summaries {
773            report.push_str(&format!(
774                "### {}\n- Mean time: {:.3}s\n- Success rate: {:.1}%\n- Memory: {}\n\n",
775                name,
776                summary.mean_time.as_secs_f64(),
777                summary.success_rate * 100.0,
778                summary
779                    .mean_memory
780                    .map(|m| format!("{:.1} MB", m as f64 / 1024.0 / 1024.0))
781                    .unwrap_or_else(|| "N/A".to_string())
782            ));
783        }
784
785        // Comparisons
786        report.push_str("## Benchmark Comparisons\n\n");
787        for comparison in &self.comparisons {
788            report.push_str(&format!(
789                "### Comparing: {}\n",
790                comparison.benchmarks.join(", ")
791            ));
792            if let Some(ref winner) = comparison.winner {
793                report.push_str(&format!("**Winner: {}**\n\n", winner));
794            }
795        }
796
797        // Recommendations
798        report.push_str("## Recommendations\n\n");
799        for (i, rec) in self.recommendations.iter().enumerate() {
800            report.push_str(&format!("{}. {}\n", i + 1, rec));
801        }
802
803        report
804    }
805}
806
807/// Utility functions for benchmark creation
808pub mod benchmark_utils {
809    use super::*;
810    use crate::simulator_backends::{MPSBackend, StatevectorBackend};
811
812    /// Create standard benchmark suite
813    pub fn create_standard_suite() -> BenchmarkFramework {
814        let mut framework = BenchmarkFramework::new();
815
816        // Add VQE benchmarks
817        framework.register_benchmark(
818            "vqe_4q",
819            Box::new(algorithm_benchmarks::VQEBenchmark::new(4, 8)),
820        );
821        framework.register_benchmark(
822            "vqe_8q",
823            Box::new(algorithm_benchmarks::VQEBenchmark::new(8, 16)),
824        );
825        framework.register_benchmark(
826            "vqe_12q",
827            Box::new(algorithm_benchmarks::VQEBenchmark::new(12, 24)),
828        );
829
830        // Add QAOA benchmarks
831        framework.register_benchmark(
832            "qaoa_6q",
833            Box::new(algorithm_benchmarks::QAOABenchmark::new(6, 3, 10)),
834        );
835        framework.register_benchmark(
836            "qaoa_10q",
837            Box::new(algorithm_benchmarks::QAOABenchmark::new(10, 3, 20)),
838        );
839
840        // Add QNN benchmarks
841        framework.register_benchmark(
842            "qnn_4q",
843            Box::new(algorithm_benchmarks::QNNBenchmark::new(4, 2, 100)),
844        );
845        framework.register_benchmark(
846            "qnn_8q",
847            Box::new(algorithm_benchmarks::QNNBenchmark::new(8, 3, 100)),
848        );
849
850        framework
851    }
852
853    /// Create backends for benchmarking
854    pub fn create_benchmark_backends() -> Vec<Backend> {
855        let mut backends: Vec<Backend> = Vec::new();
856
857        // Statevector backend
858        backends.push(Backend::Statevector(StatevectorBackend::new(15)));
859
860        // MPS backend
861        backends.push(Backend::MPS(MPSBackend::new(64, 50)));
862
863        // GPU backend if available
864        #[cfg(feature = "gpu")]
865        {
866            use crate::simulator_backends::GPUBackend;
867            if let Ok(gpu_backend) = GPUBackend::new(0, 20) {
868                backends.push(Backend::GPU(gpu_backend));
869            }
870        }
871
872        backends
873    }
874}
875
876#[cfg(test)]
877mod tests {
878    use super::*;
879    use crate::simulator_backends::StatevectorBackend;
880
881    #[test]
882    fn test_benchmark_framework() {
883        let mut framework = BenchmarkFramework::new();
884        framework.register_benchmark(
885            "test",
886            Box::new(algorithm_benchmarks::VQEBenchmark::new(4, 8)),
887        );
888
889        assert_eq!(framework.benchmarks.len(), 1);
890    }
891
892    #[test]
893    fn test_benchmark_config() {
894        let config = BenchmarkConfig {
895            repetitions: 5,
896            warmup_runs: 1,
897            ..Default::default()
898        };
899
900        assert_eq!(config.repetitions, 5);
901        assert_eq!(config.warmup_runs, 1);
902    }
903
904    #[test]
905    fn test_vqe_benchmark() {
906        let mut benchmark = algorithm_benchmarks::VQEBenchmark::new(4, 8);
907        let backend = StatevectorBackend::new(10);
908
909        let setup_result = benchmark.setup();
910        assert!(setup_result.is_ok());
911
912        let run_result = benchmark.run(&Backend::Statevector(backend));
913        assert!(run_result.is_ok());
914
915        let cleanup_result = benchmark.cleanup();
916        assert!(cleanup_result.is_ok());
917    }
918
919    #[test]
920    fn test_system_info() {
921        let info = SystemInfo::collect();
922        assert!(info.cpu_cores > 0);
923        assert!(info.available_memory > 0);
924    }
925}