ruqu_vq_nas/lib.rs
1//! # ruqu-vq-nas - Variational Quantum Neural Architecture Search
2//!
3//! This crate provides tools for automated quantum circuit architecture discovery
4//! using neural architecture search techniques. It enables finding optimal
5//! variational quantum circuit designs for quantum machine learning tasks.
6//!
7//! ## Features
8//!
9//! - **Search Space Definition**: Define quantum gate primitives, layer templates,
10//! and connectivity constraints for circuit architectures.
11//!
12//! - **Architecture Encoding**: Encode architectures as discrete choices, continuous
13//! relaxations, or embedding vectors for different search strategies.
14//!
15//! - **Search Algorithms**:
16//! - Random search (baseline)
17//! - Evolutionary search with mutation and crossover
18//! - Regularized evolution (aging-based)
19//! - Bayesian optimization interface
20//! - Differentiable architecture search
21//!
22//! - **Evaluation Metrics**:
23//! - Circuit expressibility (KL divergence from Haar random)
24//! - Entanglement capability (Meyer-Wallach measure proxy)
25//! - Training convergence proxy
26//! - Hardware cost estimation
27//!
28//! - **Circuit Builder**: Build variational quantum circuits from architecture
29//! specifications with parameter initialization and gradient computation helpers.
30//!
31//! ## Quick Start
32//!
33//! ```rust
34//! use ruqu_vq_nas::{
35//! search_space::{SearchSpace, GateType},
36//! search::{SearchAlgorithm, SearchConfig},
37//! };
38//! use rand::SeedableRng;
39//! use rand_chacha::ChaCha8Rng;
40//!
41//! // Create a search space
42//! let space = SearchSpace::hardware_efficient(4, 5).unwrap();
43//!
44//! // Configure search
45//! let config = SearchConfig::quick();
46//!
47//! // Run random search
48//! let mut rng = ChaCha8Rng::seed_from_u64(42);
49//! let mut search = SearchAlgorithm::random(space, config);
50//! let result = search.search(&mut rng).unwrap();
51//!
52//! println!("Best fitness: {}", result.best_evaluation.fitness);
53//! println!("Evaluations: {}", result.num_evaluations);
54//! ```
55//!
56//! ## Search Space Example
57//!
58//! ```rust
59//! use ruqu_vq_nas::search_space::{
60//! SearchSpaceBuilder, GateType, ConnectivityGraph, LayerTemplate
61//! };
62//!
63//! // Build a custom search space
64//! let space = SearchSpaceBuilder::new(4)
65//! .depth_range(2, 8)
66//! .gate_set(vec![GateType::RY, GateType::RZ, GateType::CNOT])
67//! .connectivity(ConnectivityGraph::linear(4))
68//! .build()
69//! .unwrap();
70//! ```
71//!
72//! ## Circuit Building Example
73//!
74//! ```rust
75//! use ruqu_vq_nas::circuit::{
76//! CircuitBuilder, HardwareEfficientAnsatz, InitializationStrategy
77//! };
78//! use ruqu_vq_nas::search_space::GateType;
79//! use rand::SeedableRng;
80//! use rand_chacha::ChaCha8Rng;
81//!
82//! // Build a hardware-efficient ansatz
83//! let ansatz = HardwareEfficientAnsatz::new(4, 3);
84//! let circuit = ansatz.build();
85//!
86//! println!("Qubits: {}", circuit.num_qubits);
87//! println!("Parameters: {}", circuit.num_parameters);
88//! println!("Two-qubit gates: {}", circuit.two_qubit_gate_count());
89//!
90//! // Or use the builder pattern
91//! let mut rng = ChaCha8Rng::seed_from_u64(42);
92//! let circuit = CircuitBuilder::new(4)
93//! .rotation_layer(&[ruqu_vq_nas::search_space::GateType::RY, ruqu_vq_nas::search_space::GateType::RZ])
94//! .entangling_layer_linear(ruqu_vq_nas::search_space::GateType::CNOT)
95//! .rotation_layer(&[ruqu_vq_nas::search_space::GateType::RY, ruqu_vq_nas::search_space::GateType::RZ])
96//! .build_with_strategy(InitializationStrategy::Small { scale: 0.1 }, &mut rng);
97//! ```
98//!
99//! ## Evaluation Example
100//!
101//! ```rust
102//! use ruqu_vq_nas::circuit::HardwareEfficientAnsatz;
103//! use ruqu_vq_nas::evaluation::{CircuitEvaluator, EvaluationConfig};
104//! use rand::SeedableRng;
105//! use rand_chacha::ChaCha8Rng;
106//!
107//! let mut rng = ChaCha8Rng::seed_from_u64(42);
108//! let circuit = HardwareEfficientAnsatz::new(4, 2).build();
109//!
110//! let evaluator = CircuitEvaluator::with_config(EvaluationConfig::fast());
111//! let result = evaluator.evaluate(&circuit, &mut rng).unwrap();
112//!
113//! println!("Expressibility: {:.4}", result.expressibility);
114//! println!("Entanglement: {:.4}", result.entanglement_capability);
115//! println!("Fitness: {:.4}", result.fitness);
116//! ```
117//!
118//! ## Tier 3 Capability (Score 74)
119//!
120//! This crate implements Tier 3 quantum capabilities for automated circuit
121//! architecture discovery. The two-week validation tests are:
122//!
123//! 1. Search space definition works correctly
124//! 2. Architecture search runs and produces valid circuits
125//!
126//! ## Crate Features
127//!
128//! - `default` - Includes parallel processing via rayon
129//! - `parallel` - Enable parallel evaluation and search
130//! - `ruqu-integration` - Integration with the ruQu quantum simulation crate
131//! - `full` - All features enabled
132
133#![warn(missing_docs)]
134#![warn(rustdoc::missing_doc_code_examples)]
135#![deny(unsafe_code)]
136
137pub mod circuit;
138pub mod encoding;
139pub mod error;
140pub mod evaluation;
141pub mod search;
142pub mod search_space;
143
144// Re-export commonly used types at crate root
145pub use circuit::{
146 CircuitBuilder, GradientComputer, HardwareEfficientAnsatz, InitializationStrategy,
147 QuantumCircuit, StronglyEntanglingLayers,
148};
149pub use encoding::{
150 ArchitectureEmbedding, ArchitectureEncoder, ContinuousEncoding, DiscreteEncoding,
151};
152pub use error::{
153 CircuitError, EncodingError, EvaluationError, Result, SearchError, SearchSpaceError,
154 VqNasError,
155};
156pub use evaluation::{
157 BatchEvaluator, CircuitEvaluator, EntanglementCalculator, EvaluationConfig, EvaluationResult,
158 ExpressibilityCalculator, FitnessWeights, HardwareCost,
159};
160pub use search::{
161 BayesianOptimization, DifferentiableSearch, EvolutionaryConfig, EvolutionarySearch,
162 RandomSearch, RegularizedEvolution, RegularizedEvolutionConfig, SearchAlgorithm, SearchConfig,
163 SearchResult,
164};
165pub use search_space::{
166 ConnectivityGraph, EntanglementPattern, GateOperation, GateType, LayerTemplate, SearchSpace,
167 SearchSpaceBuilder,
168};
169
170/// Crate version
171pub const VERSION: &str = env!("CARGO_PKG_VERSION");
172
173/// Prelude module for convenient imports.
174pub mod prelude {
175 pub use crate::circuit::{
176 CircuitBuilder, HardwareEfficientAnsatz, InitializationStrategy, QuantumCircuit,
177 };
178 pub use crate::encoding::{DiscreteEncoding, ArchitectureEncoder};
179 pub use crate::error::{Result, VqNasError};
180 pub use crate::evaluation::{CircuitEvaluator, EvaluationConfig, EvaluationResult};
181 pub use crate::search::{SearchAlgorithm, SearchConfig, SearchResult};
182 pub use crate::search_space::{GateType, SearchSpace, SearchSpaceBuilder};
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use rand::SeedableRng;
189 use rand_chacha::ChaCha8Rng;
190
191 #[test]
192 fn test_version() {
193 assert!(!VERSION.is_empty());
194 }
195
196 #[test]
197 fn test_prelude_imports() {
198 use crate::prelude::*;
199
200 let space = SearchSpace::hardware_efficient(4, 3).unwrap();
201 let config = SearchConfig::quick();
202 let mut rng = ChaCha8Rng::seed_from_u64(42);
203
204 let mut alg = SearchAlgorithm::random(space, config);
205 let result = alg.search(&mut rng).unwrap();
206
207 assert!(result.num_evaluations > 0);
208 }
209
210 #[test]
211 fn test_full_workflow() {
212 // 1. Define search space
213 let space = SearchSpaceBuilder::new(3)
214 .depth_range(1, 4)
215 .gate_set(vec![GateType::RY, GateType::RZ, GateType::CNOT])
216 .build()
217 .unwrap();
218
219 // 2. Configure search
220 let config = SearchConfig::quick();
221
222 // 3. Run search
223 let mut rng = ChaCha8Rng::seed_from_u64(42);
224 let mut search = SearchAlgorithm::random(space.clone(), config);
225 let result = search.search(&mut rng).unwrap();
226
227 // 4. Build circuit from best architecture
228 let circuit = QuantumCircuit::from_encoding(&result.best_encoding, &space).unwrap();
229
230 // 5. Verify circuit properties
231 assert_eq!(circuit.num_qubits, 3);
232 assert!(circuit.validate().is_ok());
233 }
234
235 #[test]
236 fn test_evolutionary_workflow() {
237 let space = SearchSpace::hardware_efficient(3, 3).unwrap();
238 let config = SearchConfig::quick();
239 let evo_config = EvolutionaryConfig {
240 population_size: 10,
241 num_parents: 5,
242 ..Default::default()
243 };
244
245 let mut rng = ChaCha8Rng::seed_from_u64(42);
246 let mut search =
247 SearchAlgorithm::evolutionary(space, config, evo_config).unwrap();
248 let result = search.search(&mut rng).unwrap();
249
250 assert!(result.num_evaluations > 0);
251 assert!(result.best_evaluation.fitness.is_finite());
252 }
253
254 #[test]
255 fn test_circuit_builder_workflow() {
256 let mut rng = ChaCha8Rng::seed_from_u64(42);
257
258 let circuit = CircuitBuilder::new(4)
259 .h(0)
260 .h(1)
261 .h(2)
262 .h(3)
263 .rotation_layer(&[GateType::RY, GateType::RZ])
264 .entangling_layer_linear(GateType::CNOT)
265 .rotation_layer(&[GateType::RY])
266 .build_with_random_params(&mut rng);
267
268 assert_eq!(circuit.num_qubits, 4);
269 assert!(circuit.num_parameters > 0);
270 assert!(circuit.two_qubit_gate_count() > 0);
271 }
272
273 #[test]
274 fn test_evaluation_workflow() {
275 let mut rng = ChaCha8Rng::seed_from_u64(42);
276 let circuit = HardwareEfficientAnsatz::new(3, 2).build();
277
278 let evaluator = CircuitEvaluator::with_config(EvaluationConfig::fast());
279 let result = evaluator.evaluate(&circuit, &mut rng).unwrap();
280
281 // Check all metrics are in expected ranges
282 assert!(result.expressibility >= 0.0);
283 assert!(result.entanglement_capability >= 0.0 && result.entanglement_capability <= 1.0);
284 assert!(result.convergence_proxy >= 0.0 && result.convergence_proxy <= 1.0);
285 assert!(result.hardware_cost.gate_count > 0);
286 }
287
288 #[test]
289 fn test_encoding_workflow() {
290 let space = SearchSpace::hardware_efficient(4, 5).unwrap();
291 let mut rng = ChaCha8Rng::seed_from_u64(42);
292
293 // Create random discrete encoding
294 let discrete = DiscreteEncoding::random(&space, &mut rng);
295 assert!(discrete.validate(&space).is_ok());
296
297 // Convert to embedding
298 let encoder = ArchitectureEncoder::new(space.clone(), 32);
299 let embedding = encoder.embed(&discrete).unwrap();
300 assert_eq!(embedding.dimension, 32);
301
302 // Decode to operations
303 let operations = encoder.decode_to_operations(&discrete);
304 assert_eq!(operations.len(), discrete.depth);
305 }
306
307 #[test]
308 fn test_continuous_encoding_workflow() {
309 let space = SearchSpace::hardware_efficient(3, 3).unwrap();
310 let mut rng = ChaCha8Rng::seed_from_u64(42);
311
312 // Create continuous encoding
313 let continuous = ContinuousEncoding::random(&space, &mut rng);
314
315 // Sample discrete encodings
316 for _ in 0..5 {
317 let discrete = continuous.sample(&space, &mut rng);
318 assert!(discrete.validate(&space).is_ok());
319 }
320
321 // Get argmax discrete
322 let best_discrete = continuous.to_discrete(&space);
323 assert!(best_discrete.validate(&space).is_ok());
324 }
325
326 #[test]
327 fn test_gradient_computation() {
328 let circuit = CircuitBuilder::new(2).ry(0).ry(1).cnot(0, 1).build();
329
330 let computer = GradientComputer::new();
331
332 // Quadratic loss function
333 let loss = |params: &ndarray::Array1<f64>| -> f64 {
334 params.iter().map(|x| x.powi(2)).sum()
335 };
336
337 let grads = computer.compute_gradients(&circuit, loss).unwrap();
338 assert_eq!(grads.len(), 2);
339 }
340}