Skip to main content

math_audio_test_functions/functions/
power_sum.rs

1//! Power Sum test function
2
3use ndarray::Array1;
4
5/// Power Sum Function - constrained optimization problem
6/// Global minimum: complex, depends on parameters b
7/// Bounds: x_i in [0, d] where d is dimension
8pub fn power_sum(x: &Array1<f64>) -> f64 {
9    let b = [8.0, 18.0, 44.0, 114.0]; // Parameters for up to 4D
10    let d = x.len().min(4);
11
12    let mut sum = 0.0;
13    for i in 1..=d {
14        let power_sum: f64 = x.iter().take(d).map(|&xj| xj.powf(i as f64)).sum();
15        sum += (power_sum - b[i - 1]).powi(2);
16    }
17    sum
18}
19#[cfg(test)]
20mod tests {
21    use super::*;
22
23    #[test]
24    fn test_power_sum_known_properties() {
25        use crate::{FunctionMetadata, get_function_metadata};
26        use ndarray::Array1;
27
28        // Get metadata for this function
29        let metadata = get_function_metadata();
30        let meta = metadata
31            .get("power_sum")
32            .expect("Function power_sum should have metadata");
33
34        // Test 1: Verify global minima are within bounds
35        for (minimum_coords, expected_value) in &meta.global_minima {
36            assert!(
37                minimum_coords.len() >= meta.bounds.len() || meta.bounds.len() == 1,
38                "Global minimum coordinates should match bounds dimensions"
39            );
40
41            for (i, &coord) in minimum_coords.iter().enumerate() {
42                if i < meta.bounds.len() {
43                    let (lower, upper) = meta.bounds[i];
44                    assert!(
45                        coord >= lower && coord <= upper,
46                        "Global minimum coordinate {} = {} should be within bounds [{} {}]",
47                        i,
48                        coord,
49                        lower,
50                        upper
51                    );
52                }
53            }
54        }
55
56        // Test 2: Verify function evaluates to expected values at global minima
57        let tolerance = 1e-6; // Reasonable tolerance for numerical precision
58        for (minimum_coords, expected_value) in &meta.global_minima {
59            let x = Array1::from_vec(minimum_coords.clone());
60            let actual_value = power_sum(&x);
61
62            let error = (actual_value - expected_value).abs();
63            assert!(
64                error <= tolerance,
65                "Function value at global minimum {:?} should be {}, got {}, error: {}",
66                minimum_coords,
67                expected_value,
68                actual_value,
69                error
70            );
71        }
72
73        // Test 3: Basic function properties
74        if !meta.global_minima.is_empty() {
75            let (first_minimum, _) = &meta.global_minima[0];
76            let x = Array1::from_vec(first_minimum.clone());
77            let result = power_sum(&x);
78
79            assert!(
80                result.is_finite(),
81                "Function should return finite values at global minimum"
82            );
83            assert!(
84                !result.is_nan(),
85                "Function should not return NaN at global minimum"
86            );
87        }
88    }
89}