use crate::chromosomes::Range as RangeChromosome;
use crate::operations::mutation::gaussian::GaussianConvertible;
use crate::traits::LinearChromosome;
use rand::Rng;
use std::fmt::Debug;
fn mantegna_sigma_u(alpha: f64) -> f64 {
let g1pa = gamma_approx(1.0 + alpha);
let g1pa_half = gamma_approx((1.0 + alpha) / 2.0);
let num = g1pa * (std::f64::consts::PI * alpha / 2.0).sin();
let den = g1pa_half * alpha * 2.0_f64.powf((alpha - 1.0) / 2.0);
(num / den).powf(1.0 / alpha)
}
fn gamma_approx(x: f64) -> f64 {
if x < 1.0 {
return gamma_approx(x + 1.0) / x;
}
if x > 2.0 {
return (x - 1.0) * gamma_approx(x - 1.0);
}
let t = x - 1.0;
1.0 + t * (-0.5748646 + t * (0.9512363 + t * (-0.6998588 + t * (0.4245549 - t * 0.1010678))))
}
pub fn levy_flight_mutation<T>(individual: &mut RangeChromosome<T>, alpha: f64)
where
T: Sync + Send + Clone + Default + Debug + PartialOrd + Copy + 'static + GaussianConvertible,
{
let len = individual.dna().len();
if len == 0 {
return;
}
let mut rng = crate::rng::make_rng();
let idx = rng.random_range(0..len);
let mut gene = individual.dna()[idx].clone();
if gene.ranges.is_empty() {
return;
}
let range_idx = rng.random_range(0..gene.ranges.len());
let (lo, hi) = gene.ranges[range_idx];
let current: f64 = T::to_f64(gene.value);
let lo_f64: f64 = T::to_f64(lo);
let hi_f64: f64 = T::to_f64(hi);
let alpha_clamped = alpha.clamp(0.1, 1.99);
let sigma_u = mantegna_sigma_u(alpha_clamped);
let bu1: f64 = rng.random_range(f64::EPSILON..1.0);
let bu2: f64 = rng.random_range(0.0..std::f64::consts::TAU);
let u_normal: f64 = (-2.0 * bu1.ln()).sqrt() * bu2.cos() * sigma_u;
let bv1: f64 = rng.random_range(f64::EPSILON..1.0);
let bv2: f64 = rng.random_range(0.0..std::f64::consts::TAU);
let v_normal: f64 = (-2.0 * bv1.ln()).sqrt() * bv2.cos();
let v_abs = v_normal.abs().powf(1.0 / alpha_clamped);
let levy_step: f64 = if v_abs < f64::MIN_POSITIVE {
0.0 } else {
u_normal / v_abs
};
let noise: f64 = levy_step * (hi_f64 - lo_f64);
let new_val_f64 = (current + noise).clamp(lo_f64, hi_f64);
gene.value = T::from_f64(new_val_f64);
individual.set_gene(idx, gene);
crate::log_debug!(
target: "mutation_events",
"LevyFlight mutation applied at idx={} range_idx={} alpha={} (clamped {})",
idx, range_idx, alpha, alpha_clamped
);
}