argmin_testfunctions/
matyas.rs

1// Copyright 2018-2024 argmin developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! # Matyas test function
9//!
10//! Defined as
11//!
12//! $$
13//! f(x_1,\\,x_2) = 0.26 (x_1^2 + x_2^2) - 0.48 x_1 x_2
14//! $$
15//!
16//! where $x_i \in [-10,\\,10]$.
17//!
18//! The global minimum is at $f(x_1,\\,x_2) = f(0,\\,0) = 0$.
19
20use num::{Float, FromPrimitive};
21
22/// Matyas test function.
23///
24/// Defined as
25///
26/// $$
27/// f(x_1,\\,x_2) = 0.26 (x_1^2 + x_2^2) - 0.48 x_1 x_2
28/// $$
29///
30/// where $x_i \in [-10,\\,10]$.
31///
32/// The global minimum is at $f(x_1,\\,x_2) = f(0,\\,0) = 0$.
33pub fn matyas<T>(param: &[T; 2]) -> T
34where
35    T: Float + FromPrimitive,
36{
37    let [x1, x2] = *param;
38
39    let n026 = T::from_f64(0.26).unwrap();
40    let n048 = T::from_f64(0.48).unwrap();
41
42    n026 * (x1.powi(2) + x2.powi(2)) - n048 * x1 * x2
43}
44
45/// Derivative of Matyas test function.
46pub fn matyas_derivative<T>(param: &[T; 2]) -> [T; 2]
47where
48    T: Float + FromPrimitive,
49{
50    let [x1, x2] = *param;
51
52    let n0_52 = T::from_f64(0.52).unwrap();
53    let n0_48 = T::from_f64(0.48).unwrap();
54
55    [n0_52 * x1 - n0_48 * x2, n0_52 * x2 - n0_48 * x1]
56}
57
58/// Hessian of Matyas test function.
59///
60/// Returns
61/// $$
62/// \left(
63/// \begin{matrix}
64/// 0.52 & -0.48 \\\\
65/// -0.48 & 0.52
66/// \end{matrix}
67/// \right)
68/// $$
69/// for any input.
70pub fn matyas_hessian<T>(_param: &[T; 2]) -> [[T; 2]; 2]
71where
72    T: Float + FromPrimitive,
73{
74    let n0_52 = T::from_f64(0.52).unwrap();
75    let n0_48 = T::from_f64(0.48).unwrap();
76
77    [[n0_52, -n0_48], [-n0_48, n0_52]]
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    use approx::assert_relative_eq;
84    use finitediff::FiniteDiff;
85    use proptest::prelude::*;
86    use std::{f32, f64};
87
88    #[test]
89    fn test_matyas_optimum() {
90        assert_relative_eq!(matyas(&[0_f32, 0_f32]), 0.0, epsilon = f32::EPSILON);
91        assert_relative_eq!(matyas(&[0_f64, 0_f64]), 0.0, epsilon = f64::EPSILON);
92
93        let deriv = matyas_derivative(&[0.0, 0.0]);
94        for i in 0..2 {
95            assert_relative_eq!(deriv[i], 0.0, epsilon = f64::EPSILON);
96        }
97    }
98
99    proptest! {
100        #[test]
101        fn test_matyas_derivative(a in -10.0..10.0, b in -10.0..10.0) {
102            let param = [a, b];
103            let derivative = matyas_derivative(&param);
104            let derivative_fd = Vec::from(param).central_diff(&|x| matyas(&[x[0], x[1]]));
105            for i in 0..derivative.len() {
106                assert_relative_eq!(
107                    derivative[i],
108                    derivative_fd[i],
109                    epsilon = 1e-5,
110                    max_relative = 1e-2
111                );
112            }
113        }
114    }
115
116    proptest! {
117        #[test]
118        fn test_matyas_hessian(a in -10.0..10.0, b in -10.0..10.0) {
119            let param = [a, b];
120            let hessian = matyas_hessian(&param);
121            let hessian_fd = [[0.52, -0.48], [-0.48, 0.52]];
122            let n = hessian.len();
123            for i in 0..n {
124                assert_eq!(hessian[i].len(), n);
125                for j in 0..n {
126                    assert_relative_eq!(
127                        hessian[i][j],
128                        hessian_fd[i][j],
129                        epsilon = 1e-5,
130                        max_relative = 1e-2
131                    );
132                }
133            }
134        }
135    }
136}