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 radiate_core::{AlterContext, alter::AlterUpdates};
180
181 use super::*;
182 use crate::{Arity, Node, NodeType, Op, TreeCrossover, TreeIterator};
183
184 #[test]
185 fn test_swap_subtrees() {
186 let mut tree_one = Tree::new(
187 TreeNode::new(Op::add())
188 .attach(TreeNode::new(Op::constant(1.0)))
189 .attach(TreeNode::new(Op::constant(2.0))),
190 );
191
192 let mut tree_two = Tree::new(
193 TreeNode::new(Op::mul())
194 .attach(TreeNode::new(Op::constant(3.0)))
195 .attach(TreeNode::new(Op::constant(4.0))),
196 );
197
198 let copy_one = tree_one.clone();
199 let copy_two = tree_two.clone();
200
201 let mut updates = AlterUpdates::default();
202
203 let mut ctx = AlterContext::new(&mut updates, 0, 1.0);
204
205 TreeCrossover::cross_nodes(tree_one.as_mut(), tree_two.as_mut(), usize::MAX, &mut ctx);
206
207 let new_one = tree_one.clone();
208 let new_two = tree_two.clone();
209
210 assert_ne!(copy_one, new_one);
212 assert_ne!(copy_two, new_two);
213 }
214
215 #[test]
216 fn test_size() {
217 let tree = Tree::new(
218 TreeNode::new(Op::add())
219 .attach(TreeNode::from(Op::constant(1.0)))
220 .attach(TreeNode::from(Op::constant(2.0))),
221 );
222
223 assert_eq!(tree.size(), 3);
224 }
225
226 #[test]
227 fn test_depth() {
228 let store = vec![
229 (NodeType::Vertex, vec![Op::add(), Op::sub(), Op::mul()]),
230 (NodeType::Leaf, vec![Op::constant(1.0), Op::constant(2.0)]),
231 ];
232
233 let tree = Tree::with_depth(5, store);
234 assert_eq!(tree.height(), 5);
235 }
236
237 #[test]
238 fn test_tree_with_mixed_arity() {
239 let store = vec![
240 (
241 NodeType::Vertex,
242 vec![
243 Op::add(), Op::constant(1.0), Op::sigmoid(), ],
247 ),
248 (NodeType::Leaf, vec![Op::constant(2.0)]),
249 ];
250 let tree = Tree::with_depth(3, store);
251
252 for node in tree.iter_breadth_first() {
254 match node.value() {
255 Op::Fn(name, arity, _) if *name == "add" || *name == "sub" || *name == "mul" => {
256 assert_eq!(**arity, 2, "Binary operator should have arity 2")
257 }
258 Op::Const(_, _) => assert_eq!(*node.arity(), 0, "Constant should have arity 0"),
259 Op::Fn(name, arity, _) if *name == "sigmoid" => {
260 assert!(
261 vec![0, 1, 2].contains(&**arity),
262 "Unary operator should have arity 0 or 1 or 2"
263 )
264 }
265 _ => (), }
267 }
268 }
269
270 #[test]
271 fn test_tree_with_zero_arity() {
272 let store = vec![
273 (NodeType::Vertex, vec![Op::constant(1.0)]), (NodeType::Leaf, vec![Op::constant(2.0)]),
275 ];
276 let tree = Tree::with_depth(2, store);
277
278 for node in tree.iter_breadth_first() {
280 println!("Node: {:?}", node);
281
282 assert_eq!(*node.arity(), 0, "Vertex node should have zero arity");
283 assert!(
284 node.children().is_none(),
285 "Vertex node should have no children"
286 );
287 }
288 }
289
290 #[test]
291 fn test_tree_with_exact_arity() {
292 let store = vec![
293 (NodeType::Vertex, vec![Op::add(), Op::sub()]), (NodeType::Leaf, vec![Op::constant(1.0), Op::constant(2.0)]),
295 ];
296 let tree = Tree::with_depth(2, store);
297
298 for node in tree.iter_breadth_first() {
300 if node.node_type() == NodeType::Vertex {
301 assert_eq!(node.arity(), Arity::Exact(2));
302 assert_eq!(node.children().unwrap().len(), 2);
303 }
304 }
305 }
306
307 #[test]
308 fn test_tree_with_only_leaf_nodes() {
309 let store = vec![(NodeType::Leaf, vec![Op::constant(1.0), Op::constant(2.0)])];
310 let tree = Tree::with_depth(3, store);
311 assert!(tree.root().is_none());
312 assert_eq!(tree.size(), 0);
313 assert_eq!(tree.height(), 0);
314 }
315
316 #[test]
317 fn test_tree_with_empty_store() {
318 let empty_store: Vec<(NodeType, Vec<Op<f32>>)> = vec![];
319 let tree = Tree::with_depth(3, empty_store);
320
321 assert!(tree.root().is_none());
323 assert_eq!(tree.size(), 0);
324 assert_eq!(tree.height(), 0);
325 }
326
327 #[test]
328 fn test_tree_debug() {
329 let tree = Tree::new(
330 TreeNode::new(Op::add())
331 .attach(TreeNode::new(Op::constant(1.0)))
332 .attach(TreeNode::new(Op::constant(2.0))),
333 );
334
335 let debug_str = format!("{:?}", tree);
336 assert!(debug_str.contains("Tree {"));
337 assert!(debug_str.contains("add"));
338 assert!(debug_str.contains("C"));
339 }
340
341 #[test]
342 fn test_tree_as_ref_as_mut() {
343 let mut tree = Tree::new(
344 TreeNode::new(Op::add())
345 .attach(TreeNode::new(Op::constant(1.0)))
346 .attach(TreeNode::new(Op::constant(2.0))),
347 );
348
349 let root_ref: &TreeNode<Op<f32>> = tree.as_ref();
351 assert_eq!(root_ref.value(), &Op::add());
352 assert_eq!(root_ref.children().unwrap().len(), 2);
353
354 let root_mut: &mut TreeNode<Op<f32>> = tree.as_mut();
356 assert_eq!(root_mut.value(), &Op::add());
357
358 root_mut
359 .children_mut()
360 .unwrap()
361 .push(TreeNode::new(Op::constant(3.0))); assert_eq!(root_mut.children().unwrap().len(), 3); }
365
366 #[test]
367 fn test_tree_root_operations() {
368 let mut empty_tree = Tree::<Op<f32>>::default();
370 assert!(empty_tree.root().is_none());
371 assert!(empty_tree.root_mut().is_none());
372 assert!(empty_tree.take_root().is_none());
373
374 let tree = Tree::new(
376 TreeNode::new(Op::add())
377 .attach(TreeNode::new(Op::constant(1.0)))
378 .attach(TreeNode::new(Op::constant(2.0))),
379 );
380
381 let root = tree.root().unwrap();
383 assert_eq!(root.value(), &Op::add());
384 assert_eq!(root.children().unwrap().len(), 2);
385
386 let root = tree.take_root().unwrap();
388 assert_eq!(root.value(), &Op::add());
389 }
390
391 #[test]
392 #[cfg(feature = "serde")]
393 fn test_tree_can_serde() {
394 use crate::Eval;
395
396 let store = vec![
397 (
398 NodeType::Vertex,
399 vec![
400 Op::add(),
401 Op::sub(),
402 Op::mul(),
403 Op::div(),
404 Op::sigmoid(),
405 Op::tanh(),
406 ],
407 ),
408 (
409 NodeType::Leaf,
410 vec![Op::constant(1.0), Op::constant(2.0), Op::var(0)],
411 ),
412 ];
413
414 let tree = Tree::with_depth(5, store);
415
416 let eval_before = tree.eval(&[3.0]);
417
418 let serialized = serde_json::to_string(&tree).expect("Failed to serialize tree");
419 let deserialized: Tree<Op<f32>> =
420 serde_json::from_str(&serialized).expect("Failed to deserialize tree");
421
422 let eval_after = deserialized.eval(&[3.0]);
423
424 assert_eq!(
425 eval_before, eval_after,
426 "Tree evaluation should match before and after serialization"
427 );
428 assert_eq!(tree, deserialized);
429 }
430}