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