Skip to main content

math_audio_test_functions/functions/
shekel.rs

1//! Shekel test function
2
3use ndarray::Array1;
4
5/// Shekel Function - multimodal function with m local minima
6/// Global minimum depends on m parameter
7/// Bounds: x_i in [0, 10]
8pub fn shekel(x: &Array1<f64>) -> f64 {
9    let m = 10; // Number of local minima
10    let a = [
11        [4.0, 4.0, 4.0, 4.0],
12        [1.0, 1.0, 1.0, 1.0],
13        [8.0, 8.0, 8.0, 8.0],
14        [6.0, 6.0, 6.0, 6.0],
15        [3.0, 7.0, 3.0, 7.0],
16        [2.0, 9.0, 2.0, 9.0],
17        [5.0, 5.0, 3.0, 3.0],
18        [8.0, 1.0, 8.0, 1.0],
19        [6.0, 2.0, 6.0, 2.0],
20        [7.0, 3.6, 7.0, 3.6],
21    ];
22    let c = [0.1, 0.2, 0.2, 0.4, 0.4, 0.6, 0.3, 0.7, 0.5, 0.5];
23
24    let mut sum = 0.0;
25    for i in 0..m.min(10) {
26        let mut inner_sum = 0.0;
27        for j in 0..4.min(x.len()) {
28            inner_sum += (x[j] - a[i][j]).powi(2);
29        }
30        sum += 1.0 / (inner_sum + c[i]);
31    }
32    -sum
33}
34#[cfg(test)]
35mod tests {
36    use super::*;
37
38    #[test]
39    fn test_shekel_known_properties() {
40        use crate::{FunctionMetadata, get_function_metadata};
41        use ndarray::Array1;
42
43        // Get metadata for this function
44        let metadata = get_function_metadata();
45        let meta = metadata
46            .get("shekel")
47            .expect("Function shekel should have metadata");
48
49        // Test 1: Verify global minima are within bounds
50        for (minimum_coords, expected_value) in &meta.global_minima {
51            assert!(
52                minimum_coords.len() >= meta.bounds.len() || meta.bounds.len() == 1,
53                "Global minimum coordinates should match bounds dimensions"
54            );
55
56            for (i, &coord) in minimum_coords.iter().enumerate() {
57                if i < meta.bounds.len() {
58                    let (lower, upper) = meta.bounds[i];
59                    assert!(
60                        coord >= lower && coord <= upper,
61                        "Global minimum coordinate {} = {} should be within bounds [{} {}]",
62                        i,
63                        coord,
64                        lower,
65                        upper
66                    );
67                }
68            }
69        }
70
71        // Test 2: Verify function evaluates to expected values at global minima
72        for (minimum_coords, expected_value) in &meta.global_minima {
73            let x = Array1::from_vec(minimum_coords.clone());
74            let actual_value = shekel(&x);
75
76            let error = (actual_value - expected_value).abs();
77            // Use adaptive tolerance based on magnitude of expected value
78            let tolerance = if expected_value.abs() > 1.0 {
79                1e-4 * expected_value.abs() // Relative tolerance for large values
80            } else {
81                1e-6 // Absolute tolerance for small values
82            };
83
84            assert!(
85                error <= tolerance,
86                "Function value at global minimum {:?} should be {}, got {}, error: {} (tolerance: {})",
87                minimum_coords,
88                expected_value,
89                actual_value,
90                error,
91                tolerance
92            );
93        }
94
95        // Test 3: Basic function properties
96        if !meta.global_minima.is_empty() {
97            let (first_minimum, _) = &meta.global_minima[0];
98            let x = Array1::from_vec(first_minimum.clone());
99            let result = shekel(&x);
100
101            assert!(
102                result.is_finite(),
103                "Function should return finite values at global minimum"
104            );
105            assert!(
106                !result.is_nan(),
107                "Function should not return NaN at global minimum"
108            );
109        }
110    }
111}