1use crate::error::OptimizeResult;
12use crate::result::OptimizeResults;
13use ndarray::{Array1, Array2, ArrayView1};
14use num_traits::Zero;
15use rand::{rng, Rng};
16use std::collections::VecDeque;
17use std::f64::consts::PI;
18
19#[derive(Debug, Clone, Copy)]
21pub struct Complex {
22 pub real: f64,
23 pub imag: f64,
24}
25
26impl Complex {
27 pub fn new(real: f64, imag: f64) -> Self {
28 Self { real, imag }
29 }
30
31 pub fn magnitude(&self) -> f64 {
32 (self.real * self.real + self.imag * self.imag).sqrt()
33 }
34
35 pub fn phase(&self) -> f64 {
36 self.imag.atan2(self.real)
37 }
38
39 pub fn conjugate(&self) -> Complex {
40 Complex::new(self.real, -self.imag)
41 }
42}
43
44impl std::ops::Add for Complex {
45 type Output = Complex;
46
47 fn add(self, other: Complex) -> Complex {
48 Complex::new(self.real + other.real, self.imag + other.imag)
49 }
50}
51
52impl std::ops::Mul for Complex {
53 type Output = Complex;
54
55 fn mul(self, other: Complex) -> Complex {
56 Complex::new(
57 self.real * other.real - self.imag * other.imag,
58 self.real * other.imag + self.imag * other.real,
59 )
60 }
61}
62
63impl std::ops::Mul<f64> for Complex {
64 type Output = Complex;
65
66 fn mul(self, scalar: f64) -> Complex {
67 Complex::new(self.real * scalar, self.imag * scalar)
68 }
69}
70
71impl Zero for Complex {
72 fn zero() -> Self {
73 Complex::new(0.0, 0.0)
74 }
75
76 fn is_zero(&self) -> bool {
77 self.real == 0.0 && self.imag == 0.0
78 }
79}
80
81#[derive(Debug, Clone)]
83pub struct QuantumState {
84 pub amplitudes: Array1<Complex>,
86 pub basis_states: Array2<f64>,
88 pub num_qubits: usize,
90 pub entanglement_matrix: Array2<Complex>,
92 pub decoherence_time: f64,
94 pub evolution_time: f64,
96}
97
98impl QuantumState {
99 pub fn new(num_params: usize, num_basis_states: usize) -> Self {
101 let num_qubits = (num_basis_states as f64).log2().ceil() as usize;
102 let actual_states = 1 << num_qubits;
103
104 let mut amplitudes = Array1::from_shape_fn(actual_states, |_| {
106 Complex::new(
107 rand::rng().random_range(-1.0..1.0),
108 rand::rng().random_range(-1.0..1.0),
109 )
110 });
111
112 let norm: f64 = amplitudes
114 .iter()
115 .map(|c| c.magnitude().powi(2))
116 .sum::<f64>()
117 .sqrt();
118 for amp in amplitudes.iter_mut() {
119 *amp = *amp * (1.0 / norm);
120 }
121
122 let basis_states = Array2::from_shape_fn((actual_states, num_params), |_| {
124 rand::rng().random_range(-2.0..5.0)
125 });
126
127 let entanglement_matrix = Array2::from_shape_fn((num_params, num_params), |(i, j)| {
129 if i == j {
130 Complex::new(1.0, 0.0)
131 } else {
132 let correlation = rand::rng().random_range(-0.1..0.1);
133 Complex::new(correlation, correlation * 0.1)
134 }
135 });
136
137 Self {
138 amplitudes,
139 basis_states,
140 num_qubits,
141 entanglement_matrix,
142 decoherence_time: 1000.0,
143 evolution_time: 0.0,
144 }
145 }
146
147 pub fn measure(&self) -> Array1<f64> {
149 let probabilities: Vec<f64> = self
151 .amplitudes
152 .iter()
153 .map(|c| c.magnitude().powi(2))
154 .collect();
155
156 let mut cumulative = 0.0;
158 let random_value = rand::rng().random_range(0.0..1.0);
159
160 for (i, &prob) in probabilities.iter().enumerate() {
161 cumulative += prob;
162 if random_value <= cumulative {
163 return self.basis_states.row(i).to_owned();
164 }
165 }
166
167 let max_prob_idx = probabilities
169 .iter()
170 .enumerate()
171 .max_by(|a, b| a.1.partial_cmp(b.1).unwrap())
172 .map(|(i, _)| i)
173 .unwrap_or(0);
174
175 self.basis_states.row(max_prob_idx).to_owned()
176 }
177
178 pub fn evolve(&mut self, objective_gradients: &Array1<f64>, dt: f64) -> OptimizeResult<()> {
180 self.evolution_time += dt;
181
182 let hamiltonian = self.compute_hamiltonian(objective_gradients)?;
184
185 self.apply_time_evolution(&hamiltonian, dt)?;
187
188 self.apply_decoherence(dt)?;
190
191 self.update_entanglement(objective_gradients)?;
193
194 Ok(())
195 }
196
197 fn compute_hamiltonian(
198 &self,
199 objective_gradients: &Array1<f64>,
200 ) -> OptimizeResult<Array2<Complex>> {
201 let n_states = self.amplitudes.len();
202 let mut hamiltonian = Array2::zeros((n_states, n_states));
203
204 for i in 0..n_states {
205 for j in 0..n_states {
206 if i == j {
207 let params = self.basis_states.row(i);
209 let potential = params
210 .iter()
211 .zip(objective_gradients.iter())
212 .map(|(&p, &g)| p * g)
213 .sum::<f64>();
214
215 hamiltonian[[i, j]] = Complex::new(potential, 0.0);
216 } else {
217 let distance = (&self.basis_states.row(i) - &self.basis_states.row(j))
219 .mapv(|x| x * x)
220 .sum()
221 .sqrt();
222
223 let tunneling_amplitude = (-distance * 0.1).exp();
224 hamiltonian[[i, j]] = Complex::new(0.0, tunneling_amplitude);
225 }
226 }
227 }
228
229 Ok(hamiltonian)
230 }
231
232 fn apply_time_evolution(
233 &mut self,
234 hamiltonian: &Array2<Complex>,
235 dt: f64,
236 ) -> OptimizeResult<()> {
237 let n_states = self.amplitudes.len();
241 let mut new_amplitudes = self.amplitudes.clone();
242
243 for i in 0..n_states {
244 let mut evolved_amp = Complex::new(0.0, 0.0);
245
246 for j in 0..n_states {
247 let h_element = hamiltonian[[i, j]];
248 let evolution_factor = if i == j {
249 Complex::new(1.0, 0.0) + Complex::new(0.0, -h_element.real * dt)
251 } else {
252 Complex::new(0.0, -h_element.real * dt) + Complex::new(h_element.imag * dt, 0.0)
254 };
255
256 evolved_amp = evolved_amp + evolution_factor * self.amplitudes[j];
257 }
258
259 new_amplitudes[i] = evolved_amp;
260 }
261
262 let norm: f64 = new_amplitudes
264 .iter()
265 .map(|c| c.magnitude().powi(2))
266 .sum::<f64>()
267 .sqrt();
268 for amp in new_amplitudes.iter_mut() {
269 *amp = *amp * (1.0 / norm.max(1e-12));
270 }
271
272 self.amplitudes = new_amplitudes;
273 Ok(())
274 }
275
276 fn apply_decoherence(&mut self, dt: f64) -> OptimizeResult<()> {
277 let decoherence_factor = (-dt / self.decoherence_time).exp();
279
280 for amp in self.amplitudes.iter_mut() {
281 *amp = *amp * decoherence_factor;
282 }
283
284 let noise_strength = 1.0 - decoherence_factor;
286 for amp in self.amplitudes.iter_mut() {
287 let noise_real = rand::rng().random_range(-0.5..0.5) * noise_strength * 0.01;
288 let noise_imag = rand::rng().random_range(-0.5..0.5) * noise_strength * 0.01;
289 *amp = *amp + Complex::new(noise_real, noise_imag);
290 }
291
292 let norm: f64 = self
294 .amplitudes
295 .iter()
296 .map(|c| c.magnitude().powi(2))
297 .sum::<f64>()
298 .sqrt();
299 for amp in self.amplitudes.iter_mut() {
300 *amp = *amp * (1.0 / norm.max(1e-12));
301 }
302
303 Ok(())
304 }
305
306 fn update_entanglement(&mut self, objective_gradients: &Array1<f64>) -> OptimizeResult<()> {
307 let n_params = self.entanglement_matrix.nrows();
308
309 for i in 0..n_params {
311 for j in i + 1..n_params {
312 if i < objective_gradients.len() && j < objective_gradients.len() {
313 let correlation = objective_gradients[i] * objective_gradients[j];
314 let phase_update = correlation * 0.01;
315
316 let current = self.entanglement_matrix[[i, j]];
317 let new_phase = current.phase() + phase_update;
318 let magnitude = current.magnitude() * 0.99 + correlation.abs() * 0.01;
319
320 self.entanglement_matrix[[i, j]] =
321 Complex::new(magnitude * new_phase.cos(), magnitude * new_phase.sin());
322 self.entanglement_matrix[[j, i]] = self.entanglement_matrix[[i, j]].conjugate();
323 }
324 }
325 }
326
327 Ok(())
328 }
329
330 pub fn create_superposition(&mut self, exploration_radius: f64) -> OptimizeResult<()> {
332 let n_states = self.basis_states.nrows();
333 let n_params = self.basis_states.ncols();
334
335 for i in 0..n_states {
337 for j in 0..n_params {
338 let perturbation =
339 rand::rng().random_range(-exploration_radius..exploration_radius);
340 self.basis_states[[i, j]] += perturbation;
341 }
342 }
343
344 let equal_amplitude = Complex::new(1.0 / (n_states as f64).sqrt(), 0.0);
346 for i in 0..n_states {
347 self.amplitudes[i] = equal_amplitude;
348 }
349
350 Ok(())
351 }
352
353 pub fn quantum_tunnel(
355 &mut self,
356 barrier_height: f64,
357 tunnel_probability: f64,
358 ) -> OptimizeResult<()> {
359 if rand::rng().random_range(0.0..1.0) < tunnel_probability {
360 let n_states = self.basis_states.nrows();
362 let n_params = self.basis_states.ncols();
363
364 let source_state = rand::rng().random_range(0..n_states);
366
367 for j in 0..n_params {
369 let tunnel_distance = barrier_height * rand::rng().random_range(-0.5..0.5);
370 self.basis_states[[source_state, j]] += tunnel_distance;
371 }
372
373 let tunnel_amplitude_factor = (-barrier_height * 0.1).exp();
375 self.amplitudes[source_state] = self.amplitudes[source_state] * tunnel_amplitude_factor;
376
377 let norm: f64 = self
379 .amplitudes
380 .iter()
381 .map(|c| c.magnitude().powi(2))
382 .sum::<f64>()
383 .sqrt();
384 for amp in self.amplitudes.iter_mut() {
385 *amp = *amp * (1.0 / norm.max(1e-12));
386 }
387 }
388
389 Ok(())
390 }
391}
392
393#[derive(Debug, Clone)]
395pub struct QuantumAnnealingSchedule {
396 pub initial_temperature: f64,
398 pub final_temperature: f64,
400 pub current_temperature: f64,
402 pub progress: f64,
404 pub schedule_type: CoolingSchedule,
406 pub quantum_fluctuation: f64,
408}
409
410#[derive(Debug, Clone)]
411pub enum CoolingSchedule {
412 Linear,
413 Exponential,
414 Logarithmic,
415 QuantumAdaptive,
416}
417
418impl QuantumAnnealingSchedule {
419 pub fn new(initial_temp: f64, final_temp: f64, schedule: CoolingSchedule) -> Self {
420 Self {
421 initial_temperature: initial_temp,
422 final_temperature: final_temp,
423 current_temperature: initial_temp,
424 progress: 0.0,
425 schedule_type: schedule,
426 quantum_fluctuation: 1.0,
427 }
428 }
429
430 pub fn update(&mut self, iteration: usize, max_nit: usize, energy_change: f64) {
431 self.progress = iteration as f64 / max_nit as f64;
432
433 self.current_temperature = match self.schedule_type {
434 CoolingSchedule::Linear => {
435 self.initial_temperature * (1.0 - self.progress)
436 + self.final_temperature * self.progress
437 }
438 CoolingSchedule::Exponential => {
439 self.initial_temperature
440 * (self.final_temperature / self.initial_temperature).powf(self.progress)
441 }
442 CoolingSchedule::Logarithmic => self.initial_temperature / (1.0 + self.progress).ln(),
443 CoolingSchedule::QuantumAdaptive => {
444 let base_temp = self.initial_temperature * (0.1_f64).powf(self.progress);
446 let quantum_correction = self.quantum_fluctuation * (-energy_change.abs()).exp();
447 base_temp * (1.0 + quantum_correction * 0.1)
448 }
449 };
450
451 self.quantum_fluctuation =
453 1.0 - self.progress + 0.1 * (2.0 * PI * self.progress * 10.0).sin();
454 }
455
456 pub fn should_accept(&self, energy_delta: f64) -> bool {
457 if energy_delta <= 0.0 {
458 true } else {
460 let classical_prob = (-energy_delta / self.current_temperature).exp();
462 let quantum_prob = classical_prob * (1.0 + self.quantum_fluctuation * 0.1);
463
464 rand::rng().random_range(0.0..1.0) < quantum_prob.min(1.0)
465 }
466 }
467}
468
469#[derive(Debug, Clone)]
471pub struct QuantumInspiredOptimizer {
472 pub quantum_state: QuantumState,
474 pub annealing_schedule: QuantumAnnealingSchedule,
476 pub best_solution: Array1<f64>,
478 pub best_objective: f64,
480 pub iteration: usize,
482 pub max_nit: usize,
484 pub function_evaluations: usize,
486 pub interference_history: VecDeque<f64>,
488 pub entanglement_strength: f64,
490 pub tunneling_events: usize,
492 pub tolerance: f64,
494}
495
496impl QuantumInspiredOptimizer {
497 pub fn new(
499 initial_params: &ArrayView1<f64>,
500 max_nit: usize,
501 num_quantum_states: usize,
502 ) -> Self {
503 let n_params = initial_params.len();
504 let quantum_state = QuantumState::new(n_params, num_quantum_states);
505 let annealing_schedule =
506 QuantumAnnealingSchedule::new(10.0, 0.01, CoolingSchedule::QuantumAdaptive);
507
508 Self {
509 quantum_state,
510 annealing_schedule,
511 best_solution: initial_params.to_owned(),
512 best_objective: f64::INFINITY,
513 iteration: 0,
514 max_nit,
515 function_evaluations: 0,
516 interference_history: VecDeque::with_capacity(1000),
517 entanglement_strength: 1.0,
518 tunneling_events: 0,
519 tolerance: 1e-8,
520 }
521 }
522
523 pub fn optimize<F>(&mut self, objective: F) -> OptimizeResult<OptimizeResults<f64>>
525 where
526 F: Fn(&ArrayView1<f64>) -> f64,
527 {
528 if self.best_objective == f64::INFINITY {
530 self.best_objective = objective(&self.best_solution.view());
531 self.function_evaluations += 1;
532 }
533
534 let mut prev_objective = self.best_objective;
535 let mut stagnation_counter = 0;
536
537 for iteration in 0..self.max_nit {
538 self.iteration = iteration;
539
540 let candidate_params = self.quantum_state.measure();
542 let candidate_objective = objective(&candidate_params.view());
543 self.function_evaluations += 1;
544
545 if candidate_objective < self.best_objective {
547 self.best_objective = candidate_objective;
548 self.best_solution = candidate_params.clone();
549 stagnation_counter = 0;
550 } else {
551 stagnation_counter += 1;
552 }
553
554 let energy_change = candidate_objective - prev_objective;
556 let gradients =
557 self.compute_finite_difference_gradient(&objective, &candidate_params.view())?;
558
559 self.quantum_state.evolve(&gradients, 0.1)?;
561
562 self.annealing_schedule
564 .update(iteration, self.max_nit, energy_change);
565
566 if stagnation_counter > 20 {
568 let barrier_height = self.annealing_schedule.current_temperature;
569 let tunnel_prob = 0.1 * self.annealing_schedule.quantum_fluctuation;
570 self.quantum_state
571 .quantum_tunnel(barrier_height, tunnel_prob)?;
572
573 if rand::rng().random_range(0.0..1.0) < tunnel_prob {
574 self.tunneling_events += 1;
575 stagnation_counter = 0;
576 }
577 }
578
579 if iteration % 50 == 0 {
581 let exploration_radius = self.annealing_schedule.current_temperature * 0.1;
582 self.quantum_state
583 .create_superposition(exploration_radius)?;
584 }
585
586 let interference = self.compute_quantum_interference();
588 self.interference_history.push_back(interference);
589 if self.interference_history.len() > 1000 {
590 self.interference_history.pop_front();
591 }
592
593 self.entanglement_strength = self.compute_entanglement_strength();
595
596 if (prev_objective - candidate_objective).abs() < self.tolerance && iteration > 100 {
598 break;
599 }
600
601 prev_objective = candidate_objective;
602 }
603
604 Ok(OptimizeResults::<f64> {
605 x: self.best_solution.clone(),
606 fun: self.best_objective,
607 success: self.best_objective < f64::INFINITY,
608 nit: self.iteration,
609 message: format!(
610 "Quantum optimization completed. Tunneling events: {}, Final entanglement: {:.3}",
611 self.tunneling_events, self.entanglement_strength
612 ),
613 jac: None,
614 hess: None,
615 constr: None,
616 nfev: self.iteration * self.quantum_state.num_qubits, njev: 0,
618 nhev: 0,
619 maxcv: 0,
620 status: if self.best_objective < f64::INFINITY {
621 0
622 } else {
623 1
624 },
625 })
626 }
627
628 fn compute_finite_difference_gradient<F>(
629 &self,
630 objective: &F,
631 params: &ArrayView1<f64>,
632 ) -> OptimizeResult<Array1<f64>>
633 where
634 F: Fn(&ArrayView1<f64>) -> f64,
635 {
636 let eps = 1e-8;
637 let mut gradient = Array1::zeros(params.len());
638 let base_value = objective(params);
639
640 for i in 0..params.len() {
641 let mut params_plus = params.to_owned();
642 params_plus[i] += eps;
643 let value_plus = objective(¶ms_plus.view());
644
645 gradient[i] = (value_plus - base_value) / eps;
646 }
647
648 Ok(gradient)
649 }
650
651 fn compute_quantum_interference(&self) -> f64 {
652 let mut interference = 0.0;
654 let n_states = self.quantum_state.amplitudes.len();
655
656 for i in 0..n_states {
657 for j in i + 1..n_states {
658 let amp_i = self.quantum_state.amplitudes[i];
659 let amp_j = self.quantum_state.amplitudes[j];
660
661 let interference_term = (amp_i.conjugate() * amp_j).real;
663 interference += interference_term.abs();
664 }
665 }
666
667 interference / (n_states * (n_states - 1) / 2) as f64
668 }
669
670 fn compute_entanglement_strength(&self) -> f64 {
671 let mut total_entanglement = 0.0;
673 let n_params = self.quantum_state.entanglement_matrix.nrows();
674 let mut count = 0;
675
676 for i in 0..n_params {
677 for j in i + 1..n_params {
678 total_entanglement += self.quantum_state.entanglement_matrix[[i, j]].magnitude();
679 count += 1;
680 }
681 }
682
683 if count > 0 {
684 total_entanglement / count as f64
685 } else {
686 0.0
687 }
688 }
689
690 pub fn get_quantum_stats(&self) -> QuantumOptimizationStats {
692 QuantumOptimizationStats {
693 function_evaluations: self.function_evaluations,
694 tunneling_events: self.tunneling_events,
695 current_temperature: self.annealing_schedule.current_temperature,
696 entanglement_strength: self.entanglement_strength,
697 quantum_interference: self.interference_history.back().copied().unwrap_or(0.0),
698 superposition_dimension: self.quantum_state.amplitudes.len(),
699 evolution_time: self.quantum_state.evolution_time,
700 decoherence_level: 1.0
701 - (-self.quantum_state.evolution_time / self.quantum_state.decoherence_time).exp(),
702 }
703 }
704}
705
706#[derive(Debug, Clone)]
708pub struct QuantumOptimizationStats {
709 pub function_evaluations: usize,
710 pub tunneling_events: usize,
711 pub current_temperature: f64,
712 pub entanglement_strength: f64,
713 pub quantum_interference: f64,
714 pub superposition_dimension: usize,
715 pub evolution_time: f64,
716 pub decoherence_level: f64,
717}
718
719#[allow(dead_code)]
721pub fn quantum_optimize<F>(
722 objective: F,
723 initial_params: &ArrayView1<f64>,
724 max_nit: Option<usize>,
725 num_quantum_states: Option<usize>,
726) -> OptimizeResult<OptimizeResults<f64>>
727where
728 F: Fn(&ArrayView1<f64>) -> f64,
729{
730 let max_iter = max_nit.unwrap_or(1000);
731 let num_states = num_quantum_states.unwrap_or(32);
732
733 let mut optimizer = QuantumInspiredOptimizer::new(initial_params, max_iter, num_states);
734 optimizer.optimize(objective)
735}
736
737#[allow(dead_code)]
739pub fn quantum_particle_swarm_optimize<F>(
740 objective: F,
741 initial_params: &ArrayView1<f64>,
742 numparticles: usize,
743 max_nit: usize,
744) -> OptimizeResult<OptimizeResults<f64>>
745where
746 F: Fn(&ArrayView1<f64>) -> f64,
747{
748 let mut particles = Vec::new();
749
750 for _ in 0..numparticles {
752 let particle_optimizer = QuantumInspiredOptimizer::new(initial_params, max_nit, 8);
753 particles.push(particle_optimizer);
754 }
755
756 let mut global_best_solution = initial_params.to_owned();
757 let mut global_best_objective = f64::INFINITY;
758
759 for iteration in 0..max_nit {
760 for particle in &mut particles {
761 for _ in 0..5 {
763 let candidate = particle.quantum_state.measure();
764 let obj_value = objective(&candidate.view());
765
766 if obj_value < particle.best_objective {
767 particle.best_objective = obj_value;
768 particle.best_solution = candidate.clone();
769 }
770
771 if obj_value < global_best_objective {
772 global_best_objective = obj_value;
773 global_best_solution = candidate.clone();
774 }
775
776 let gradients =
778 particle.compute_finite_difference_gradient(&objective, &candidate.view())?;
779 particle.quantum_state.evolve(&gradients, 0.01)?;
780
781 if rand::rng().random_range(0.0..1.0) < 0.1 {
783 let n_params = initial_params.len();
784 for i in 0..n_params.min(particle.quantum_state.basis_states.ncols()) {
785 let entanglement_strength = 0.1;
786 for state_idx in 0..particle.quantum_state.basis_states.nrows() {
787 particle.quantum_state.basis_states[[state_idx, i]] = (1.0
788 - entanglement_strength)
789 * particle.quantum_state.basis_states[[state_idx, i]]
790 + entanglement_strength * global_best_solution[i];
791 }
792 }
793 }
794 }
795 }
796
797 if iteration % 100 == 0 {
799 for particle in &mut particles {
800 particle.quantum_state.quantum_tunnel(1.0, 0.05)?;
801 }
802 }
803 }
804
805 Ok(OptimizeResults::<f64> {
806 x: global_best_solution,
807 fun: global_best_objective,
808 success: global_best_objective < f64::INFINITY,
809 nit: max_nit,
810 message: format!(
811 "Quantum particle swarm optimization completed with {} particles",
812 numparticles
813 ),
814 jac: None,
815 hess: None,
816 constr: None,
817 nfev: max_nit * numparticles, njev: 0,
819 nhev: 0,
820 maxcv: 0,
821 status: if global_best_objective < f64::INFINITY {
822 0
823 } else {
824 1
825 },
826 })
827}
828
829#[cfg(test)]
830mod tests {
831 use super::*;
832
833 #[test]
834 fn test_complex_arithmetic() {
835 let c1 = Complex::new(1.0, 2.0);
836 let c2 = Complex::new(3.0, 4.0);
837
838 let sum = c1 + c2;
839 assert_eq!(sum.real, 4.0);
840 assert_eq!(sum.imag, 6.0);
841
842 let product = c1 * c2;
843 assert_eq!(product.real, -5.0); assert_eq!(product.imag, 10.0); assert!((c1.magnitude() - (5.0_f64).sqrt()).abs() < 1e-10);
847 }
848
849 #[test]
850 fn test_quantum_state_creation() {
851 let state = QuantumState::new(3, 8);
852 assert_eq!(state.num_qubits, 3);
853 assert_eq!(state.amplitudes.len(), 8);
854 assert_eq!(state.basis_states.nrows(), 8);
855 assert_eq!(state.basis_states.ncols(), 3);
856
857 let norm_squared: f64 = state.amplitudes.iter().map(|c| c.magnitude().powi(2)).sum();
859 assert!((norm_squared - 1.0).abs() < 1e-10);
860 }
861
862 #[test]
863 fn test_quantum_measurement() {
864 let state = QuantumState::new(2, 4);
865 let measured_params = state.measure();
866 assert_eq!(measured_params.len(), 2);
867 }
868
869 #[test]
870 fn test_quantum_annealing_schedule() {
871 let mut schedule = QuantumAnnealingSchedule::new(10.0, 0.1, CoolingSchedule::Linear);
872
873 schedule.update(0, 100, 0.0);
874 assert!((schedule.current_temperature - 10.0).abs() < 1e-10);
875
876 schedule.update(50, 100, -1.0);
877 assert!(schedule.current_temperature < 10.0);
878 assert!(schedule.current_temperature > 0.1);
879
880 schedule.update(100, 100, 0.0);
881 assert!((schedule.current_temperature - 0.1).abs() < 1e-10);
882 }
883
884 #[test]
885 fn test_quantum_optimizer_creation() {
886 let initial_params = Array1::from(vec![1.0, 2.0]);
887 let optimizer = QuantumInspiredOptimizer::new(&initial_params.view(), 100, 16);
888
889 assert_eq!(optimizer.best_solution.len(), 2);
890 assert_eq!(optimizer.max_nit, 100);
891 assert_eq!(optimizer.quantum_state.amplitudes.len(), 16);
892 }
893
894 #[test]
895 fn test_quantum_optimization() {
896 let objective = |x: &ArrayView1<f64>| (x[0] - 1.0).powi(2) + (x[1] - 2.0).powi(2);
897 let initial = Array1::from(vec![0.0, 0.0]);
898
899 let result = quantum_optimize(objective, &initial.view(), Some(200), Some(16)).unwrap();
900
901 assert!(result.nit > 0);
902 assert!(result.fun.is_finite());
904 assert!(result.success);
905 assert_eq!(result.x.len(), 2);
906
907 assert!(result.x[0].abs() < 10.0);
909 assert!(result.x[1].abs() < 10.0);
910 }
911
912 #[test]
913 fn test_quantum_tunneling() {
914 let mut state = QuantumState::new(2, 4);
915 let original_states = state.basis_states.clone();
916
917 state.quantum_tunnel(5.0, 1.0).unwrap(); let mut changed = false;
921 for i in 0..state.basis_states.nrows() {
922 for j in 0..state.basis_states.ncols() {
923 if (state.basis_states[[i, j]] - original_states[[i, j]]).abs() > 1e-10 {
924 changed = true;
925 break;
926 }
927 }
928 }
929
930 assert!(changed);
931 }
932
933 #[test]
934 fn test_quantum_particle_swarm() {
935 let objective = |x: &ArrayView1<f64>| x[0].powi(2) + x[1].powi(2);
936 let initial = Array1::from(vec![5.0, 5.0]);
937
938 let result = quantum_particle_swarm_optimize(objective, &initial.view(), 5, 20).unwrap();
939
940 assert!(result.nit > 0);
941 assert!(result.fun < objective(&initial.view()));
942 assert!(result.success);
943 }
944
945 #[test]
946 fn test_quantum_superposition() {
947 let mut state = QuantumState::new(2, 4);
948 state.create_superposition(1.0).unwrap();
949
950 let n_states = state.amplitudes.len();
952 let expected_magnitude = 1.0 / (n_states as f64).sqrt();
953
954 for amp in &state.amplitudes {
955 assert!((amp.magnitude() - expected_magnitude).abs() < 0.1);
956 }
957 }
958
959 #[test]
960 fn test_quantum_evolution() {
961 let mut state = QuantumState::new(2, 4);
962 let gradients = Array1::from(vec![1.0, -1.0]);
963
964 let original_amplitudes = state.amplitudes.clone();
965 state.evolve(&gradients, 0.1).unwrap();
966
967 let mut evolved = false;
969 for i in 0..state.amplitudes.len() {
970 if (state.amplitudes[i].real - original_amplitudes[i].real).abs() > 1e-10
971 || (state.amplitudes[i].imag - original_amplitudes[i].imag).abs() > 1e-10
972 {
973 evolved = true;
974 break;
975 }
976 }
977
978 assert!(evolved);
979 }
980}