1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
use crate::prelude::*;
use alloc::boxed::Box;

/// A quick interface help to create objective function from a callable object.
///
/// See also [`ObjFunc`] for implementing the full definitions.
///
/// ```
/// use metaheuristics_nature::{Fx, Rga, Solver};
///
/// let bound = [[-50., 50.]; 4];
/// let f = Fx::new(&bound, |&[a, b, c, d]| a * a + 8. * b * b + c * c + d * d);
/// let s = Solver::build(Rga::default(), f)
///     .seed(0)
///     .task(|ctx| ctx.gen == 20)
///     .solve();
/// ```
pub struct Fx<'b, 'f, Y: Fitness, const DIM: usize> {
    bound: &'b [[f64; 2]; DIM],
    #[allow(clippy::type_complexity)]
    func: Box<dyn Fn(&[f64; DIM]) -> Y + Sync + Send + 'f>,
}

impl<'b, 'f, Y: Fitness, const DIM: usize> Fx<'b, 'f, Y, DIM> {
    /// Create objective function from a callable object.
    pub fn new<F>(bound: &'b [[f64; 2]; DIM], func: F) -> Self
    where
        F: Fn(&[f64; DIM]) -> Y + Sync + Send + 'f,
    {
        Self { func: Box::new(func), bound }
    }
}

impl<Y: Fitness, const DIM: usize> Bounded for Fx<'_, '_, Y, DIM> {
    #[inline]
    fn bound(&self) -> &[[f64; 2]] {
        self.bound
    }
}

impl<Y: Fitness, const DIM: usize> ObjFunc for Fx<'_, '_, Y, DIM> {
    type Ys = Y;
    fn fitness(&self, xs: &[f64]) -> Self::Ys {
        (self.func)(xs.try_into().unwrap_or_else(|_| unreachable!()))
    }
}