1use crate::builder::Circuit;
7use quantrs2_core::{
8 error::{QuantRS2Error, QuantRS2Result},
9 qubit::QubitId,
10};
11use scirs2_core::Complex64;
12use std::collections::HashMap;
13
14#[derive(Debug, Clone)]
19pub struct HybridOptimizationProblem<const N: usize> {
20 pub quantum_circuits: Vec<ParameterizedQuantumComponent<N>>,
22 pub classical_steps: Vec<ClassicalProcessingStep>,
24 pub data_flow: DataFlowGraph,
26 pub global_parameters: Vec<f64>,
28 pub objective: ObjectiveFunction,
30}
31
32#[derive(Debug, Clone)]
34pub struct ParameterizedQuantumComponent<const N: usize> {
35 pub circuit: Circuit<N>,
37 pub parameter_indices: Vec<usize>,
39 pub classical_inputs: Vec<String>,
41 pub quantum_outputs: Vec<String>,
43 pub id: String,
45}
46
47#[derive(Debug, Clone)]
49pub struct ClassicalProcessingStep {
50 pub id: String,
52 pub step_type: ClassicalStepType,
54 pub inputs: Vec<String>,
56 pub outputs: Vec<String>,
58 pub parameters: HashMap<String, f64>,
60}
61
62#[derive(Debug, Clone, PartialEq, Eq)]
64pub enum ClassicalStepType {
65 LinearAlgebra(LinearAlgebraOp),
67 MachineLearning(MLModelType),
69 Optimization(OptimizationMethod),
71 DataProcessing(DataProcessingOp),
73 ControlFlow(ControlFlowType),
75 ParameterUpdate(UpdateRule),
77 Custom(String),
79}
80
81#[derive(Debug, Clone, PartialEq, Eq)]
83pub enum LinearAlgebraOp {
84 MatrixMultiplication,
85 Eigendecomposition,
86 SVD,
87 LeastSquares,
88 LinearSolve,
89 TensorContraction,
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
94pub enum MLModelType {
95 NeuralNetwork,
96 SupportVectorMachine,
97 RandomForest,
98 GaussianProcess,
99 LinearRegression,
100 LogisticRegression,
101}
102
103#[derive(Debug, Clone, PartialEq, Eq)]
105pub enum OptimizationMethod {
106 GradientDescent,
107 BFGS,
108 NelderMead,
109 SimulatedAnnealing,
110 GeneticAlgorithm,
111 BayesianOptimization,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq)]
116pub enum DataProcessingOp {
117 Normalization,
118 Standardization,
119 PCA,
120 FeatureSelection,
121 DataAugmentation,
122 OutlierRemoval,
123}
124
125#[derive(Debug, Clone, PartialEq, Eq)]
127pub enum ControlFlowType {
128 Conditional,
129 Loop,
130 Parallel,
131 Adaptive,
132}
133
134#[derive(Debug, Clone, PartialEq, Eq)]
136pub enum UpdateRule {
137 GradientBased,
138 MomentumBased,
139 AdamOptimizer,
140 AdaGrad,
141 RMSProp,
142 Custom(String),
143}
144
145#[derive(Debug, Clone)]
147pub struct DataFlowGraph {
148 pub nodes: Vec<String>,
150 pub edges: Vec<(String, String, DataType)>,
152 pub execution_order: Vec<Vec<String>>,
154}
155
156#[derive(Debug, Clone, PartialEq)]
158pub enum DataType {
159 Measurements(Vec<f64>),
161 Probabilities(Vec<f64>),
163 Matrix(Vec<Vec<f64>>),
165 Scalar(f64),
167 Parameters(Vec<f64>),
169 Control(bool),
171 Custom(String),
173}
174
175#[derive(Debug, Clone)]
177pub struct ObjectiveFunction {
178 pub function_type: ObjectiveFunctionType,
180 pub target: Option<f64>,
182 pub weights: Vec<f64>,
184 pub regularization: Vec<RegularizationTerm>,
186}
187
188#[derive(Debug, Clone, PartialEq)]
190pub enum ObjectiveFunctionType {
191 ExpectationValue,
193 Fidelity,
195 CostFunction,
197 MultiObjective(Vec<Self>),
199 Custom(String),
201}
202
203#[derive(Debug, Clone)]
205pub struct RegularizationTerm {
206 pub reg_type: RegularizationType,
208 pub strength: f64,
210 pub parameter_indices: Vec<usize>,
212}
213
214#[derive(Debug, Clone, PartialEq, Eq)]
216pub enum RegularizationType {
217 L1,
218 L2,
219 ElasticNet,
220 TotalVariation,
221 Sparsity,
222 Smoothness,
223}
224
225#[derive(Debug, Clone)]
227pub struct HybridOptimizationResult {
228 pub optimal_parameters: Vec<f64>,
230 pub optimal_value: f64,
232 pub iterations: usize,
234 pub converged: bool,
236 pub history: OptimizationHistory,
238 pub quantum_info: QuantumStateInfo,
240}
241
242#[derive(Debug, Clone)]
244pub struct OptimizationHistory {
245 pub objective_values: Vec<f64>,
247 pub parameter_history: Vec<Vec<f64>>,
249 pub gradient_norms: Vec<f64>,
251 pub step_sizes: Vec<f64>,
253 pub execution_times: Vec<f64>,
255}
256
257#[derive(Debug, Clone)]
259pub struct QuantumStateInfo {
260 pub final_states: HashMap<String, Vec<Complex64>>,
262 pub measurement_stats: HashMap<String, MeasurementStatistics>,
264 pub entanglement_info: HashMap<String, EntanglementInfo>,
266}
267
268#[derive(Debug, Clone)]
270pub struct MeasurementStatistics {
271 pub means: Vec<f64>,
273 pub std_devs: Vec<f64>,
275 pub correlations: Vec<Vec<f64>>,
277 pub num_shots: usize,
279}
280
281#[derive(Debug, Clone)]
283pub struct EntanglementInfo {
284 pub von_neumann_entropy: f64,
286 pub mutual_information: Vec<Vec<f64>>,
288 pub entanglement_spectrum: Vec<f64>,
290}
291
292pub struct HybridOptimizer {
294 pub algorithm: HybridOptimizationAlgorithm,
296 pub max_iterations: usize,
298 pub tolerance: f64,
300 pub learning_rate_schedule: LearningRateSchedule,
302 pub parallelization: ParallelizationConfig,
304}
305
306#[derive(Debug, Clone, PartialEq, Eq)]
308pub enum HybridOptimizationAlgorithm {
309 CoordinateDescent,
311 SimultaneousOptimization,
313 HierarchicalOptimization,
315 AdaptiveOptimization,
317 Custom(String),
319}
320
321#[derive(Debug, Clone)]
323pub struct LearningRateSchedule {
324 pub initial_rate: f64,
326 pub schedule_type: ScheduleType,
328 pub parameters: HashMap<String, f64>,
330}
331
332#[derive(Debug, Clone, PartialEq, Eq)]
334pub enum ScheduleType {
335 Constant,
336 LinearDecay,
337 ExponentialDecay,
338 StepDecay,
339 CosineAnnealing,
340 Adaptive,
341}
342
343#[derive(Debug, Clone)]
345pub struct ParallelizationConfig {
346 pub quantum_parallelism: usize,
348 pub classical_parallelism: usize,
350 pub asynchronous: bool,
352 pub load_balancing: LoadBalancingStrategy,
354}
355
356#[derive(Debug, Clone, PartialEq, Eq)]
358pub enum LoadBalancingStrategy {
359 RoundRobin,
360 WorkStealing,
361 Dynamic,
362 Static,
363}
364
365impl<const N: usize> HybridOptimizationProblem<N> {
366 #[must_use]
368 pub fn new() -> Self {
369 Self {
370 quantum_circuits: Vec::new(),
371 classical_steps: Vec::new(),
372 data_flow: DataFlowGraph {
373 nodes: Vec::new(),
374 edges: Vec::new(),
375 execution_order: Vec::new(),
376 },
377 global_parameters: Vec::new(),
378 objective: ObjectiveFunction {
379 function_type: ObjectiveFunctionType::ExpectationValue,
380 target: None,
381 weights: vec![1.0],
382 regularization: Vec::new(),
383 },
384 }
385 }
386
387 pub fn add_quantum_component(
389 &mut self,
390 id: String,
391 circuit: Circuit<N>,
392 parameter_indices: Vec<usize>,
393 ) -> QuantRS2Result<()> {
394 for &idx in ¶meter_indices {
396 if idx >= self.global_parameters.len() {
397 return Err(QuantRS2Error::InvalidInput(format!(
398 "Parameter index {} out of range (total parameters: {})",
399 idx,
400 self.global_parameters.len()
401 )));
402 }
403 }
404
405 let component = ParameterizedQuantumComponent {
406 circuit,
407 parameter_indices,
408 classical_inputs: Vec::new(),
409 quantum_outputs: Vec::new(),
410 id: id.clone(),
411 };
412
413 self.quantum_circuits.push(component);
414 self.data_flow.nodes.push(id);
415 Ok(())
416 }
417
418 pub fn add_classical_step(
420 &mut self,
421 id: String,
422 step_type: ClassicalStepType,
423 inputs: Vec<String>,
424 outputs: Vec<String>,
425 ) -> QuantRS2Result<()> {
426 let step = ClassicalProcessingStep {
427 id: id.clone(),
428 step_type,
429 inputs,
430 outputs,
431 parameters: HashMap::new(),
432 };
433
434 self.classical_steps.push(step);
435 self.data_flow.nodes.push(id);
436 Ok(())
437 }
438
439 pub fn add_data_flow(
441 &mut self,
442 source: String,
443 target: String,
444 data_type: DataType,
445 ) -> QuantRS2Result<()> {
446 if !self.data_flow.nodes.contains(&source) {
448 return Err(QuantRS2Error::InvalidInput(format!(
449 "Source component '{source}' not found"
450 )));
451 }
452 if !self.data_flow.nodes.contains(&target) {
453 return Err(QuantRS2Error::InvalidInput(format!(
454 "Target component '{target}' not found"
455 )));
456 }
457
458 self.data_flow.edges.push((source, target, data_type));
459 Ok(())
460 }
461
462 pub fn set_global_parameters(&mut self, parameters: Vec<f64>) {
464 self.global_parameters = parameters;
465 }
466
467 pub fn add_regularization(
469 &mut self,
470 reg_type: RegularizationType,
471 strength: f64,
472 parameter_indices: Vec<usize>,
473 ) -> QuantRS2Result<()> {
474 for &idx in ¶meter_indices {
476 if idx >= self.global_parameters.len() {
477 return Err(QuantRS2Error::InvalidInput(format!(
478 "Parameter index {idx} out of range"
479 )));
480 }
481 }
482
483 self.objective.regularization.push(RegularizationTerm {
484 reg_type,
485 strength,
486 parameter_indices,
487 });
488
489 Ok(())
490 }
491
492 pub fn validate(&self) -> QuantRS2Result<()> {
494 for edge in &self.data_flow.edges {
496 let (source, target, _) = edge;
497 if !self.data_flow.nodes.contains(source) {
498 return Err(QuantRS2Error::InvalidInput(format!(
499 "Data flow edge references non-existent source '{source}'"
500 )));
501 }
502 if !self.data_flow.nodes.contains(target) {
503 return Err(QuantRS2Error::InvalidInput(format!(
504 "Data flow edge references non-existent target '{target}'"
505 )));
506 }
507 }
508
509 if self.has_circular_dependencies()? {
511 return Err(QuantRS2Error::InvalidInput(
512 "Circular dependencies detected in data flow graph".to_string(),
513 ));
514 }
515
516 Ok(())
517 }
518
519 fn has_circular_dependencies(&self) -> QuantRS2Result<bool> {
521 for (source, target, _) in &self.data_flow.edges {
524 if source == target {
525 return Ok(true);
526 }
527 }
528 Ok(false)
529 }
530}
531
532impl Default for HybridOptimizationProblem<4> {
533 fn default() -> Self {
534 Self::new()
535 }
536}
537
538impl HybridOptimizer {
539 #[must_use]
541 pub fn new(algorithm: HybridOptimizationAlgorithm) -> Self {
542 Self {
543 algorithm,
544 max_iterations: 1000,
545 tolerance: 1e-6,
546 learning_rate_schedule: LearningRateSchedule {
547 initial_rate: 0.01,
548 schedule_type: ScheduleType::Constant,
549 parameters: HashMap::new(),
550 },
551 parallelization: ParallelizationConfig {
552 quantum_parallelism: 1,
553 classical_parallelism: 1,
554 asynchronous: false,
555 load_balancing: LoadBalancingStrategy::RoundRobin,
556 },
557 }
558 }
559
560 pub fn optimize<const N: usize>(
562 &self,
563 problem: &mut HybridOptimizationProblem<N>,
564 ) -> QuantRS2Result<HybridOptimizationResult> {
565 problem.validate()?;
567
568 let mut history = OptimizationHistory {
570 objective_values: Vec::new(),
571 parameter_history: Vec::new(),
572 gradient_norms: Vec::new(),
573 step_sizes: Vec::new(),
574 execution_times: Vec::new(),
575 };
576
577 let mut current_parameters = problem.global_parameters.clone();
578 let mut best_parameters = current_parameters.clone();
579 let mut best_value = f64::INFINITY;
580
581 for iteration in 0..self.max_iterations {
583 let start_time = std::time::Instant::now();
584
585 let current_value = self.evaluate_objective(problem, ¤t_parameters)?;
587
588 if current_value < best_value {
589 best_value = current_value;
590 best_parameters.clone_from(¤t_parameters);
591 }
592
593 history.objective_values.push(current_value);
595 history.parameter_history.push(current_parameters.clone());
596
597 let gradients = self.compute_gradients(problem, ¤t_parameters)?;
599 let gradient_norm = gradients.iter().map(|g| g * g).sum::<f64>().sqrt();
600 history.gradient_norms.push(gradient_norm);
601
602 if gradient_norm < self.tolerance {
604 let execution_time = start_time.elapsed().as_secs_f64();
605 history.execution_times.push(execution_time);
606
607 return Ok(HybridOptimizationResult {
608 optimal_parameters: best_parameters,
609 optimal_value: best_value,
610 iterations: iteration + 1,
611 converged: true,
612 history,
613 quantum_info: self.extract_quantum_info(problem)?,
614 });
615 }
616
617 let learning_rate = self.get_learning_rate(iteration);
619 for (i, gradient) in gradients.iter().enumerate() {
620 current_parameters[i] -= learning_rate * gradient;
621 }
622
623 let step_size = learning_rate * gradient_norm;
624 history.step_sizes.push(step_size);
625
626 let execution_time = start_time.elapsed().as_secs_f64();
627 history.execution_times.push(execution_time);
628 }
629
630 Ok(HybridOptimizationResult {
632 optimal_parameters: best_parameters,
633 optimal_value: best_value,
634 iterations: self.max_iterations,
635 converged: false,
636 history,
637 quantum_info: self.extract_quantum_info(problem)?,
638 })
639 }
640
641 const fn evaluate_objective<const N: usize>(
643 &self,
644 _problem: &HybridOptimizationProblem<N>,
645 _parameters: &[f64],
646 ) -> QuantRS2Result<f64> {
647 Ok(1.0)
655 }
656
657 fn compute_gradients<const N: usize>(
659 &self,
660 problem: &HybridOptimizationProblem<N>,
661 _parameters: &[f64],
662 ) -> QuantRS2Result<Vec<f64>> {
663 Ok(vec![0.001; problem.global_parameters.len()])
670 }
671
672 fn get_learning_rate(&self, iteration: usize) -> f64 {
674 match self.learning_rate_schedule.schedule_type {
675 ScheduleType::Constant => self.learning_rate_schedule.initial_rate,
676 ScheduleType::LinearDecay => {
677 let decay_rate = self
678 .learning_rate_schedule
679 .parameters
680 .get("decay_rate")
681 .unwrap_or(&0.001);
682 self.learning_rate_schedule.initial_rate / (1.0 + decay_rate * iteration as f64)
683 }
684 ScheduleType::ExponentialDecay => {
685 let decay_rate = self
686 .learning_rate_schedule
687 .parameters
688 .get("decay_rate")
689 .unwrap_or(&0.95);
690 self.learning_rate_schedule.initial_rate * decay_rate.powi(iteration as i32)
691 }
692 _ => self.learning_rate_schedule.initial_rate, }
694 }
695
696 fn extract_quantum_info<const N: usize>(
698 &self,
699 _problem: &HybridOptimizationProblem<N>,
700 ) -> QuantRS2Result<QuantumStateInfo> {
701 Ok(QuantumStateInfo {
707 final_states: HashMap::new(),
708 measurement_stats: HashMap::new(),
709 entanglement_info: HashMap::new(),
710 })
711 }
712}
713
714impl Default for HybridOptimizer {
715 fn default() -> Self {
716 Self::new(HybridOptimizationAlgorithm::CoordinateDescent)
717 }
718}
719
720#[cfg(test)]
721mod tests {
722 use super::*;
723
724 #[test]
725 fn test_hybrid_problem_creation() {
726 let problem = HybridOptimizationProblem::<4>::new();
727 assert_eq!(problem.quantum_circuits.len(), 0);
728 assert_eq!(problem.classical_steps.len(), 0);
729 }
730
731 #[test]
732 fn test_component_addition() {
733 let mut problem = HybridOptimizationProblem::<2>::new();
734 problem.set_global_parameters(vec![0.1, 0.2, 0.3]);
735
736 let circuit = Circuit::<2>::new();
737 problem
738 .add_quantum_component("q1".to_string(), circuit, vec![0, 1])
739 .expect("add_quantum_component should succeed");
740
741 assert_eq!(problem.quantum_circuits.len(), 1);
742 assert_eq!(problem.data_flow.nodes.len(), 1);
743 }
744
745 #[test]
746 fn test_data_flow() {
747 let mut problem = HybridOptimizationProblem::<2>::new();
748 problem.set_global_parameters(vec![0.1, 0.2]);
749
750 let circuit = Circuit::<2>::new();
751 problem
752 .add_quantum_component("q1".to_string(), circuit, vec![0])
753 .expect("add_quantum_component should succeed");
754 problem
755 .add_classical_step(
756 "c1".to_string(),
757 ClassicalStepType::LinearAlgebra(LinearAlgebraOp::MatrixMultiplication),
758 vec!["q1".to_string()],
759 vec!["output".to_string()],
760 )
761 .expect("add_classical_step should succeed");
762
763 problem
764 .add_data_flow(
765 "q1".to_string(),
766 "c1".to_string(),
767 DataType::Measurements(vec![0.1, 0.2]),
768 )
769 .expect("add_data_flow should succeed");
770
771 assert_eq!(problem.data_flow.edges.len(), 1);
772 }
773
774 #[test]
775 fn test_optimizer_creation() {
776 let optimizer = HybridOptimizer::new(HybridOptimizationAlgorithm::SimultaneousOptimization);
777 assert_eq!(
778 optimizer.algorithm,
779 HybridOptimizationAlgorithm::SimultaneousOptimization
780 );
781 assert_eq!(optimizer.max_iterations, 1000);
782 }
783}