use ndarray::Array1;
pub fn hartman_4d(x: &Array1<f64>) -> f64 {
let a = [
[10.0, 3.0, 17.0, 3.5],
[0.05, 10.0, 17.0, 0.1],
[3.0, 3.5, 1.7, 10.0],
[17.0, 8.0, 0.05, 10.0],
];
let c = [1.0, 1.2, 3.0, 3.2];
let p = [
[0.1312, 0.1696, 0.5569, 0.0124],
[0.2329, 0.4135, 0.8307, 0.3736],
[0.2348, 0.1451, 0.3522, 0.2883],
[0.4047, 0.8828, 0.8732, 0.5743],
];
-c.iter()
.enumerate()
.map(|(i, &ci)| {
let inner_sum = a[i]
.iter()
.zip(p[i].iter())
.enumerate()
.map(|(j, (&aij, &pij))| aij * (x[j] - pij).powi(2))
.sum::<f64>();
ci * (-inner_sum).exp()
})
.sum::<f64>()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hartman_4d_known_properties() {
use crate::{FunctionMetadata, get_function_metadata};
use ndarray::Array1;
let metadata = get_function_metadata();
let meta = metadata
.get("hartman_4d")
.expect("Function hartman_4d should have metadata");
for (minimum_coords, expected_value) in &meta.global_minima {
assert!(
minimum_coords.len() >= meta.bounds.len() || meta.bounds.len() == 1,
"Global minimum coordinates should match bounds dimensions"
);
for (i, &coord) in minimum_coords.iter().enumerate() {
if i < meta.bounds.len() {
let (lower, upper) = meta.bounds[i];
assert!(
coord >= lower && coord <= upper,
"Global minimum coordinate {} = {} should be within bounds [{} {}]",
i,
coord,
lower,
upper
);
}
}
}
for (minimum_coords, expected_value) in &meta.global_minima {
let x = Array1::from_vec(minimum_coords.clone());
let actual_value = hartman_4d(&x);
let error = (actual_value - expected_value).abs();
let tolerance = if expected_value.abs() > 1.0 {
1e-4 * expected_value.abs() } else {
1e-6 };
assert!(
error <= tolerance,
"Function value at global minimum {:?} should be {}, got {}, error: {} (tolerance: {})",
minimum_coords,
expected_value,
actual_value,
error,
tolerance
);
}
if !meta.global_minima.is_empty() {
let (first_minimum, _) = &meta.global_minima[0];
let x = Array1::from_vec(first_minimum.clone());
let result = hartman_4d(&x);
assert!(
result.is_finite(),
"Function should return finite values at global minimum"
);
assert!(
!result.is_nan(),
"Function should not return NaN at global minimum"
);
}
}
}