Skip to main content

optde_basic/
optde_basic.rs

1use math_audio_optimisation::{
2    CallbackAction, Crossover, DEConfig, Mutation, PolishConfig, Strategy, differential_evolution,
3};
4use ndarray::Array1;
5use std::sync::Arc;
6
7fn main() {
8    // Ackley function (2D)
9    let ackley = |x: &Array1<f64>| {
10        let x0 = x[0];
11        let x1 = x[1];
12        let s = 0.5 * (x0 * x0 + x1 * x1);
13        let c = 0.5
14            * ((2.0 * std::f64::consts::PI * x0).cos() + (2.0 * std::f64::consts::PI * x1).cos());
15        -20.0 * (-0.2 * s.sqrt()).exp() - c.exp() + 20.0 + std::f64::consts::E
16    };
17
18    let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
19
20    let mut cfg = DEConfig {
21        maxiter: 300,
22        popsize: 20,
23        strategy: Strategy::Best1Bin,
24        crossover: Crossover::Exponential, // demonstrate exponential crossover
25        mutation: Mutation::Range { min: 0.5, max: 1.0 }, // dithering
26        recombination: 0.9,
27        seed: Some(42),
28        ..Default::default()
29    };
30
31    // Penalty examples (here just a dummy inequality fc(x) <= 0):
32    // Circle of radius 3: x0^2 + x1^2 - 9 <= 0
33    cfg.penalty_ineq.push((
34        Arc::new(|x: &Array1<f64>| x[0] * x[0] + x[1] * x[1] - 9.0),
35        1e3,
36    ));
37
38    // Callback every generation: stop early when convergence small enough
39    let mut iter_log = 0usize;
40    cfg.callback = Some(Box::new(move |inter| {
41        if iter_log.is_multiple_of(25) {
42            eprintln!(
43                "iter {:4}  best_f={:.6e}  conv(stdE)={:.3e}",
44                inter.iter, inter.fun, inter.convergence
45            );
46        }
47        iter_log += 1;
48        if inter.convergence < 1e-6 {
49            CallbackAction::Stop
50        } else {
51            CallbackAction::Continue
52        }
53    }));
54
55    // Optional polishing with a local optimizer
56    cfg.polish = Some(PolishConfig {
57        enabled: true,
58        algo: "neldermead".into(),
59        maxeval: 400,
60    });
61
62    let report = differential_evolution(&ackley, &bounds, cfg).expect("optimization failed");
63
64    println!(
65        "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
66        report.success, report.message, report.fun, report.x
67    );
68}