radiate_gp/collections/graphs/
node.rs

1use crate::node::Node;
2use crate::{Arity, NodeType};
3use radiate::{Gene, Valid};
4use std::collections::BTreeSet;
5use std::fmt::Debug;
6use std::hash::Hash;
7use uuid::Uuid;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum Direction {
11    Forward,
12    Backward,
13}
14
15#[derive(Clone, PartialEq)]
16pub struct GraphNode<T> {
17    value: T,
18    id: Uuid,
19    index: usize,
20    enabled: bool,
21    direction: Direction,
22    node_type: Option<NodeType>,
23    arity: Option<Arity>,
24    incoming: BTreeSet<usize>,
25    outgoing: BTreeSet<usize>,
26}
27
28impl<T> GraphNode<T> {
29    pub fn new(index: usize, node_type: NodeType, value: T) -> Self {
30        GraphNode {
31            id: Uuid::new_v4(),
32            index,
33            value,
34            enabled: true,
35            direction: Direction::Forward,
36            node_type: Some(node_type),
37            arity: None,
38            incoming: BTreeSet::new(),
39            outgoing: BTreeSet::new(),
40        }
41    }
42
43    pub fn with_arity(index: usize, node_type: NodeType, value: T, arity: Arity) -> Self {
44        GraphNode {
45            id: Uuid::new_v4(),
46            index,
47            value,
48            enabled: true,
49            direction: Direction::Forward,
50            node_type: Some(node_type),
51            arity: Some(arity),
52            incoming: BTreeSet::new(),
53            outgoing: BTreeSet::new(),
54        }
55    }
56
57    pub fn direction(&self) -> Direction {
58        self.direction
59    }
60
61    pub fn set_direction(&mut self, direction: Direction) {
62        self.direction = direction;
63    }
64
65    pub fn is_enabled(&self) -> bool {
66        self.enabled
67    }
68
69    pub fn enable(&mut self) {
70        self.enabled = true;
71    }
72
73    pub fn disable(&mut self) {
74        self.enabled = false;
75    }
76
77    pub fn index(&self) -> usize {
78        self.index
79    }
80
81    pub fn id(&self) -> &Uuid {
82        &self.id
83    }
84
85    pub fn is_recurrent(&self) -> bool {
86        self.direction == Direction::Backward
87            || self.incoming.contains(&self.index)
88            || self.outgoing.contains(&self.index)
89    }
90
91    pub fn incoming(&self) -> &BTreeSet<usize> {
92        &self.incoming
93    }
94
95    pub fn outgoing(&self) -> &BTreeSet<usize> {
96        &self.outgoing
97    }
98
99    pub fn incoming_mut(&mut self) -> &mut BTreeSet<usize> {
100        &mut self.incoming
101    }
102
103    pub fn outgoing_mut(&mut self) -> &mut BTreeSet<usize> {
104        &mut self.outgoing
105    }
106
107    pub fn is_locked(&self) -> bool {
108        if self.arity() == Arity::Any {
109            return false;
110        }
111
112        self.incoming.len() == *self.arity()
113    }
114}
115
116impl<T> Node for GraphNode<T> {
117    type Value = T;
118
119    fn value(&self) -> &Self::Value {
120        &self.value
121    }
122
123    fn node_type(&self) -> NodeType {
124        if let Some(node_type) = self.node_type {
125            return node_type;
126        }
127
128        let arity = self.arity();
129
130        if let Arity::Any = arity {
131            if self.outgoing.is_empty() {
132                return NodeType::Output;
133            } else {
134                return NodeType::Vertex;
135            }
136        } else if let Arity::Exact(1) = arity {
137            if self.incoming.len() == 1 && self.outgoing.len() == 1 {
138                return NodeType::Edge;
139            } else {
140                return NodeType::Vertex;
141            }
142        } else if let Arity::Zero = arity {
143            return NodeType::Input;
144        } else {
145            return NodeType::Vertex;
146        }
147    }
148
149    fn arity(&self) -> Arity {
150        if let Some(node_type) = self.node_type {
151            return self.arity.unwrap_or(match node_type {
152                NodeType::Input => Arity::Zero,
153                NodeType::Output => Arity::Any,
154                NodeType::Vertex => Arity::Any,
155                NodeType::Edge => Arity::Exact(1),
156                NodeType::Leaf => Arity::Zero,
157                NodeType::Root => Arity::Any,
158            });
159        }
160
161        self.arity.unwrap_or(Arity::Any)
162    }
163}
164
165impl<T> Gene for GraphNode<T>
166where
167    T: Clone + PartialEq + Default,
168{
169    type Allele = T;
170
171    fn allele(&self) -> &Self::Allele {
172        self.value()
173    }
174
175    fn new_instance(&self) -> GraphNode<T> {
176        GraphNode {
177            id: Uuid::new_v4(),
178            index: self.index,
179            enabled: self.enabled,
180            value: self.value.clone(),
181            direction: self.direction,
182            node_type: self.node_type,
183            arity: self.arity,
184            incoming: self.incoming.clone(),
185            outgoing: self.outgoing.clone(),
186        }
187    }
188
189    fn with_allele(&self, allele: &Self::Allele) -> GraphNode<T> {
190        GraphNode {
191            id: Uuid::new_v4(),
192            index: self.index,
193            value: allele.clone(),
194            enabled: self.enabled,
195            direction: self.direction,
196            node_type: self.node_type,
197            arity: self.arity,
198            incoming: self.incoming.clone(),
199            outgoing: self.outgoing.clone(),
200        }
201    }
202}
203
204impl<T> Valid for GraphNode<T> {
205    fn is_valid(&self) -> bool {
206        match self.node_type() {
207            NodeType::Input => self.incoming.is_empty() && !self.outgoing.is_empty(),
208            NodeType::Output => {
209                (!self.incoming.is_empty())
210                    && (self.incoming.len() == *self.arity() || self.arity() == Arity::Any)
211            }
212            NodeType::Vertex => {
213                if !self.incoming.is_empty() && !self.outgoing.is_empty() {
214                    if let Arity::Exact(n) = self.arity() {
215                        return self.incoming.len() == n;
216                    } else if self.arity() == Arity::Any {
217                        return true;
218                    }
219                }
220                false
221            }
222            NodeType::Edge => {
223                if self.arity() == Arity::Exact(1) {
224                    return self.incoming.len() == 1 && self.outgoing.len() == 1;
225                }
226
227                false
228            }
229            _ => false,
230        }
231    }
232}
233
234impl<T> Into<GraphNode<T>> for (usize, NodeType, T) {
235    fn into(self) -> GraphNode<T> {
236        let (index, node_type, value) = self;
237        GraphNode::new(index, node_type, value)
238    }
239}
240
241impl<T: Default> Into<GraphNode<T>> for (usize, T) {
242    fn into(self) -> GraphNode<T> {
243        let (index, value) = self;
244        GraphNode {
245            index,
246            id: Uuid::new_v4(),
247            value,
248            enabled: true,
249            direction: Direction::Forward,
250            node_type: None,
251            arity: None,
252            incoming: BTreeSet::new(),
253            outgoing: BTreeSet::new(),
254        }
255    }
256}
257
258impl<T: Default> Into<GraphNode<T>> for (usize, NodeType, T, Arity) {
259    fn into(self) -> GraphNode<T> {
260        let (index, node_type, value, arity) = self;
261        GraphNode::with_arity(index, node_type, value, arity)
262    }
263}
264
265impl<T: Default> Into<GraphNode<T>> for (usize, T, Arity) {
266    fn into(self) -> GraphNode<T> {
267        let (index, value, arity) = self;
268        GraphNode {
269            index,
270            id: Uuid::new_v4(),
271            value,
272            enabled: true,
273            direction: Direction::Forward,
274            node_type: None,
275            arity: Some(arity),
276            incoming: BTreeSet::new(),
277            outgoing: BTreeSet::new(),
278        }
279    }
280}
281
282impl<T: Default> Default for GraphNode<T> {
283    fn default() -> Self {
284        GraphNode {
285            id: Uuid::new_v4(),
286            index: 0,
287            enabled: true,
288            value: Default::default(),
289            direction: Direction::Forward,
290            node_type: None,
291            arity: None,
292            incoming: BTreeSet::new(),
293            outgoing: BTreeSet::new(),
294        }
295    }
296}
297
298impl<T: Debug> Debug for GraphNode<T> {
299    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
300        let incoming = self
301            .incoming
302            .iter()
303            .map(|idx| idx.to_string())
304            .collect::<Vec<String>>()
305            .join(", ");
306
307        write!(
308            f,
309            "[{:<3}] {:>10?} :: {:<10} {:<12} E: {:<5} V:{:<5} R:{:<5} {:<2} {:<2} < [{}]",
310            self.index,
311            format!("{:?}", self.node_type())[..3].to_owned(),
312            self.arity(),
313            format!("{:?}", self.value).to_owned(),
314            self.enabled,
315            self.is_valid(),
316            self.is_recurrent(),
317            self.incoming.len(),
318            self.outgoing.len(),
319            incoming,
320        )
321    }
322}
323
324#[cfg(test)]
325mod tests {
326    use super::*;
327    use crate::NodeType;
328    use std::collections::BTreeSet;
329
330    #[test]
331    fn test_graph_node() {
332        let node = GraphNode::new(0, NodeType::Input, 0.0);
333
334        assert_eq!(node.index(), 0);
335        assert_eq!(node.node_type(), NodeType::Input);
336        assert_eq!(node.arity(), Arity::Zero);
337        assert_eq!(node.is_valid(), false);
338        assert_eq!(node.is_enabled(), true);
339        assert_eq!(node.is_recurrent(), false);
340        assert_eq!(node.incoming(), &BTreeSet::new());
341        assert_eq!(node.outgoing(), &BTreeSet::new());
342    }
343
344    #[test]
345    fn test_graph_node_with_arity() {
346        let node = GraphNode::with_arity(0, NodeType::Input, 0.0, Arity::Zero);
347
348        assert_eq!(node.index(), 0);
349        assert_eq!(node.node_type(), NodeType::Input);
350        assert_eq!(node.arity(), Arity::Zero);
351        assert_eq!(node.is_valid(), false);
352        assert_eq!(node.is_enabled(), true);
353        assert_eq!(node.is_recurrent(), false);
354        assert_eq!(node.incoming(), &BTreeSet::new());
355        assert_eq!(node.outgoing(), &BTreeSet::new());
356    }
357
358    #[test]
359    fn test_graph_node_with_allele() {
360        let node = GraphNode::new(0, NodeType::Input, 0.0);
361
362        let new_node = node.with_allele(&1.0);
363        assert_eq!(new_node.index(), 0);
364        assert_eq!(new_node.node_type(), NodeType::Input);
365        assert_eq!(new_node.arity(), Arity::Zero);
366        assert_eq!(new_node.is_valid(), false);
367        assert_eq!(new_node.is_enabled(), true);
368        assert_eq!(new_node.is_recurrent(), false);
369        assert_eq!(new_node.incoming(), &BTreeSet::new());
370        assert_eq!(new_node.outgoing(), &BTreeSet::new());
371    }
372
373    #[test]
374    fn test_graph_node_with_direction() {
375        let mut node = GraphNode::new(0, NodeType::Input, 0.0);
376
377        assert_eq!(node.direction(), Direction::Forward);
378        node.set_direction(Direction::Backward);
379        assert_eq!(node.direction(), Direction::Backward);
380    }
381}