Skip to main content

radiate_gp/collections/
eval.rs

1/// [Eval] trait is used to evaluate a [Tree] or [Graph] of node's.
2/// It is implemented directly on the GP structures to allow for easy and dynamic
3/// evaluation of the structures with a given input.
4///
5/// The [Eval] trait and subsequent method is used to transform the `Input` into
6/// the `Output`. This is extremely useful for evaluating the [Graph] or [Tree] with a given input
7/// as traversing each can be very slow or sometimes cumbersome to do manually.
8///
9/// # Example
10/// ```rust
11/// use radiate_gp::{Op, Eval, TreeNode};
12///
13/// let root = TreeNode::new(Op::add())
14///     .attach(
15///         TreeNode::new(Op::mul())
16///             .attach(TreeNode::new(Op::constant(2.0)))
17///             .attach(TreeNode::new(Op::constant(3.0))),
18///     )
19///     .attach(
20///         TreeNode::new(Op::add())
21///             .attach(TreeNode::new(Op::constant(2.0)))
22///             .attach(TreeNode::new(Op::var(0))),
23///     );
24///
25/// // And the result of evaluating this tree with an input of `1` would be:
26/// let result = root.eval(&vec![1_f32]);
27/// assert_eq!(result, 9.0);
28/// ```
29/// This creates a `Tree` that looks like:
30/// ```text
31///      +
32///    /   \
33///   *     +
34///  / \   / \
35/// 2  3  2   x
36/// ```
37/// Where `x` is the first variable in the input.
38///
39/// This can also be thought of (and is functionally equivalent) as:
40/// ```text
41/// f(x) = (2 * 3) + (2 + x)
42/// ```
43pub trait Eval<I: ?Sized, O> {
44    fn eval(&self, input: &I) -> O;
45}
46
47pub trait EvalMut<I: ?Sized, O> {
48    fn eval_mut(&mut self, input: &I) -> O;
49}
50
51impl<I, O, T> EvalMut<I, O> for T
52where
53    I: ?Sized,
54    T: Eval<I, O>,
55{
56    #[inline]
57    fn eval_mut(&mut self, input: &I) -> O {
58        self.eval(input)
59    }
60}
61
62/// [EvalInto] trait is used to evaluate anything that implements the trait into a mutable buffer.
63/// In some cases where we can cache a buffer to write into, this can avoid allocations and massively
64/// improve performance. Just like the [Eval] & [EvalMut] traits the mutable version offers a way for the
65/// implementing type to mutate its internal state if needed. These are also implemented for the GP structures.
66///
67/// # Example
68/// ```rust
69/// use radiate_gp::*;
70///
71/// // Create a simple graph that adds two inputs together
72/// // This is functionaly equivalent to f(x, y) = x + y
73/// let store = node_store! {
74///     Input => vec![Op::var(0), Op::var(1)],
75///     Output => vec![Op::add()]
76/// };
77///
78/// let mut graph = Graph::directed(2, 1, store);
79///
80/// // Define a buffer to store the output
81/// let mut output_buffer = vec![vec![0.0]];
82/// graph.eval_into(&vec![vec![5.0, 10.0]], &mut output_buffer);
83///
84/// // Check the output - it should be 5 + 10 = 15
85/// assert_eq!(output_buffer[0][0], 15.0);
86/// ```
87pub trait EvalInto<I: ?Sized, O: ?Sized> {
88    fn eval_into(&self, input: &I, buffer: &mut O);
89}
90
91pub trait EvalIntoMut<I: ?Sized, O: ?Sized> {
92    fn eval_into_mut(&mut self, input: &I, buffer: &mut O);
93}
94
95impl<I, O, T> EvalIntoMut<I, O> for T
96where
97    I: ?Sized,
98    O: ?Sized,
99    T: EvalInto<I, O>,
100{
101    #[inline]
102    fn eval_into_mut(&mut self, input: &I, buffer: &mut O) {
103        self.eval_into(input, buffer)
104    }
105}
106
107/// --- Blanket Implementations ---
108///
109/// Below are blanket implementations for closures to make it easy to use them
110/// wherever an [Eval] or [EvalInto] is required.
111impl<F, I, O> EvalInto<I, O> for F
112where
113    I: ?Sized,
114    O: ?Sized,
115    F: Fn(&I, &mut O),
116{
117    #[inline]
118    fn eval_into(&self, input: &I, buffer: &mut O) {
119        (self)(input, buffer)
120    }
121}
122
123/// [Eval] implementation for closures that take an input and return an output.
124impl<F, I, O> Eval<I, O> for F
125where
126    I: ?Sized,
127    F: Fn(&I) -> O,
128{
129    #[inline]
130    fn eval(&self, input: &I) -> O {
131        (self)(input)
132    }
133}