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