radiate_gp/collections/trees/
tree.rs1use crate::{TreeIterator, collections::TreeNode};
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4use std::{fmt::Debug, hash::Hash};
5
6#[derive(Clone, PartialEq, Default)]
115#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
116pub struct Tree<T> {
117 root: Option<TreeNode<T>>,
118}
119
120impl<T> Tree<T> {
121 pub fn new(root: impl Into<TreeNode<T>>) -> Self {
122 Tree {
123 root: Some(root.into()),
124 }
125 }
126
127 pub fn root(&self) -> Option<&TreeNode<T>> {
128 self.root.as_ref()
129 }
130
131 pub fn root_mut(&mut self) -> Option<&mut TreeNode<T>> {
132 self.root.as_mut()
133 }
134
135 pub fn take_root(self) -> Option<TreeNode<T>> {
136 self.root
137 }
138
139 pub fn size(&self) -> usize {
140 self.root.as_ref().map_or(0, |node| node.size())
141 }
142
143 pub fn height(&self) -> usize {
144 self.root.as_ref().map_or(0, |node| node.height())
145 }
146}
147
148impl<T> AsRef<TreeNode<T>> for Tree<T> {
149 fn as_ref(&self) -> &TreeNode<T> {
150 self.root.as_ref().unwrap()
151 }
152}
153
154impl<T> AsMut<TreeNode<T>> for Tree<T> {
155 fn as_mut(&mut self) -> &mut TreeNode<T> {
156 self.root.as_mut().unwrap()
157 }
158}
159
160impl<T: Hash> Hash for Tree<T> {
161 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
162 self.root.hash(state);
163 }
164}
165
166impl<T: Debug> Debug for Tree<T> {
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 writeln!(f, "Tree {{")?;
169 for node in self.iter_breadth_first() {
170 writeln!(f, " {:?}", node)?;
171 }
172 write!(f, "}}")
173 }
174}
175
176#[cfg(test)]
177mod test {
178
179 use super::*;
180 use crate::{Arity, Node, NodeType, Op, TreeCrossover, TreeIterator};
181 use radiate_core::{AlterContext, alter::AlterUpdates};
182
183 #[test]
184 fn test_swap_subtrees() {
185 let mut tree_one = Tree::new(
186 TreeNode::new(Op::add())
187 .attach(TreeNode::new(Op::constant(1.0)))
188 .attach(TreeNode::new(Op::constant(2.0))),
189 );
190
191 let mut tree_two = Tree::new(
192 TreeNode::new(Op::mul())
193 .attach(TreeNode::new(Op::constant(3.0)))
194 .attach(TreeNode::new(Op::constant(4.0))),
195 );
196
197 let copy_one = tree_one.clone();
198 let copy_two = tree_two.clone();
199
200 let mut updates = AlterUpdates::default();
201
202 let mut ctx = AlterContext::new(&mut updates, 0, 1.0, &[]);
203
204 TreeCrossover::cross_nodes(tree_one.as_mut(), tree_two.as_mut(), usize::MAX, &mut ctx);
205
206 let new_one = tree_one.clone();
207 let new_two = tree_two.clone();
208
209 assert_ne!(copy_one, new_one);
211 assert_ne!(copy_two, new_two);
212 }
213
214 #[test]
215 fn test_size() {
216 let tree = Tree::new(
217 TreeNode::new(Op::add())
218 .attach(TreeNode::from(Op::constant(1.0)))
219 .attach(TreeNode::from(Op::constant(2.0))),
220 );
221
222 assert_eq!(tree.size(), 3);
223 }
224
225 #[test]
226 fn test_depth() {
227 let store = vec![
228 (NodeType::Vertex, vec![Op::add(), Op::sub(), Op::mul()]),
229 (NodeType::Leaf, vec![Op::constant(1.0), Op::constant(2.0)]),
230 ];
231
232 let tree = Tree::with_depth(5, store);
233 assert_eq!(tree.height(), 5);
234 }
235
236 #[test]
237 fn test_tree_with_mixed_arity() {
238 let store = vec![
239 (
240 NodeType::Vertex,
241 vec![
242 Op::add(), Op::constant(1.0), Op::sigmoid(), ],
246 ),
247 (NodeType::Leaf, vec![Op::constant(2.0)]),
248 ];
249 let tree = Tree::with_depth(3, store);
250
251 for node in tree.iter_breadth_first() {
253 match node.value() {
254 Op::Fn(name, arity, _) if *name == "add" || *name == "sub" || *name == "mul" => {
255 assert_eq!(**arity, 2, "Binary operator should have arity 2")
256 }
257 Op::Const(_, _) => assert_eq!(*node.arity(), 0, "Constant should have arity 0"),
258 Op::Fn(name, arity, _) if *name == "sigmoid" => {
259 assert!(
260 vec![0, 1, 2].contains(&**arity),
261 "Unary operator should have arity 0 or 1 or 2"
262 )
263 }
264 _ => (), }
266 }
267 }
268
269 #[test]
270 fn test_tree_with_zero_arity() {
271 let store = vec![
272 (NodeType::Vertex, vec![Op::constant(1.0)]), (NodeType::Leaf, vec![Op::constant(2.0)]),
274 ];
275 let tree = Tree::with_depth(2, store);
276
277 for node in tree.iter_breadth_first() {
279 println!("Node: {:?}", node);
280
281 assert_eq!(*node.arity(), 0, "Vertex node should have zero arity");
282 assert!(
283 node.children().is_none(),
284 "Vertex node should have no children"
285 );
286 }
287 }
288
289 #[test]
290 fn test_tree_with_exact_arity() {
291 let store = vec![
292 (NodeType::Vertex, vec![Op::add(), Op::sub()]), (NodeType::Leaf, vec![Op::constant(1.0), Op::constant(2.0)]),
294 ];
295 let tree = Tree::with_depth(2, store);
296
297 for node in tree.iter_breadth_first() {
299 if node.node_type() == NodeType::Vertex {
300 assert_eq!(node.arity(), Arity::Exact(2));
301 assert_eq!(node.children().unwrap().len(), 2);
302 }
303 }
304 }
305
306 #[test]
307 fn test_tree_with_only_leaf_nodes() {
308 let store = vec![(NodeType::Leaf, vec![Op::constant(1.0), Op::constant(2.0)])];
309 let tree = Tree::with_depth(3, store);
310 assert!(tree.root().is_none());
311 assert_eq!(tree.size(), 0);
312 assert_eq!(tree.height(), 0);
313 }
314
315 #[test]
316 fn test_tree_with_empty_store() {
317 let empty_store: Vec<(NodeType, Vec<Op<f32>>)> = vec![];
318 let tree = Tree::with_depth(3, empty_store);
319
320 assert!(tree.root().is_none());
322 assert_eq!(tree.size(), 0);
323 assert_eq!(tree.height(), 0);
324 }
325
326 #[test]
327 fn test_tree_debug() {
328 let tree = Tree::new(
329 TreeNode::new(Op::add())
330 .attach(TreeNode::new(Op::constant(1.0)))
331 .attach(TreeNode::new(Op::constant(2.0))),
332 );
333
334 let debug_str = format!("{:?}", tree);
335 assert!(debug_str.contains("Tree {"));
336 assert!(debug_str.contains("add"));
337 assert!(debug_str.contains("C"));
338 }
339
340 #[test]
341 fn test_tree_as_ref_as_mut() {
342 let mut tree = Tree::new(
343 TreeNode::new(Op::add())
344 .attach(TreeNode::new(Op::constant(1.0)))
345 .attach(TreeNode::new(Op::constant(2.0))),
346 );
347
348 let root_ref: &TreeNode<Op<f32>> = tree.as_ref();
350 assert_eq!(root_ref.value(), &Op::add());
351 assert_eq!(root_ref.children().unwrap().len(), 2);
352
353 let root_mut: &mut TreeNode<Op<f32>> = tree.as_mut();
355 assert_eq!(root_mut.value(), &Op::add());
356
357 root_mut
358 .children_mut()
359 .unwrap()
360 .push(TreeNode::new(Op::constant(3.0))); assert_eq!(root_mut.children().unwrap().len(), 3); }
364
365 #[test]
366 fn test_tree_root_operations() {
367 let mut empty_tree = Tree::<Op<f32>>::default();
369 assert!(empty_tree.root().is_none());
370 assert!(empty_tree.root_mut().is_none());
371 assert!(empty_tree.take_root().is_none());
372
373 let tree = Tree::new(
375 TreeNode::new(Op::add())
376 .attach(TreeNode::new(Op::constant(1.0)))
377 .attach(TreeNode::new(Op::constant(2.0))),
378 );
379
380 let root = tree.root().unwrap();
382 assert_eq!(root.value(), &Op::add());
383 assert_eq!(root.children().unwrap().len(), 2);
384
385 let root = tree.take_root().unwrap();
387 assert_eq!(root.value(), &Op::add());
388 }
389
390 #[test]
391 #[cfg(feature = "serde")]
392 fn test_tree_can_serde() {
393 use crate::Eval;
394
395 let store = vec![
396 (
397 NodeType::Vertex,
398 vec![
399 Op::add(),
400 Op::sub(),
401 Op::mul(),
402 Op::div(),
403 Op::sigmoid(),
404 Op::tanh(),
405 ],
406 ),
407 (
408 NodeType::Leaf,
409 vec![Op::constant(1.0), Op::constant(2.0), Op::var(0)],
410 ),
411 ];
412
413 let tree = Tree::with_depth(5, store);
414
415 let eval_before = tree.eval(&[3.0]);
416
417 let serialized = serde_json::to_string(&tree).expect("Failed to serialize tree");
418 let deserialized: Tree<Op<f32>> =
419 serde_json::from_str(&serialized).expect("Failed to deserialize tree");
420
421 let eval_after = deserialized.eval(&[3.0]);
422
423 assert_eq!(
424 eval_before, eval_after,
425 "Tree evaluation should match before and after serialization"
426 );
427 assert_eq!(tree, deserialized);
428 }
429}