quantum_nas/
quantum_nas.rs

1//! Quantum Neural Architecture Search Example
2//!
3//! This example demonstrates various quantum neural architecture search algorithms
4//! including evolutionary search, reinforcement learning, random search,
5//! Bayesian optimization, and DARTS.
6
7use quantrs2_ml::prelude::*;
8use quantrs2_ml::qnn::QNNLayerType;
9use scirs2_core::ndarray::{Array1, Array2};
10use scirs2_core::random::prelude::*;
11
12fn main() -> Result<()> {
13    println!("=== Quantum Neural Architecture Search Demo ===\n");
14
15    // Step 1: Evolutionary algorithm search
16    println!("1. Evolutionary Algorithm Search...");
17    evolutionary_search_demo()?;
18
19    // Step 2: Random search baseline
20    println!("\n2. Random Search Baseline...");
21    random_search_demo()?;
22
23    // Step 3: Reinforcement learning search
24    println!("\n3. Reinforcement Learning Search...");
25    rl_search_demo()?;
26
27    // Step 4: Bayesian optimization
28    println!("\n4. Bayesian Optimization Search...");
29    bayesian_search_demo()?;
30
31    // Step 5: DARTS (Differentiable Architecture Search)
32    println!("\n5. DARTS (Differentiable Architecture Search)...");
33    darts_demo()?;
34
35    // Step 6: Multi-objective optimization
36    println!("\n6. Multi-Objective Optimization...");
37    multi_objective_demo()?;
38
39    // Step 7: Architecture analysis
40    println!("\n7. Architecture Analysis...");
41    architecture_analysis_demo()?;
42
43    println!("\n=== Quantum NAS Demo Complete ===");
44
45    Ok(())
46}
47
48/// Evolutionary algorithm search demonstration
49fn evolutionary_search_demo() -> Result<()> {
50    // Create search space
51    let search_space = create_default_search_space();
52
53    // Configure evolutionary strategy
54    let strategy = SearchStrategy::Evolutionary {
55        population_size: 20,
56        mutation_rate: 0.2,
57        crossover_rate: 0.7,
58        elitism_ratio: 0.1,
59    };
60
61    let mut nas = QuantumNAS::new(strategy, search_space);
62
63    println!("   Created evolutionary NAS:");
64    println!("   - Population size: 20");
65    println!("   - Mutation rate: 0.2");
66    println!("   - Crossover rate: 0.7");
67    println!("   - Elitism ratio: 0.1");
68
69    // Set evaluation data (synthetic for demo)
70    let eval_data = Array2::from_shape_fn((100, 4), |(i, j)| (i as f64 + j as f64) / 50.0);
71    let eval_labels = Array1::from_shape_fn(100, |i| i % 2);
72    nas.set_evaluation_data(eval_data, eval_labels);
73
74    // Run search
75    println!("\n   Running evolutionary search for 10 generations...");
76    let best_architectures = nas.search(10)?;
77
78    println!("   Search complete!");
79    println!(
80        "   - Best architectures found: {}",
81        best_architectures.len()
82    );
83
84    if let Some(best) = best_architectures.first() {
85        println!("   - Best architecture: {best}");
86        println!("   - Circuit depth: {}", best.metrics.circuit_depth);
87        println!("   - Parameter count: {}", best.metrics.parameter_count);
88
89        if let Some(expressivity) = best.properties.expressivity {
90            println!("   - Expressivity: {expressivity:.3}");
91        }
92    }
93
94    // Show search summary
95    let summary = nas.get_search_summary();
96    println!(
97        "   - Total architectures evaluated: {}",
98        summary.total_architectures_evaluated
99    );
100    println!("   - Pareto front size: {}", summary.pareto_front_size);
101
102    Ok(())
103}
104
105/// Random search baseline demonstration
106fn random_search_demo() -> Result<()> {
107    let search_space = create_default_search_space();
108    let strategy = SearchStrategy::Random { num_samples: 50 };
109
110    let mut nas = QuantumNAS::new(strategy, search_space);
111
112    println!("   Created random search NAS:");
113    println!("   - Number of samples: 50");
114
115    // Generate synthetic evaluation data
116    let eval_data = Array2::from_shape_fn((80, 4), |(i, j)| {
117        0.5f64.mul_add((i as f64).sin(), 0.3 * (j as f64).cos())
118    });
119    let eval_labels = Array1::from_shape_fn(80, |i| usize::from(i % 3 != 0));
120    nas.set_evaluation_data(eval_data, eval_labels);
121
122    println!("\n   Running random search...");
123    let best_architectures = nas.search(50)?;
124
125    println!("   Random search complete!");
126    if let Some(best) = best_architectures.first() {
127        println!("   - Best random architecture: {best}");
128        if let Some(accuracy) = best.metrics.accuracy {
129            println!("   - Accuracy: {accuracy:.3}");
130        }
131    }
132
133    Ok(())
134}
135
136/// Reinforcement learning search demonstration
137fn rl_search_demo() -> Result<()> {
138    let search_space = create_custom_search_space();
139
140    let strategy = SearchStrategy::ReinforcementLearning {
141        agent_type: RLAgentType::PolicyGradient,
142        exploration_rate: 0.3,
143        learning_rate: 0.01,
144    };
145
146    let mut nas = QuantumNAS::new(strategy, search_space);
147
148    println!("   Created RL-based NAS:");
149    println!("   - Agent type: Policy Gradient");
150    println!("   - Exploration rate: 0.3");
151    println!("   - Learning rate: 0.01");
152
153    println!("\n   Running RL search for 100 episodes...");
154    let best_architectures = nas.search(100)?;
155
156    println!("   RL search complete!");
157    println!("   - Architectures found: {}", best_architectures.len());
158
159    if let Some(best) = best_architectures.first() {
160        println!("   - Best RL architecture: {best}");
161        if let Some(entanglement) = best.properties.entanglement_capability {
162            println!("   - Entanglement capability: {entanglement:.3}");
163        }
164    }
165
166    Ok(())
167}
168
169/// Bayesian optimization search demonstration
170fn bayesian_search_demo() -> Result<()> {
171    let search_space = create_default_search_space();
172
173    let strategy = SearchStrategy::BayesianOptimization {
174        acquisition_function: AcquisitionFunction::ExpectedImprovement,
175        num_initial_points: 10,
176    };
177
178    let mut nas = QuantumNAS::new(strategy, search_space);
179
180    println!("   Created Bayesian optimization NAS:");
181    println!("   - Acquisition function: Expected Improvement");
182    println!("   - Initial random points: 10");
183
184    // Set up evaluation data
185    let eval_data = generate_quantum_data(60, 4);
186    let eval_labels = Array1::from_shape_fn(60, |i| i % 3);
187    nas.set_evaluation_data(eval_data, eval_labels);
188
189    println!("\n   Running Bayesian optimization for 30 iterations...");
190    let best_architectures = nas.search(30)?;
191
192    println!("   Bayesian optimization complete!");
193    if let Some(best) = best_architectures.first() {
194        println!("   - Best Bayesian architecture: {best}");
195        if let Some(hardware_eff) = best.metrics.hardware_efficiency {
196            println!("   - Hardware efficiency: {hardware_eff:.3}");
197        }
198    }
199
200    Ok(())
201}
202
203/// DARTS demonstration
204fn darts_demo() -> Result<()> {
205    let search_space = create_darts_search_space();
206
207    let strategy = SearchStrategy::DARTS {
208        learning_rate: 0.01,
209        weight_decay: 1e-4,
210    };
211
212    let mut nas = QuantumNAS::new(strategy, search_space);
213
214    println!("   Created DARTS NAS:");
215    println!("   - Learning rate: 0.01");
216    println!("   - Weight decay: 1e-4");
217    println!("   - Differentiable architecture search");
218
219    println!("\n   Running DARTS for 200 epochs...");
220    let best_architectures = nas.search(200)?;
221
222    println!("   DARTS search complete!");
223    if let Some(best) = best_architectures.first() {
224        println!("   - DARTS architecture: {best}");
225        println!("   - Learned through gradient-based optimization");
226
227        if let Some(gradient_var) = best.properties.gradient_variance {
228            println!("   - Gradient variance: {gradient_var:.3}");
229        }
230    }
231
232    Ok(())
233}
234
235/// Multi-objective optimization demonstration
236fn multi_objective_demo() -> Result<()> {
237    let search_space = create_default_search_space();
238
239    let strategy = SearchStrategy::Evolutionary {
240        population_size: 30,
241        mutation_rate: 0.15,
242        crossover_rate: 0.8,
243        elitism_ratio: 0.2,
244    };
245
246    let mut nas = QuantumNAS::new(strategy, search_space);
247
248    println!("   Multi-objective optimization:");
249    println!("   - Optimizing accuracy vs. complexity");
250    println!("   - Finding Pareto-optimal architectures");
251
252    // Run search
253    nas.search(15)?;
254
255    // Analyze Pareto front
256    let pareto_front = nas.get_pareto_front();
257    println!("   Pareto front analysis:");
258    println!("   - Pareto-optimal architectures: {}", pareto_front.len());
259
260    for (i, arch) in pareto_front.iter().take(3).enumerate() {
261        println!(
262            "   Architecture {}: {} params, {:.3} accuracy",
263            i + 1,
264            arch.metrics.parameter_count,
265            arch.metrics.accuracy.unwrap_or(0.0)
266        );
267    }
268
269    Ok(())
270}
271
272/// Architecture analysis demonstration
273fn architecture_analysis_demo() -> Result<()> {
274    println!("   Analyzing quantum circuit architectures...");
275
276    // Create sample architectures with different properties
277    let architectures = create_sample_architectures();
278
279    println!("\n   Architecture comparison:");
280    for (i, arch) in architectures.iter().enumerate() {
281        println!("   Architecture {}:", i + 1);
282        println!("     - Layers: {}", arch.layers.len());
283        println!("     - Qubits: {}", arch.num_qubits);
284        println!("     - Circuit depth: {}", arch.metrics.circuit_depth);
285
286        if let Some(expressivity) = arch.properties.expressivity {
287            println!("     - Expressivity: {expressivity:.3}");
288        }
289
290        if let Some(entanglement) = arch.properties.entanglement_capability {
291            println!("     - Entanglement: {entanglement:.3}");
292        }
293
294        if let Some(barren_plateau) = arch.properties.barren_plateau_score {
295            println!("     - Barren plateau risk: {barren_plateau:.3}");
296        }
297
298        println!();
299    }
300
301    // Performance trade-offs analysis
302    println!("   Performance trade-offs:");
303    println!("   - Deeper circuits: higher expressivity, more barren plateaus");
304    println!("   - More entanglement: better feature mixing, higher noise sensitivity");
305    println!("   - More parameters: greater capacity, overfitting risk");
306
307    Ok(())
308}
309
310/// Generate quantum-inspired synthetic data
311fn generate_quantum_data(samples: usize, features: usize) -> Array2<f64> {
312    Array2::from_shape_fn((samples, features), |(i, j)| {
313        let phase = (i as f64).mul_add(0.1, j as f64 * 0.2).sin();
314        let amplitude = (i as f64 / samples as f64).exp() * 0.5;
315        amplitude * phase + 0.1 * fastrand::f64()
316    })
317}
318
319/// Create custom search space for RL demo
320fn create_custom_search_space() -> SearchSpace {
321    SearchSpace {
322        layer_types: vec![
323            QNNLayerType::VariationalLayer { num_params: 4 },
324            QNNLayerType::VariationalLayer { num_params: 8 },
325            QNNLayerType::EntanglementLayer {
326                connectivity: "circular".to_string(),
327            },
328            QNNLayerType::EntanglementLayer {
329                connectivity: "linear".to_string(),
330            },
331        ],
332        depth_range: (1, 5),
333        qubit_constraints: QubitConstraints {
334            min_qubits: 3,
335            max_qubits: 6,
336            topology: Some(QuantumTopology::Ring),
337        },
338        param_ranges: vec![("variational_params".to_string(), (3, 12))]
339            .into_iter()
340            .collect(),
341        connectivity_patterns: vec!["linear".to_string(), "circular".to_string()],
342        measurement_bases: vec!["computational".to_string(), "Pauli-Z".to_string()],
343    }
344}
345
346/// Create search space optimized for DARTS
347fn create_darts_search_space() -> SearchSpace {
348    SearchSpace {
349        layer_types: vec![
350            QNNLayerType::VariationalLayer { num_params: 6 },
351            QNNLayerType::VariationalLayer { num_params: 9 },
352            QNNLayerType::EntanglementLayer {
353                connectivity: "full".to_string(),
354            },
355        ],
356        depth_range: (3, 6),
357        qubit_constraints: QubitConstraints {
358            min_qubits: 4,
359            max_qubits: 4, // Fixed for DARTS
360            topology: Some(QuantumTopology::Complete),
361        },
362        param_ranges: vec![("variational_params".to_string(), (6, 9))]
363            .into_iter()
364            .collect(),
365        connectivity_patterns: vec!["full".to_string()],
366        measurement_bases: vec!["computational".to_string()],
367    }
368}
369
370/// Create sample architectures for analysis
371fn create_sample_architectures() -> Vec<ArchitectureCandidate> {
372    vec![
373        // Simple architecture
374        ArchitectureCandidate {
375            id: "simple".to_string(),
376            layers: vec![
377                QNNLayerType::EncodingLayer { num_features: 4 },
378                QNNLayerType::VariationalLayer { num_params: 6 },
379                QNNLayerType::MeasurementLayer {
380                    measurement_basis: "computational".to_string(),
381                },
382            ],
383            num_qubits: 3,
384            metrics: ArchitectureMetrics {
385                accuracy: Some(0.65),
386                loss: Some(0.4),
387                circuit_depth: 3,
388                parameter_count: 6,
389                training_time: Some(10.0),
390                memory_usage: Some(512),
391                hardware_efficiency: Some(0.8),
392            },
393            properties: ArchitectureProperties {
394                expressivity: Some(0.3),
395                entanglement_capability: Some(0.2),
396                gradient_variance: Some(0.1),
397                barren_plateau_score: Some(0.2),
398                noise_resilience: Some(0.7),
399            },
400        },
401        // Complex architecture
402        ArchitectureCandidate {
403            id: "complex".to_string(),
404            layers: vec![
405                QNNLayerType::EncodingLayer { num_features: 6 },
406                QNNLayerType::VariationalLayer { num_params: 12 },
407                QNNLayerType::EntanglementLayer {
408                    connectivity: "full".to_string(),
409                },
410                QNNLayerType::VariationalLayer { num_params: 12 },
411                QNNLayerType::EntanglementLayer {
412                    connectivity: "circular".to_string(),
413                },
414                QNNLayerType::MeasurementLayer {
415                    measurement_basis: "Pauli-Z".to_string(),
416                },
417            ],
418            num_qubits: 6,
419            metrics: ArchitectureMetrics {
420                accuracy: Some(0.85),
421                loss: Some(0.2),
422                circuit_depth: 8,
423                parameter_count: 24,
424                training_time: Some(45.0),
425                memory_usage: Some(2048),
426                hardware_efficiency: Some(0.4),
427            },
428            properties: ArchitectureProperties {
429                expressivity: Some(0.8),
430                entanglement_capability: Some(0.9),
431                gradient_variance: Some(0.3),
432                barren_plateau_score: Some(0.7),
433                noise_resilience: Some(0.3),
434            },
435        },
436        // Balanced architecture
437        ArchitectureCandidate {
438            id: "balanced".to_string(),
439            layers: vec![
440                QNNLayerType::EncodingLayer { num_features: 4 },
441                QNNLayerType::VariationalLayer { num_params: 8 },
442                QNNLayerType::EntanglementLayer {
443                    connectivity: "circular".to_string(),
444                },
445                QNNLayerType::VariationalLayer { num_params: 8 },
446                QNNLayerType::MeasurementLayer {
447                    measurement_basis: "computational".to_string(),
448                },
449            ],
450            num_qubits: 4,
451            metrics: ArchitectureMetrics {
452                accuracy: Some(0.78),
453                loss: Some(0.28),
454                circuit_depth: 5,
455                parameter_count: 16,
456                training_time: Some(25.0),
457                memory_usage: Some(1024),
458                hardware_efficiency: Some(0.65),
459            },
460            properties: ArchitectureProperties {
461                expressivity: Some(0.6),
462                entanglement_capability: Some(0.5),
463                gradient_variance: Some(0.15),
464                barren_plateau_score: Some(0.4),
465                noise_resilience: Some(0.6),
466            },
467        },
468    ]
469}