Skip to main content

math_audio_optimisation/
metadata.rs

1//! Tests for metadata-driven optimization examples
2
3#[cfg(test)]
4#[allow(clippy::field_reassign_with_default)]
5mod tests {
6    use crate::{
7        DEConfig, DEConfigBuilder, Mutation, Strategy, differential_evolution,
8        run_recorded_differential_evolution,
9    };
10    use math_audio_test_functions::{get_function_bounds_2d, get_function_bounds_vec, rosenbrock};
11
12    /// Example test showing how to use metadata for bounds
13    #[test]
14    fn test_de_rosenbrock_with_metadata_bounds() {
15        // Use metadata bounds instead of hardcoded ones
16        let bounds = get_function_bounds_2d("rosenbrock", (-5.0, 5.0)); // fallback if not found
17
18        let mut config = DEConfig::default();
19        config.seed = Some(42);
20        config.maxiter = 500;
21        config.popsize = 40;
22        config.recombination = 0.9;
23        config.strategy = Strategy::RandToBest1Exp;
24
25        let result = differential_evolution(&rosenbrock, &bounds, config)
26            .expect("optimization should succeed");
27
28        // Rosenbrock function: Global minimum f(x) = 0 at x = (1, 1)
29        assert!(result.fun < 1e-3);
30
31        // Check that solution is close to expected optimum
32        assert!(
33            (result.x[0] - 1.0).abs() < 0.1,
34            "x[0] should be close to 1.0: {}",
35            result.x[0]
36        );
37        assert!(
38            (result.x[1] - 1.0).abs() < 0.1,
39            "x[1] should be close to 1.0: {}",
40            result.x[1]
41        );
42
43        println!("Used bounds: {:?}", bounds);
44        println!(
45            "Found solution: ({:.4}, {:.4}) with f = {:.6}",
46            result.x[0], result.x[1], result.fun
47        );
48    }
49
50    #[test]
51    fn test_de_rosenbrock_recorded_with_metadata() {
52        // Use metadata bounds for recorded optimization
53        let bounds = get_function_bounds_vec("rosenbrock", (-5.0, 5.0));
54        let config = DEConfigBuilder::new()
55            .seed(123)
56            .maxiter(500)
57            .popsize(40)
58            .strategy(Strategy::RandToBest1Exp)
59            .mutation(Mutation::Factor(0.7))
60            .recombination(0.9)
61            .build()
62            .expect("popsize must be >= 4");
63
64        // Run the recorded optimization (requires AUTOEQ_DIR to be set)
65        let result =
66            run_recorded_differential_evolution("rosenbrock_metadata", rosenbrock, &bounds, config);
67
68        match result {
69            Ok((report, _csv_path)) => {
70                assert!(report.fun < 1e-3);
71
72                // Check that solution is close to expected optimum (1, 1)
73                assert!(
74                    report.x[0] > 0.9 && report.x[0] < 1.1,
75                    "x[0] not close to 1: {}",
76                    report.x[0]
77                );
78                assert!(
79                    report.x[1] > 0.9 && report.x[1] < 1.1,
80                    "x[1] not close to 1: {}",
81                    report.x[1]
82                );
83
84                println!("Used bounds: {:?}", bounds);
85                println!(
86                    "Found solution: ({:.4}, {:.4}) with f = {:.6}",
87                    report.x[0], report.x[1], report.fun
88                );
89            }
90            Err(e) => {
91                panic!(
92                    "Test requires AUTOEQ_DIR to be set. Error: {}\nPlease run: export AUTOEQ_DIR=/path/to/autoeq",
93                    e
94                );
95            }
96        }
97    }
98}