math_audio_differential_evolution/
impl_helpers.rs

1use crate::{DEReport, DifferentialEvolution};
2use ndarray::{Array1, Array2};
3
4// ------------------------------ Internal helpers ------------------------------
5
6impl<'a, F> DifferentialEvolution<'a, F>
7where
8    F: Fn(&Array1<f64>) -> f64 + Sync,
9{
10    pub(crate) fn energy(&self, x: &Array1<f64>) -> f64 {
11        let base = (self.func)(x);
12        base + self.penalty(x)
13    }
14
15    pub(crate) fn penalty(&self, x: &Array1<f64>) -> f64 {
16        let mut p = 0.0;
17        // Nonlinear ineq: fc(x) <= 0 feasible
18        for (f, w) in &self.config.penalty_ineq {
19            let v = f(x);
20            let viol = v.max(0.0);
21            p += w * viol * viol;
22        }
23        // Nonlinear eq: h(x) = 0
24        for (h, w) in &self.config.penalty_eq {
25            let v = h(x);
26            p += w * v * v;
27        }
28        // Linear penalties: lb <= A x <= ub
29        if let Some(lp) = &self.config.linear_penalty {
30            let ax = lp.a.dot(&x.view());
31            for i in 0..ax.len() {
32                let v = ax[i];
33                let lo = lp.lb[i];
34                let hi = lp.ub[i];
35                if v < lo {
36                    let d = lo - v;
37                    p += lp.weight * d * d;
38                }
39                if v > hi {
40                    let d = v - hi;
41                    p += lp.weight * d * d;
42                }
43            }
44        }
45        p
46    }
47
48    #[allow(clippy::too_many_arguments)]
49    pub(crate) fn finish_report(
50        &self,
51        pop: Array2<f64>,
52        energies: Array1<f64>,
53        x: Array1<f64>,
54        fun: f64,
55        success: bool,
56        message: String,
57        nit: usize,
58        nfev: usize,
59    ) -> DEReport {
60        DEReport {
61            x,
62            fun,
63            success,
64            message,
65            nit,
66            nfev,
67            population: pop,
68            population_energies: energies,
69        }
70    }
71
72    pub(crate) fn polish(&self, x0: &Array1<f64>) -> (Array1<f64>, f64, usize) {
73        // Simple polish: just return the input solution (polishing disabled)
74        // In a full implementation, this would use a local optimizer like Nelder-Mead
75        let f = self.energy(x0);
76        (x0.clone(), f, 1)
77    }
78}