basin/problems/
holder_table.rs1use core::marker::PhantomData;
14
15use super::spec::{Dimensionality, HasSpec, ProblemSpec, Properties, Reference};
16use crate::CostFunction;
17
18pub const STANDARD_LOWER: f64 = -10.0;
20pub const STANDARD_UPPER: f64 = 10.0;
22
23pub fn holder_table(x: &[f64]) -> f64 {
25 debug_assert_eq!(x.len(), 2);
26 let pi = core::f64::consts::PI;
27 let (a, b) = (x[0], x[1]);
28 let inner = (1.0 - (a * a + b * b).sqrt() / pi).abs();
29 -(a.sin() * b.cos() * inner.exp()).abs()
30}
31
32pub struct HolderTable<P = Vec<f64>>(PhantomData<fn() -> P>);
35
36impl<P> HolderTable<P> {
37 pub const fn new() -> Self {
40 Self(PhantomData)
41 }
42}
43
44impl<P> Default for HolderTable<P> {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50pub static HOLDER_TABLE_SPEC: ProblemSpec = ProblemSpec {
52 name: "Holder table",
53 dim: Dimensionality::Fixed(2),
54 properties: Properties {
55 smooth: false,
56 differentiable: false,
57 convex: false,
58 unimodal: false,
59 separable: false,
60 scalable: false,
61 },
62 references: &[Reference {
63 citation: "Jamil & Yang (2013)",
64 title: "A literature survey of benchmark functions for global optimisation problems",
65 source: "International Journal of Mathematical Modelling and Numerical Optimisation, 4(2), 150–194",
66 doi: Some("10.1504/IJMMNO.2013.055204"),
67 url: Some("https://arxiv.org/abs/1308.4008"),
68 }],
69 description: "Multimodal surface with four equal global minima at \
70 (±8.05502, ±9.66459), value ≈ −19.2085, at the corners of a \
71 flat table. Non-differentiable (nested |·| terms); usual \
72 search domain is x, y ∈ [-10, 10]. Cost-only, for \
73 derivative-free / global solvers.",
74};
75
76impl<P> HasSpec for HolderTable<P> {
77 const SPEC: &'static ProblemSpec = &HOLDER_TABLE_SPEC;
78}
79
80impl CostFunction for HolderTable<Vec<f64>> {
81 type Param = Vec<f64>;
82 type Output = f64;
83 type Error = std::convert::Infallible;
84 fn cost(&self, x: &Vec<f64>) -> Result<f64, std::convert::Infallible> {
85 Ok(holder_table(x))
86 }
87}
88
89#[cfg(feature = "nalgebra")]
90mod nalgebra_impl {
91 use super::{HolderTable, holder_table};
92 use crate::CostFunction;
93 use nalgebra::DVector;
94
95 impl CostFunction for HolderTable<DVector<f64>> {
96 type Param = DVector<f64>;
97 type Output = f64;
98 type Error = std::convert::Infallible;
99 fn cost(&self, x: &DVector<f64>) -> Result<f64, std::convert::Infallible> {
100 Ok(holder_table(x.as_slice()))
101 }
102 }
103}
104
105#[cfg(feature = "ndarray")]
106mod ndarray_impl {
107 use super::{HolderTable, holder_table};
108 use crate::CostFunction;
109 use ndarray::Array1;
110
111 impl CostFunction for HolderTable<Array1<f64>> {
112 type Param = Array1<f64>;
113 type Output = f64;
114 type Error = std::convert::Infallible;
115 fn cost(&self, x: &Array1<f64>) -> Result<f64, std::convert::Infallible> {
116 Ok(holder_table(x.as_slice().expect("Array1 is contiguous")))
117 }
118 }
119}
120
121#[cfg(feature = "faer")]
122mod faer_impl {
123 use super::HolderTable;
124 use crate::CostFunction;
125 use faer::Col;
126
127 impl CostFunction for HolderTable<Col<f64>> {
128 type Param = Col<f64>;
129 type Output = f64;
130 type Error = std::convert::Infallible;
131 fn cost(&self, x: &Col<f64>) -> Result<f64, std::convert::Infallible> {
132 debug_assert_eq!(x.nrows(), 2);
133 let pi = core::f64::consts::PI;
134 let (a, b) = (x[0], x[1]);
135 let inner = (1.0 - (a * a + b * b).sqrt() / pi).abs();
136 Ok(-(a.sin() * b.cos() * inner.exp()).abs())
137 }
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn known_value_at_origin() {
147 assert!(holder_table(&[0.0, 0.0]).abs() < 1e-15);
149 }
150
151 #[test]
152 fn minimum_value_at_documented_optimum() {
153 let f = holder_table(&[8.05502, 9.66459]);
154 assert!((f - (-19.2085)).abs() < 1e-3, "got {f}");
155 }
156
157 #[test]
158 fn spec_is_wired_up_via_has_spec_trait() {
159 let spec = <HolderTable<Vec<f64>> as HasSpec>::SPEC;
160 assert_eq!(spec.name, "Holder table");
161 assert!(!spec.properties.differentiable);
162 assert!(matches!(spec.dim, Dimensionality::Fixed(2)));
163 assert!(!spec.references.is_empty());
164 }
165}