Skip to main content

optde_parallel/
optde_parallel.rs

1use math_audio_optimisation::{
2    DEConfig, Mutation, ParallelConfig, Strategy, differential_evolution,
3};
4use ndarray::Array1;
5use std::time::Instant;
6
7fn main() {
8    // Rastrigin function with artificial compute delay to simulate expensive evaluations
9    let dimension = 10;
10    let rastrigin = move |x: &Array1<f64>| -> f64 {
11        // Add some compute-intensive work to make parallelization beneficial
12        let mut sum = 0.0;
13        for _ in 0..1000 {
14            for &xi in x.iter() {
15                sum += xi.sin().cos().exp().ln_1p();
16            }
17        }
18
19        // Actual Rastrigin function
20        let a = 10.0;
21        let n = x.len() as f64;
22        let result = a * n
23            + x.iter()
24                .map(|&xi| xi * xi - a * (2.0 * std::f64::consts::PI * xi).cos())
25                .sum::<f64>();
26        result + sum * 1e-10 // Add tiny contribution from expensive computation
27    };
28
29    let bounds: Vec<(f64, f64)> = vec![(-5.12, 5.12); dimension];
30
31    // Test sequential evaluation
32    println!("Testing Sequential Evaluation:");
33    let mut cfg_seq = DEConfig::default();
34    cfg_seq.maxiter = 100;
35    cfg_seq.popsize = 15;
36    cfg_seq.strategy = Strategy::Best1Bin;
37    cfg_seq.mutation = Mutation::Factor(0.8);
38    cfg_seq.recombination = 0.9;
39    cfg_seq.seed = Some(42);
40    cfg_seq.disp = true;
41    cfg_seq.parallel.enabled = false; // Disable parallel evaluation
42
43    let start_seq = Instant::now();
44    let report_seq =
45        differential_evolution(&rastrigin, &bounds, cfg_seq).expect("optimization failed");
46    let duration_seq = start_seq.elapsed();
47
48    println!("\nSequential Results:");
49    println!("  Success: {}", report_seq.success);
50    println!("  Best f: {:.6e}", report_seq.fun);
51    println!("  Iterations: {}", report_seq.nit);
52    println!("  Function evaluations: {}", report_seq.nfev);
53    println!("  Time: {:.3} seconds", duration_seq.as_secs_f64());
54
55    // Test parallel evaluation
56    println!("\n\nTesting Parallel Evaluation:");
57    let mut cfg_par = DEConfig::default();
58    cfg_par.maxiter = 100;
59    cfg_par.popsize = 15;
60    cfg_par.strategy = Strategy::Best1Bin;
61    cfg_par.mutation = Mutation::Factor(0.8);
62    cfg_par.recombination = 0.9;
63    cfg_par.seed = Some(42);
64    cfg_par.disp = true;
65    cfg_par.parallel = ParallelConfig {
66        enabled: true,
67        num_threads: None, // Use all available cores
68    };
69
70    let start_par = Instant::now();
71    let report_par =
72        differential_evolution(&rastrigin, &bounds, cfg_par).expect("optimization failed");
73    let duration_par = start_par.elapsed();
74
75    println!("\nParallel Results:");
76    println!("  Success: {}", report_par.success);
77    println!("  Best f: {:.6e}", report_par.fun);
78    println!("  Iterations: {}", report_par.nit);
79    println!("  Function evaluations: {}", report_par.nfev);
80    println!("  Time: {:.3} seconds", duration_par.as_secs_f64());
81
82    // Compare results
83    println!("\n\nComparison:");
84    println!(
85        "  Speedup: {:.2}x",
86        duration_seq.as_secs_f64() / duration_par.as_secs_f64()
87    );
88    println!(
89        "  Result difference: {:.6e}",
90        (report_seq.fun - report_par.fun).abs()
91    );
92
93    // Test with different thread counts
94    println!("\n\nTesting with different thread counts:");
95    for num_threads in [1, 2, 4, 8] {
96        let mut cfg_threads = DEConfig::default();
97        cfg_threads.maxiter = 50;
98        cfg_threads.popsize = 15;
99        cfg_threads.strategy = Strategy::Best1Bin;
100        cfg_threads.mutation = Mutation::Factor(0.8);
101        cfg_threads.recombination = 0.9;
102        cfg_threads.seed = Some(42);
103        cfg_threads.disp = false;
104        cfg_threads.parallel = ParallelConfig {
105            enabled: true,
106            num_threads: Some(num_threads),
107        };
108
109        let start = Instant::now();
110        let _ =
111            differential_evolution(&rastrigin, &bounds, cfg_threads).expect("optimization failed");
112        let duration = start.elapsed();
113
114        println!(
115            "  {} thread(s): {:.3} seconds",
116            num_threads,
117            duration.as_secs_f64()
118        );
119    }
120}