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}