1use quantrs2_circuit::builder::{Circuit, Simulator};
7use quantrs2_core::{error::QuantRS2Result, qubit::QubitId};
8use scirs2_core::random::{Rng, SeedableRng};
9use scirs2_core::random::ChaCha8Rng;
10use std::time::{Duration, Instant};
11
12use crate::optimized_simulator::OptimizedSimulator;
13use crate::optimized_simulator_chunked::OptimizedSimulatorChunked;
14use crate::optimized_simulator_simple::OptimizedSimulatorSimple;
15use crate::statevector::StateVectorSimulator;
16
17#[derive(Debug, Clone)]
19pub struct BenchmarkResult {
20 pub simulator_name: String,
22 pub num_qubits: usize,
24 pub num_gates: usize,
26 pub duration: Duration,
28 pub notes: Option<String>,
30 pub peak_memory: Option<usize>,
32}
33
34impl BenchmarkResult {
35 pub fn new(
37 simulator_name: &str,
38 num_qubits: usize,
39 num_gates: usize,
40 duration: Duration,
41 notes: Option<String>,
42 peak_memory: Option<usize>,
43 ) -> Self {
44 Self {
45 simulator_name: simulator_name.to_string(),
46 num_qubits,
47 num_gates,
48 duration,
49 notes,
50 peak_memory,
51 }
52 }
53
54 pub fn format(&self) -> String {
56 let duration_ms = self.duration.as_millis();
57 let rate = if duration_ms > 0 {
58 self.num_gates as f64 / (duration_ms as f64 / 1000.0)
59 } else {
60 f64::INFINITY
61 };
62
63 let notes = if let Some(ref notes) = self.notes {
64 format!(" ({})", notes)
65 } else {
66 String::new()
67 };
68
69 let memory_str = if let Some(mem) = self.peak_memory {
70 format!(", Memory: {:.2} MB", mem as f64 / (1024.0 * 1024.0))
71 } else {
72 String::new()
73 };
74
75 format!(
76 "Simulator: {}{}\n Qubits: {}\n Gates: {}\n Time: {} ms\n Rate: {:.2} gates/s{}",
77 self.simulator_name,
78 notes,
79 self.num_qubits,
80 self.num_gates,
81 duration_ms,
82 rate,
83 memory_str
84 )
85 }
86}
87
88pub fn run_benchmark<S, const N: usize>(
90 name: &str,
91 simulator: &S,
92 circuit: &Circuit<N>,
93 notes: Option<String>,
94) -> QuantRS2Result<BenchmarkResult>
95where
96 S: Simulator<N>,
97{
98 let num_qubits = N;
99 let num_gates = circuit.gates().len();
100
101 let start = Instant::now();
102 let _result = simulator.run(circuit)?;
103 let duration = start.elapsed();
104
105 Ok(BenchmarkResult::new(
106 name, num_qubits, num_gates, duration, notes, None,
107 ))
108}
109
110pub fn compare_simulators<const N: usize>(circuit: &Circuit<N>) -> Vec<BenchmarkResult> {
112 let mut results = Vec::new();
113
114 if N <= 24 {
116 let standard_sim = StateVectorSimulator::new();
118 if let Ok(result) = run_benchmark("Standard Simulator", &standard_sim, circuit, None) {
119 results.push(result);
120 }
121 }
122
123 let simple_opt_sim = OptimizedSimulatorSimple::new();
125 if let Ok(result) = run_benchmark("Simple Optimized", &simple_opt_sim, circuit, None) {
126 results.push(result);
127 }
128
129 let chunked_sim = OptimizedSimulatorChunked::new();
131 if let Ok(result) = run_benchmark("Chunked Optimized", &chunked_sim, circuit, None) {
132 results.push(result);
133 }
134
135 let optimized_sim = OptimizedSimulator::new();
137 if let Ok(result) = run_benchmark(
138 "Full Optimized",
139 &optimized_sim,
140 circuit,
141 Some("Auto-selection".to_string()),
142 ) {
143 results.push(result);
144 }
145
146 if N <= 20 {
148 let memory_efficient_sim = OptimizedSimulator::memory_efficient();
149 if let Ok(result) = run_benchmark(
150 "Memory Efficient",
151 &memory_efficient_sim,
152 circuit,
153 Some("Low memory".to_string()),
154 ) {
155 results.push(result);
156 }
157 }
158
159 results
160}
161
162pub fn generate_benchmark_circuit<const N: usize>(
164 num_gates: usize,
165 two_qubit_ratio: f64,
166) -> Circuit<N> {
167 let mut circuit = Circuit::new();
168 let mut rng = ChaCha8Rng::seed_from_u64(42); for _ in 0..num_gates {
171 let is_two_qubit = rng.random::<f64>() < two_qubit_ratio;
173
174 if is_two_qubit && N > 1 {
175 let qubit1 = QubitId::new(rng.random_range(0..N as u32));
177 let mut qubit2 = QubitId::new(rng.random_range(0..N as u32));
178 while qubit2 == qubit1 {
179 qubit2 = QubitId::new(rng.random_range(0..N as u32));
180 }
181
182 let gate_type = rng.random_range(0..3);
184 match gate_type {
185 0 => {
186 let _ = circuit.cnot(qubit1, qubit2);
187 }
188 1 => {
189 let _ = circuit.cz(qubit1, qubit2);
190 }
191 _ => {
192 let _ = circuit.swap(qubit1, qubit2);
193 }
194 }
195 } else {
196 let qubit = QubitId::new(rng.random_range(0..N as u32));
198
199 let gate_type = rng.random_range(0..7);
201 match gate_type {
202 0 => {
203 let _ = circuit.h(qubit);
204 }
205 1 => {
206 let _ = circuit.x(qubit);
207 }
208 2 => {
209 let _ = circuit.y(qubit);
210 }
211 3 => {
212 let _ = circuit.z(qubit);
213 }
214 4 => {
215 let _ = circuit.s(qubit);
216 }
217 5 => {
218 let _ = circuit.t(qubit);
219 }
220 _ => {
221 let angle = rng.random_range(0.0..std::f64::consts::TAU);
223 let rotation_type = rng.random_range(0..3);
224 match rotation_type {
225 0 => {
226 let _ = circuit.rx(qubit, angle);
227 }
228 1 => {
229 let _ = circuit.ry(qubit, angle);
230 }
231 _ => {
232 let _ = circuit.rz(qubit, angle);
233 }
234 }
235 }
236 }
237 }
238 }
239
240 circuit
241}
242
243pub fn run_benchmark_suite() {
245 println!("=== Quantrs Simulator Benchmark Suite ===");
246 println!("Testing various circuit sizes with different simulator implementations");
247 println!();
248
249 benchmark_circuit_size::<16>("Small", 16, 100, 0.3);
251
252 benchmark_circuit_size::<20>("Medium", 20, 50, 0.3);
254
255 benchmark_circuit_size::<25>("Large", 25, 20, 0.2);
257
258 benchmark_large_circuit::<28>("Very Large", 28, 10, 0.1);
260}
261
262fn benchmark_circuit_size<const N: usize>(
264 size_name: &str,
265 max_qubits: usize,
266 gates_per_qubit: usize,
267 two_qubit_ratio: f64,
268) {
269 println!(
270 "\n=== {} Circuit Tests (up to {} qubits) ===",
271 size_name, max_qubits
272 );
273
274 if N < max_qubits {
276 println!("Cannot benchmark this size - const generic N is too small");
277 return;
278 }
279
280 for qubits in [
282 max_qubits / 4,
283 max_qubits / 2,
284 (3 * max_qubits) / 4,
285 max_qubits,
286 ] {
287 let num_gates = qubits * gates_per_qubit;
288 println!("\nCircuit with {} qubits and {} gates:", qubits, num_gates);
289
290 let circuit = generate_benchmark_circuit::<N>(num_gates, two_qubit_ratio);
292
293 let results = compare_simulators(&circuit);
295
296 for result in &results {
298 println!("{}\n", result.format());
299 }
300 }
301}
302
303fn benchmark_large_circuit<const N: usize>(
305 size_name: &str,
306 max_qubits: usize,
307 gates_per_qubit: usize,
308 two_qubit_ratio: f64,
309) {
310 println!(
311 "\n=== {} Circuit Tests ({} qubits) ===",
312 size_name, max_qubits
313 );
314
315 if N < max_qubits {
317 println!("Cannot benchmark this size - const generic N is too small");
318 return;
319 }
320
321 let num_gates = max_qubits * gates_per_qubit;
322 println!(
323 "\nCircuit with {} qubits and {} gates:",
324 max_qubits, num_gates
325 );
326
327 let circuit = generate_benchmark_circuit::<N>(num_gates, two_qubit_ratio);
329
330 let mut results = Vec::new();
332
333 let chunked_sim = OptimizedSimulatorChunked::new();
335 if let Ok(result) = run_benchmark("Chunked Optimized", &chunked_sim, &circuit, None) {
336 results.push(result);
337 }
338
339 let optimized_sim = OptimizedSimulator::new();
341 if let Ok(result) = run_benchmark(
342 "Full Optimized",
343 &optimized_sim,
344 &circuit,
345 Some("Auto-selection".to_string()),
346 ) {
347 results.push(result);
348 }
349
350 for result in &results {
352 println!("{}\n", result.format());
353 }
354}
355
356#[cfg(test)]
357mod tests {
358 use super::*;
359
360 #[test]
361 #[ignore] fn benchmark_small_circuit() {
363 const QUBITS: usize = 16;
364 let circuit = generate_benchmark_circuit::<QUBITS>(100, 0.3);
365
366 let results = compare_simulators(&circuit);
367
368 for result in &results {
369 println!("{}\n", result.format());
370 }
371 }
372
373 #[test]
374 #[ignore] fn benchmark_medium_circuit() {
376 const QUBITS: usize = 20;
377 let circuit = generate_benchmark_circuit::<QUBITS>(50, 0.3);
378
379 let results = compare_simulators(&circuit);
380
381 for result in &results {
382 println!("{}\n", result.format());
383 }
384 }
385
386 #[test]
387 #[ignore] fn benchmark_large_circuit() {
389 const QUBITS: usize = 25;
390 let circuit = generate_benchmark_circuit::<QUBITS>(20, 0.2);
391
392 let mut results = Vec::new();
394
395 let chunked_sim = OptimizedSimulatorChunked::new();
397 if let Ok(result) = run_benchmark("Chunked Optimized", &chunked_sim, &circuit, None) {
398 results.push(result);
399 }
400
401 let optimized_sim = OptimizedSimulator::new();
402 if let Ok(result) = run_benchmark(
403 "Full Optimized",
404 &optimized_sim,
405 &circuit,
406 Some("Auto-selection".to_string()),
407 ) {
408 results.push(result);
409 }
410
411 for result in &results {
412 println!("{}\n", result.format());
413 }
414 }
415
416 #[test]
417 #[ignore] fn run_full_benchmark_suite() {
419 run_benchmark_suite();
420 }
421}