1use crate::random::{
64 core::{seeded_rng, Random},
65 distributions::MultivariateNormal,
66 parallel::{ParallelRng, ThreadLocalRngPool},
67};
68use ::ndarray::{s, Array1, Array2, Array3, Axis};
69use rand::Rng;
70use rand_distr::{Distribution, Normal, Uniform};
71use std::collections::HashMap;
72use std::f64::consts::PI;
73
74#[derive(Debug)]
80pub struct QuantumInspiredEvolutionary {
81 population_size: usize,
82 dimension: usize,
83 quantum_population: Array3<f64>, classical_population: Array2<f64>,
85 rotation_angles: Array2<f64>,
86 generation: usize,
87 best_solution: Option<Array1<f64>>,
88 best_fitness: f64,
89}
90
91impl QuantumInspiredEvolutionary {
92 pub fn new(population_size: usize, dimension: usize) -> Self {
94 let mut quantum_pop = Array3::zeros((population_size, dimension, 2));
95
96 let initial_angle = PI / 4.0; for i in 0..population_size {
99 for j in 0..dimension {
100 quantum_pop[[i, j, 0]] = initial_angle.cos(); quantum_pop[[i, j, 1]] = initial_angle.sin(); }
103 }
104
105 Self {
106 population_size,
107 dimension,
108 quantum_population: quantum_pop,
109 classical_population: Array2::zeros((population_size, dimension)),
110 rotation_angles: Array2::zeros((population_size, dimension)),
111 generation: 0,
112 best_solution: None,
113 best_fitness: f64::NEG_INFINITY,
114 }
115 }
116
117 pub fn optimize<F>(
119 &mut self,
120 fitness_function: F,
121 max_generations: usize,
122 ) -> Result<Array1<f64>, String>
123 where
124 F: Fn(&Array1<f64>) -> f64,
125 {
126 let mut rng = seeded_rng(42);
127
128 for generation in 0..max_generations {
129 self.generation = generation;
130
131 self.measure_quantum_population(&mut rng)?;
133
134 let fitness_values = self.evaluate_population(&fitness_function)?;
136
137 for (i, &fitness) in fitness_values.iter().enumerate() {
139 if fitness > self.best_fitness {
140 self.best_fitness = fitness;
141 self.best_solution = Some(self.classical_population.row(i).to_owned());
142 }
143 }
144
145 self.quantum_rotation(&fitness_values)?;
147
148 if generation % 10 == 0 {
150 self.quantum_interference()?;
151 }
152
153 if generation % 50 == 0 {
155 self.quantum_mutation(&mut rng)?;
156 }
157
158 if generation % 100 == 0 {
159 println!(
160 "Generation {}: Best fitness = {:.6}",
161 generation, self.best_fitness
162 );
163 }
164 }
165
166 self.best_solution
167 .clone()
168 .ok_or_else(|| "No solution found".to_string())
169 }
170
171 fn measure_quantum_population(
173 &mut self,
174 rng: &mut Random<rand::rngs::StdRng>,
175 ) -> Result<(), String> {
176 for i in 0..self.population_size {
177 for j in 0..self.dimension {
178 let alpha = self.quantum_population[[i, j, 0]];
179 let beta = self.quantum_population[[i, j, 1]];
180
181 let prob_zero = alpha * alpha;
183
184 let measurement =
186 if rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed")) < prob_zero {
187 0.0
188 } else {
189 1.0
190 };
191
192 self.classical_population[[i, j]] = measurement;
193 }
194 }
195
196 Ok(())
197 }
198
199 fn evaluate_population<F>(&self, fitness_function: &F) -> Result<Vec<f64>, String>
201 where
202 F: Fn(&Array1<f64>) -> f64,
203 {
204 let mut fitness_values = Vec::with_capacity(self.population_size);
205
206 for i in 0..self.population_size {
207 let individual = self.classical_population.row(i).to_owned();
208 let fitness = fitness_function(&individual);
209 fitness_values.push(fitness);
210 }
211
212 Ok(fitness_values)
213 }
214
215 fn quantum_rotation(&mut self, fitness_values: &[f64]) -> Result<(), String> {
217 let best_fitness = fitness_values
218 .iter()
219 .fold(f64::NEG_INFINITY, |a, &b| a.max(b));
220 let best_individual_idx = fitness_values
221 .iter()
222 .position(|&f| f == best_fitness)
223 .unwrap_or(0);
224
225 #[allow(clippy::needless_range_loop)]
226 for i in 0..self.population_size {
227 if i == best_individual_idx {
228 continue; }
230
231 let fitness_ratio = fitness_values[i] / best_fitness.max(1e-10);
232 let base_angle = 0.01 * PI * (1.0 - fitness_ratio); for j in 0..self.dimension {
235 let current_alpha = self.quantum_population[[i, j, 0]];
236 let current_beta = self.quantum_population[[i, j, 1]];
237
238 let best_bit = self.classical_population[[best_individual_idx, j]];
239 let current_bit = self.classical_population[[i, j]];
240
241 let rotation_angle = if current_bit == best_bit {
243 0.0 } else {
245 if best_bit > current_bit {
247 base_angle
248 } else {
249 -base_angle
250 }
251 };
252
253 if rotation_angle.abs() > 1e-10 {
255 let cos_theta = rotation_angle.cos();
256 let sin_theta = rotation_angle.sin();
257
258 let new_alpha = cos_theta * current_alpha - sin_theta * current_beta;
259 let new_beta = sin_theta * current_alpha + cos_theta * current_beta;
260
261 self.quantum_population[[i, j, 0]] = new_alpha;
262 self.quantum_population[[i, j, 1]] = new_beta;
263 }
264
265 self.rotation_angles[[i, j]] = rotation_angle;
266 }
267 }
268
269 Ok(())
270 }
271
272 fn quantum_interference(&mut self) -> Result<(), String> {
274 for i in 0..self.population_size {
276 for j in (i + 1)..self.population_size {
277 let similarity = self.calculate_quantum_similarity(i, j)?;
278
279 if similarity > 0.8 {
280 for k in 0..self.dimension {
282 let alpha_i = self.quantum_population[[i, k, 0]];
283 let beta_i = self.quantum_population[[i, k, 1]];
284 let alpha_j = self.quantum_population[[j, k, 0]];
285 let beta_j = self.quantum_population[[j, k, 1]];
286
287 let new_alpha_i = 0.9 * alpha_i + 0.1 * alpha_j;
289 let new_beta_i = 0.9 * beta_i + 0.1 * beta_j;
290
291 let norm = (new_alpha_i * new_alpha_i + new_beta_i * new_beta_i).sqrt();
293 if norm > 1e-10 {
294 self.quantum_population[[i, k, 0]] = new_alpha_i / norm;
295 self.quantum_population[[i, k, 1]] = new_beta_i / norm;
296 }
297 }
298 }
299 }
300 }
301
302 Ok(())
303 }
304
305 fn calculate_quantum_similarity(&self, i: usize, j: usize) -> Result<f64, String> {
307 let mut similarity = 0.0;
308
309 for k in 0..self.dimension {
310 let alpha_i = self.quantum_population[[i, k, 0]];
311 let beta_i = self.quantum_population[[i, k, 1]];
312 let alpha_j = self.quantum_population[[j, k, 0]];
313 let beta_j = self.quantum_population[[j, k, 1]];
314
315 let fidelity = (alpha_i * alpha_j + beta_i * beta_j).abs();
317 similarity += fidelity;
318 }
319
320 Ok(similarity / self.dimension as f64)
321 }
322
323 fn quantum_mutation(&mut self, rng: &mut Random<rand::rngs::StdRng>) -> Result<(), String> {
325 let mutation_rate = 0.01;
326 let mutation_strength = 0.1;
327
328 for i in 0..self.population_size {
329 for j in 0..self.dimension {
330 if rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed")) < mutation_rate {
331 let random_angle = rng.sample(
333 Uniform::new(-mutation_strength * PI, mutation_strength * PI)
334 .expect("Operation failed"),
335 );
336
337 let current_alpha = self.quantum_population[[i, j, 0]];
338 let current_beta = self.quantum_population[[i, j, 1]];
339
340 let cos_theta = random_angle.cos();
341 let sin_theta = random_angle.sin();
342
343 let new_alpha = cos_theta * current_alpha - sin_theta * current_beta;
344 let new_beta = sin_theta * current_alpha + cos_theta * current_beta;
345
346 self.quantum_population[[i, j, 0]] = new_alpha;
347 self.quantum_population[[i, j, 1]] = new_beta;
348 }
349 }
350 }
351
352 Ok(())
353 }
354
355 pub fn get_best_solution(&self) -> Option<&Array1<f64>> {
357 self.best_solution.as_ref()
358 }
359
360 pub fn get_best_fitness(&self) -> f64 {
362 self.best_fitness
363 }
364}
365
366#[derive(Debug)]
371pub struct QuantumAmplitudeAmplification {
372 target_probability: f64,
373 optimal_iterations: usize,
374 oracle_calls: usize,
375}
376
377impl QuantumAmplitudeAmplification {
378 pub fn new(target_probability: f64) -> Self {
380 let optimal_iterations = ((PI / 4.0) / target_probability.sqrt().asin()).floor() as usize;
382
383 Self {
384 target_probability,
385 optimal_iterations,
386 oracle_calls: 0,
387 }
388 }
389
390 pub fn sample<F>(
392 &mut self,
393 oracle: F,
394 num_samples: usize,
395 seed: u64,
396 ) -> Result<Vec<Array1<f64>>, String>
397 where
398 F: Fn(&Array1<f64>) -> bool, {
400 let mut rng = seeded_rng(seed);
401 let mut target_samples = Vec::new();
402 let dimension = 10; let amplified_attempts = (num_samples as f64 / self.target_probability).ceil() as usize;
406
407 for _ in 0..amplified_attempts {
408 let mut state_amplitudes = Array2::zeros((1 << dimension.min(10), 2)); let amplitude = 1.0 / ((1 << dimension.min(10)) as f64).sqrt();
413 for i in 0..state_amplitudes.nrows() {
414 state_amplitudes[[i, 0]] = amplitude; state_amplitudes[[i, 1]] = 0.0; }
417
418 for _ in 0..self.optimal_iterations {
420 self.apply_oracle(&mut state_amplitudes, &oracle, dimension)?;
422
423 self.apply_diffusion(&mut state_amplitudes)?;
425 }
426
427 let measured_state =
429 self.measure_amplified_state(&state_amplitudes, dimension, &mut rng)?;
430
431 let sample = self.state_to_sample(&measured_state, dimension, &mut rng)?;
433
434 if oracle(&sample) {
436 target_samples.push(sample);
437 if target_samples.len() >= num_samples {
438 break;
439 }
440 }
441 }
442
443 Ok(target_samples)
444 }
445
446 fn apply_oracle<F>(
448 &mut self,
449 amplitudes: &mut Array2<f64>,
450 oracle: &F,
451 dimension: usize,
452 ) -> Result<(), String>
453 where
454 F: Fn(&Array1<f64>) -> bool,
455 {
456 self.oracle_calls += 1;
457
458 for i in 0..amplitudes.nrows() {
459 let sample = self.index_to_sample(i, dimension)?;
461
462 if oracle(&sample) {
464 amplitudes[[i, 0]] = -amplitudes[[i, 0]]; amplitudes[[i, 1]] = -amplitudes[[i, 1]]; }
467 }
468
469 Ok(())
470 }
471
472 fn apply_diffusion(&self, amplitudes: &mut Array2<f64>) -> Result<(), String> {
474 let num_states = amplitudes.nrows();
475
476 let mut avg_real = 0.0;
478 let mut avg_imag = 0.0;
479 for i in 0..num_states {
480 avg_real += amplitudes[[i, 0]];
481 avg_imag += amplitudes[[i, 1]];
482 }
483 avg_real /= num_states as f64;
484 avg_imag /= num_states as f64;
485
486 for i in 0..num_states {
488 amplitudes[[i, 0]] = 2.0 * avg_real - amplitudes[[i, 0]];
489 amplitudes[[i, 1]] = 2.0 * avg_imag - amplitudes[[i, 1]];
490 }
491
492 Ok(())
493 }
494
495 fn measure_amplified_state(
497 &self,
498 amplitudes: &Array2<f64>,
499 dimension: usize,
500 rng: &mut Random<rand::rngs::StdRng>,
501 ) -> Result<usize, String> {
502 let mut probabilities = Vec::with_capacity(amplitudes.nrows());
504 for i in 0..amplitudes.nrows() {
505 let real = amplitudes[[i, 0]];
506 let imag = amplitudes[[i, 1]];
507 let prob = real * real + imag * imag;
508 probabilities.push(prob);
509 }
510
511 let total_prob: f64 = probabilities.iter().sum();
513 if total_prob > 1e-10 {
514 for prob in &mut probabilities {
515 *prob /= total_prob;
516 }
517 }
518
519 let random_val = rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed"));
521 let mut cumulative = 0.0;
522
523 for (i, &prob) in probabilities.iter().enumerate() {
524 cumulative += prob;
525 if random_val <= cumulative {
526 return Ok(i);
527 }
528 }
529
530 Ok(probabilities.len() - 1)
531 }
532
533 fn index_to_sample(&self, index: usize, dimension: usize) -> Result<Array1<f64>, String> {
535 let mut sample = Array1::zeros(dimension);
536
537 for i in 0..dimension.min(10) {
538 let bit = (index >> i) & 1;
539 sample[i] = bit as f64;
540 }
541
542 for i in 10..dimension {
544 sample[i] = ((index as f64) * (i as f64 + 1.0)).sin();
545 }
546
547 Ok(sample)
548 }
549
550 fn state_to_sample(
552 &self,
553 state_index: &usize,
554 dimension: usize,
555 rng: &mut Random<rand::rngs::StdRng>,
556 ) -> Result<Array1<f64>, String> {
557 let mut sample = Array1::zeros(dimension);
558
559 for i in 0..dimension {
561 let base_value = ((*state_index as f64) * (i as f64 + 1.0) * 0.1).sin();
562 let noise = rng.sample(Normal::new(0.0, 0.1).expect("Operation failed"));
563 sample[i] = base_value + noise;
564 }
565
566 Ok(sample)
567 }
568
569 pub fn get_oracle_calls(&self) -> usize {
571 self.oracle_calls
572 }
573}
574
575#[derive(Debug)]
581pub struct QuantumWalk {
582 dimension: usize,
583 position_amplitudes: Array2<f64>, coin_operator: Array2<f64>, step_size: f64,
586 coherence_time: usize,
587}
588
589impl QuantumWalk {
590 pub fn new(dimension: usize, coin_parameters: CoinParameters) -> Self {
592 let num_positions = 2_usize.pow(dimension.min(10) as u32);
593 let mut position_amplitudes = Array2::zeros((num_positions, 2));
594
595 let center = num_positions / 2;
597 position_amplitudes[[center, 0]] = 1.0; let coin_operator = match coin_parameters {
601 CoinParameters::Hadamard => {
602 let mut coin = Array2::zeros((2, 2));
603 let inv_sqrt2 = 1.0 / 2.0_f64.sqrt();
604 coin[[0, 0]] = inv_sqrt2;
605 coin[[0, 1]] = inv_sqrt2;
606 coin[[1, 0]] = inv_sqrt2;
607 coin[[1, 1]] = -inv_sqrt2;
608 coin
609 }
610 CoinParameters::Rotation(angle) => {
611 let mut coin = Array2::zeros((2, 2));
612 coin[[0, 0]] = angle.cos();
613 coin[[0, 1]] = -angle.sin();
614 coin[[1, 0]] = angle.sin();
615 coin[[1, 1]] = angle.cos();
616 coin
617 }
618 CoinParameters::Custom(matrix) => matrix,
619 };
620
621 Self {
622 dimension,
623 position_amplitudes,
624 coin_operator,
625 step_size: 1.0,
626 coherence_time: 1000,
627 }
628 }
629
630 pub fn evolve(
632 &mut self,
633 num_steps: usize,
634 initial_state: Option<usize>,
635 ) -> Result<Vec<usize>, String> {
636 if let Some(initial_pos) = initial_state {
637 self.position_amplitudes.fill(0.0);
639 if initial_pos < self.position_amplitudes.nrows() {
640 self.position_amplitudes[[initial_pos, 0]] = 1.0;
641 }
642 }
643
644 let mut trajectory = Vec::with_capacity(num_steps);
645 let mut rng = seeded_rng(42);
646
647 for step in 0..num_steps {
648 self.quantum_walk_step()?;
650
651 if step % 10 == 0 || step >= num_steps - 1 {
653 let measured_position = self.measure_position(&mut rng)?;
654 trajectory.push(measured_position);
655 }
656
657 if step > 0 && step % self.coherence_time == 0 {
659 self.apply_decoherence(&mut rng)?;
660 }
661 }
662
663 Ok(trajectory)
664 }
665
666 fn quantum_walk_step(&mut self) -> Result<(), String> {
668 let num_positions = self.position_amplitudes.nrows();
669 let mut new_amplitudes = Array2::zeros((num_positions, 2));
670
671 for pos in 0..num_positions {
673 let current_real = self.position_amplitudes[[pos, 0]];
674 let current_imag = self.position_amplitudes[[pos, 1]];
675
676 if current_real.abs() > 1e-10 || current_imag.abs() > 1e-10 {
677 let (left_real, left_imag, right_real, right_imag) =
679 self.apply_coin_operation(current_real, current_imag);
680
681 let left_pos = if pos > 0 { pos - 1 } else { num_positions - 1 };
683 let right_pos = (pos + 1) % num_positions;
684
685 new_amplitudes[[left_pos, 0]] += left_real;
687 new_amplitudes[[left_pos, 1]] += left_imag;
688 new_amplitudes[[right_pos, 0]] += right_real;
689 new_amplitudes[[right_pos, 1]] += right_imag;
690 }
691 }
692
693 self.position_amplitudes = new_amplitudes;
694 Ok(())
695 }
696
697 fn apply_coin_operation(&self, real: f64, imag: f64) -> (f64, f64, f64, f64) {
699 let left_real = self.coin_operator[[0, 0]] * real + self.coin_operator[[0, 1]] * imag;
701 let left_imag = self.coin_operator[[0, 0]] * imag - self.coin_operator[[0, 1]] * real;
702 let right_real = self.coin_operator[[1, 0]] * real + self.coin_operator[[1, 1]] * imag;
703 let right_imag = self.coin_operator[[1, 0]] * imag - self.coin_operator[[1, 1]] * real;
704
705 (left_real, left_imag, right_real, right_imag)
706 }
707
708 fn measure_position<R: Rng>(&self, rng: &mut Random<R>) -> Result<usize, String> {
710 let mut probabilities = Vec::with_capacity(self.position_amplitudes.nrows());
711
712 for i in 0..self.position_amplitudes.nrows() {
714 let real = self.position_amplitudes[[i, 0]];
715 let imag = self.position_amplitudes[[i, 1]];
716 let prob = real * real + imag * imag;
717 probabilities.push(prob);
718 }
719
720 let total_prob: f64 = probabilities.iter().sum();
722 if total_prob > 1e-10 {
723 for prob in &mut probabilities {
724 *prob /= total_prob;
725 }
726 }
727
728 let random_val = rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed"));
730 let mut cumulative = 0.0;
731
732 for (i, &prob) in probabilities.iter().enumerate() {
733 cumulative += prob;
734 if random_val <= cumulative {
735 return Ok(i);
736 }
737 }
738
739 Ok(probabilities.len() - 1)
740 }
741
742 fn apply_decoherence<R: Rng>(&mut self, rng: &mut Random<R>) -> Result<(), String> {
744 let decoherence_strength = 0.1;
745
746 for i in 0..self.position_amplitudes.nrows() {
747 let phase_noise =
749 rng.sample(Normal::new(0.0, decoherence_strength).expect("Operation failed"));
750 let amplitude_noise =
751 rng.sample(Normal::new(0.0, decoherence_strength * 0.1).expect("Operation failed"));
752
753 let real = self.position_amplitudes[[i, 0]];
754 let imag = self.position_amplitudes[[i, 1]];
755
756 let new_real =
758 real * (1.0 + amplitude_noise) * phase_noise.cos() - imag * phase_noise.sin();
759 let new_imag =
760 real * phase_noise.sin() + imag * (1.0 + amplitude_noise) * phase_noise.cos();
761
762 self.position_amplitudes[[i, 0]] = new_real;
763 self.position_amplitudes[[i, 1]] = new_imag;
764 }
765
766 let mut total_prob = 0.0;
768 for i in 0..self.position_amplitudes.nrows() {
769 let real = self.position_amplitudes[[i, 0]];
770 let imag = self.position_amplitudes[[i, 1]];
771 total_prob += real * real + imag * imag;
772 }
773
774 if total_prob > 1e-10 {
775 let norm_factor = total_prob.sqrt();
776 for i in 0..self.position_amplitudes.nrows() {
777 self.position_amplitudes[[i, 0]] /= norm_factor;
778 self.position_amplitudes[[i, 1]] /= norm_factor;
779 }
780 }
781
782 Ok(())
783 }
784
785 pub fn get_probability_distribution(&self) -> Vec<f64> {
787 let mut probabilities = Vec::with_capacity(self.position_amplitudes.nrows());
788
789 for i in 0..self.position_amplitudes.nrows() {
790 let real = self.position_amplitudes[[i, 0]];
791 let imag = self.position_amplitudes[[i, 1]];
792 let prob = real * real + imag * imag;
793 probabilities.push(prob);
794 }
795
796 probabilities
797 }
798}
799
800#[derive(Debug, Clone)]
802pub enum CoinParameters {
803 Hadamard, Rotation(f64), Custom(Array2<f64>), }
807
808type EnergyFunction = Box<dyn Fn(&Array1<f64>) -> f64>;
810
811pub struct QuantumInspiredAnnealing {
813 dimension: usize,
814 temperature_schedule: Vec<f64>,
815 quantum_tunneling_strength: f64,
816 current_state: Array1<f64>,
817 energy_function: Option<EnergyFunction>,
818}
819
820impl QuantumInspiredAnnealing {
821 pub fn new(
823 dimension: usize,
824 initial_temperature: f64,
825 final_temperature: f64,
826 num_steps: usize,
827 ) -> Self {
828 let mut temperature_schedule = Vec::with_capacity(num_steps);
830 for i in 0..num_steps {
831 let t =
832 (final_temperature / initial_temperature).powf(i as f64 / (num_steps - 1) as f64);
833 temperature_schedule.push(initial_temperature * t);
834 }
835
836 Self {
837 dimension,
838 temperature_schedule,
839 quantum_tunneling_strength: 1.0,
840 current_state: Array1::zeros(dimension),
841 energy_function: None,
842 }
843 }
844
845 pub fn with_tunneling_strength(mut self, strength: f64) -> Self {
847 self.quantum_tunneling_strength = strength;
848 self
849 }
850
851 pub fn optimize<F>(
853 &mut self,
854 energy_function: F,
855 initial_state: Array1<f64>,
856 seed: u64,
857 ) -> Result<Array1<f64>, String>
858 where
859 F: Fn(&Array1<f64>) -> f64,
860 {
861 self.current_state = initial_state;
862 let mut rng = seeded_rng(seed);
863 let mut best_state = self.current_state.clone();
864 let mut best_energy = energy_function(&best_state);
865
866 for (step, &temperature) in self.temperature_schedule.iter().enumerate() {
867 let tunneling_probability = self.quantum_tunneling_strength * temperature;
869
870 let proposal_state = if rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed"))
872 < tunneling_probability
873 {
874 self.quantum_tunneling_move(&mut rng)?
876 } else {
877 self.thermal_move(temperature, &mut rng)?
879 };
880
881 let current_energy = energy_function(&self.current_state);
883 let proposal_energy = energy_function(&proposal_state);
884
885 let quantum_acceptance = self.quantum_acceptance_probability(
887 current_energy,
888 proposal_energy,
889 temperature,
890 tunneling_probability,
891 );
892
893 if rng.sample(Uniform::new(0.0, 1.0).expect("Operation failed")) < quantum_acceptance {
895 self.current_state = proposal_state;
896
897 if proposal_energy < best_energy {
899 best_energy = proposal_energy;
900 best_state = self.current_state.clone();
901 }
902 }
903
904 if step % 100 == 0 {
905 println!(
906 "Step {}: Temperature = {:.6}, Best energy = {:.6}",
907 step, temperature, best_energy
908 );
909 }
910 }
911
912 Ok(best_state)
913 }
914
915 fn quantum_tunneling_move<R: Rng>(&self, rng: &mut Random<R>) -> Result<Array1<f64>, String> {
917 let mut new_state = Array1::zeros(self.dimension);
918
919 let tunneling_scale = 2.0 * self.quantum_tunneling_strength;
921
922 for i in 0..self.dimension {
923 let tunneling_distance =
924 rng.sample(Normal::new(0.0, tunneling_scale).expect("Operation failed"));
925 new_state[i] = self.current_state[i] + tunneling_distance;
926 }
927
928 Ok(new_state)
929 }
930
931 fn thermal_move<R: Rng>(
933 &self,
934 temperature: f64,
935 rng: &mut Random<R>,
936 ) -> Result<Array1<f64>, String> {
937 let mut new_state = self.current_state.clone();
938 let step_size = temperature.sqrt();
939
940 for i in 0..self.dimension {
941 let thermal_noise = rng.sample(Normal::new(0.0, step_size).expect("Operation failed"));
942 new_state[i] += thermal_noise;
943 }
944
945 Ok(new_state)
946 }
947
948 fn quantum_acceptance_probability(
950 &self,
951 current_energy: f64,
952 proposal_energy: f64,
953 temperature: f64,
954 tunneling_probability: f64,
955 ) -> f64 {
956 let energy_diff = proposal_energy - current_energy;
957
958 if energy_diff <= 0.0 {
959 1.0
961 } else {
962 let classical_prob = (-energy_diff / temperature).exp();
964
965 let quantum_enhancement =
967 1.0 + tunneling_probability * (-energy_diff / (2.0 * temperature)).exp();
968
969 (classical_prob * quantum_enhancement).min(1.0)
970 }
971 }
972
973 pub fn get_current_state(&self) -> &Array1<f64> {
975 &self.current_state
976 }
977}
978
979#[cfg(test)]
980mod tests {
981 use super::*;
982 use approx::assert_relative_eq;
983
984 #[test]
985 fn test_quantum_inspired_evolutionary() {
986 let mut qiea = QuantumInspiredEvolutionary::new(20, 5);
987
988 let solution = qiea
990 .optimize(|x| -x.iter().map(|xi| xi * xi).sum::<f64>(), 100)
991 .expect("Operation failed");
992
993 assert_eq!(solution.len(), 5);
994 for &val in solution.iter() {
996 assert!(val.abs() < 2.0);
997 }
998 }
999
1000 #[test]
1001 fn test_quantum_amplitude_amplification() {
1002 let mut qaa = QuantumAmplitudeAmplification::new(0.1);
1003
1004 let oracle = |x: &Array1<f64>| x[0] > 0.5;
1006
1007 let samples = qaa.sample(oracle, 10, 42).expect("Operation failed");
1008
1009 for sample in &samples {
1011 assert!(oracle(sample));
1012 }
1013
1014 assert!(qaa.get_oracle_calls() < 100);
1016 }
1017
1018 #[test]
1019 fn test_quantum_walk() {
1020 let mut qwalk = QuantumWalk::new(5, CoinParameters::Hadamard);
1021
1022 let trajectory = qwalk.evolve(50, Some(16)).expect("Operation failed"); assert!(!trajectory.is_empty());
1025
1026 let unique_positions: std::collections::HashSet<_> = trajectory.iter().collect();
1028 assert!(unique_positions.len() > 1);
1029 }
1030
1031 #[test]
1032 fn test_quantum_annealing() {
1033 let mut qa = QuantumInspiredAnnealing::new(2, 1.0, 0.01, 100);
1034
1035 let energy_function = |x: &Array1<f64>| (x[0] - 1.0).powi(2) + (x[1] - 1.0).powi(2);
1037
1038 let initial_state = Array1::from_vec(vec![0.0, 0.0]);
1039 let solution = qa
1040 .optimize(energy_function, initial_state, 42)
1041 .expect("Operation failed");
1042
1043 assert_relative_eq!(solution[0], 1.0, epsilon = 0.5);
1045 assert_relative_eq!(solution[1], 1.0, epsilon = 0.5);
1046 }
1047
1048 #[test]
1049 fn test_coin_parameters() {
1050 let _hadamard_walk = QuantumWalk::new(3, CoinParameters::Hadamard);
1052 let _rotation_walk = QuantumWalk::new(3, CoinParameters::Rotation(PI / 4.0));
1053
1054 let custom_coin =
1055 Array2::from_shape_vec((2, 2), vec![0.8, 0.6, 0.6, -0.8]).expect("Operation failed");
1056 let _custom_walk = QuantumWalk::new(3, CoinParameters::Custom(custom_coin));
1057 }
1058}