adic_shape/shape/
tree_shape.rs

1use std::iter::{once, repeat};
2use adic::AdicInteger;
3use petgraph::{
4    graph::{EdgeIndex, NodeIndex},
5    visit::{EdgeRef, NodeRef},
6    Directed, Graph
7};
8
9use crate::{AdicShapeError, DisplayShape};
10use super::{
11    element::{AdicEl, PathDInstruction, PathEl},
12    Direction,
13};
14
15
16/// List of branch choices that should be drawn in gold
17type GoldBranchChoices = Vec<u32>;
18type Coordinate = (f64, f64);
19
20use Direction::{Left, Right, Up, Down};
21
22
23pub type TreeGraph = Graph<TreeNode, TreeEdge, Directed>;
24
25
26#[derive(Debug, Clone)]
27/// Tree shape for drawing
28///
29/// ```
30/// # use adic::radic;
31/// # use adic_shape::{Direction, TreeShape, TreeShapeOptions};
32/// let a = radic!(5, [1, 2, 3, 4], [0, 3]);
33/// let depth = 20;
34/// let shape_options = TreeShapeOptions{
35///     direction: Direction::Up,
36///     ..Default::default()
37/// };
38/// let tree_shape = TreeShape::zoomed_tree(&a, depth, shape_options);
39/// ```
40#[doc = ""]
41#[doc = "<style>"]
42#[doc = include_str!("../../img/rustdoc.css")]
43#[doc = "</style>"]
44#[doc = ""]
45#[doc = include_str!("../../img/tree-shape-example.svg")]
46#[doc = ""]
47pub struct TreeShape {
48    /// Number of ticks on the clock
49    p: u32,
50    /// Options for creating `TreeShape`
51    options: TreeShapeOptions,
52    /// Tree position
53    position: TreePosition,
54    /// Stores the tree information
55    graph: TreeGraph,
56    /// Root node index of the tree
57    root_idx: NodeIndex<u32>,
58    /// Index for node dangling from root node of the tree
59    dangling_idx: Option<NodeIndex<u32>>,
60    /// Special branches colored differently, e.g. to indicate a path through the tree
61    gold_branches: Vec<GoldBranchChoices>,
62}
63
64
65#[derive(Debug, Clone, Copy)]
66/// Options for creating tree shape
67pub struct TreeShapeOptions {
68    /// Direction the tree is growing
69    pub direction: Direction,
70    /// Direction that node is dangling from root node of the tree
71    pub dangling_direction: Option<Direction>,
72    /// Width of the tree window
73    pub viewbox_width: u32,
74    /// Height of the tree window
75    pub viewbox_height: u32,
76}
77
78impl Default for TreeShapeOptions {
79    fn default() -> Self {
80        TreeShapeOptions {
81            direction: Up,
82            dangling_direction: Some(Right),
83            viewbox_width: 100,
84            viewbox_height: 100,
85        }
86    }
87}
88
89
90#[derive(Debug, Clone, Copy)]
91/// Tree layout information
92pub struct TreePosition {
93    /// Position of center of the tree
94    pub center: Coordinate,
95}
96
97
98impl TreeShape {
99
100    /// `TreeShape` showing a full tree with no special branches
101    ///
102    /// # Errors
103    /// Errors for (1) integer conversion failure, (2) inconsistent directions, and (3) petgraph inconsistency
104    ///
105    /// <div class="warning">
106    ///
107    /// This full tree uses a LOT of lines if the depth is large, on the order of `p^depth`.
108    /// Consider using [`zoomed_tree`](Self::zoomed_tree) instead.
109    ///
110    /// </div>
111    pub fn full_tree(
112        p: u32,
113        depth: usize,
114        options: TreeShapeOptions,
115    ) -> Result<Self, AdicShapeError> {
116
117        let TreeShapeOptions { direction, dangling_direction, .. } = options;
118
119        let (mut graph, root_idx, dangling_idx) = create_tree_graph(p, depth, direction, dangling_direction)?;
120
121        let width = f64::from(options.viewbox_width);
122        let height = f64::from(options.viewbox_height);
123        adjust_size(&mut graph, direction, width, height);
124
125        Ok(Self {
126            p,
127            position: TreePosition {
128                center: (0.5*width, 0.5*height),
129            },
130            graph,
131            root_idx,
132            dangling_idx,
133            options,
134            gold_branches: vec![],
135        })
136
137    }
138
139    /// `TreeShape` showing a full tree with a gold branch showing `adic_data`
140    ///
141    /// # Errors
142    /// Errors for (1) integer conversion failure, (2) inconsistent directions, and (3) petgraph inconsistency
143    ///
144    /// <div class="warning">
145    ///
146    /// This full tree uses a LOT of lines if the depth is large, on the order of `p^depth`.
147    /// Consider using [`zoomed_tree`](Self::zoomed_tree) instead.
148    ///
149    /// </div>
150    pub fn adic_number_full_tree(
151        adic_data: &impl AdicInteger,
152        depth: usize,
153        options: TreeShapeOptions,
154    ) -> Result<Self, AdicShapeError> {
155
156        let p = adic_data.p();
157        let TreeShapeOptions { direction, dangling_direction, .. } = options;
158
159        let (mut graph, root_idx, dangling_idx) = create_tree_graph(p, depth, direction, dangling_direction)?;
160
161        let width = f64::from(options.viewbox_width);
162        let height = f64::from(options.viewbox_height);
163        adjust_size(&mut graph, direction, width, height);
164
165        Ok(Self {
166            p,
167            position: TreePosition {
168                center: (0.5*width, 0.5*height),
169            },
170            graph,
171            root_idx,
172            dangling_idx,
173            options,
174            gold_branches: vec![adic_data.digits().take(depth).copied().collect()]
175        })
176
177    }
178
179    /// `TreeShape` showing a zoomed tree, only fully following the `adic_data` branch choice
180    ///
181    /// # Errors
182    /// Errors for (1) integer conversion failure, (2) inconsistent directions, and (3) petgraph inconsistency
183    pub fn zoomed_tree(
184        adic_data: &impl AdicInteger,
185        depth: usize,
186        options: TreeShapeOptions,
187    ) -> Result<Self, AdicShapeError> {
188
189        let p = adic_data.p();
190        let TreeShapeOptions { direction, dangling_direction, .. } = options;
191
192        let (mut graph, root_idx, dangling_idx) = create_zoomed_tree_graph(adic_data.clone(), depth, direction, dangling_direction)?;
193
194        let width = f64::from(options.viewbox_width);
195        let height = f64::from(options.viewbox_height);
196        adjust_size(&mut graph, direction, width, height);
197
198        Ok(Self {
199            p,
200            position: TreePosition {
201                center: (0.5*width, 0.5*height),
202            },
203            graph,
204            root_idx,
205            dangling_idx,
206            options,
207            gold_branches: vec![adic_data.digits().take(depth).copied().collect()]
208        })
209
210    }
211
212
213    /// Number of branches from each branch point
214    pub fn p(&self) -> u32 {
215        self.p
216    }
217
218    /// Centerpoint for the tree
219    pub fn center(&self) -> (f64, f64) {
220        self.position.center
221    }
222
223    /// Path instructions (Move and Line) to draw the base tree
224    ///
225    /// # Errors
226    /// Errors if graph gets into a bad state
227    fn tree_instructions(&self) -> Result<Vec<PathDInstruction>, AdicShapeError> {
228
229        let mut instructions = vec![];
230        for e in self.graph.edge_references() {
231            let source = self.graph.node_weight(e.source()).ok_or(AdicShapeError::PetGraph)?;
232            let target = self.graph.node_weight(e.target()).ok_or(AdicShapeError::PetGraph)?;
233            instructions.push(PathDInstruction::Move((source.x, source.y)));
234            instructions.push(PathDInstruction::Line((target.x, target.y)));
235        }
236
237        Ok(instructions)
238
239    }
240
241
242    /// Path instructions (Move and Line) to draw the gold branches
243    ///
244    /// # Errors
245    /// Errors if graph gets into a bad state
246    fn gold_branch_instructions(&self) -> Result<Vec<Vec<PathDInstruction>>, AdicShapeError> {
247
248        let mut all_instructions = vec![];
249        for gold_branch_choices in &self.gold_branches {
250
251            let (mut node_id, choices) = if let Some(dangling_idx) = self.dangling_idx {
252                let mut choices = vec![0];
253                choices.extend(gold_branch_choices);
254                (dangling_idx, choices)
255            } else {
256                (self.root_idx, gold_branch_choices.clone())
257            };
258
259            let mut instructions = vec![];
260            for gold_choice in choices.into_iter().chain(repeat(0)) {
261                let mut edges = self.graph.edges(node_id);
262                let gold_edge = edges.find(|e| e.weight().branch_choice == gold_choice);
263                if let Some(ge) = gold_edge {
264                    node_id = ge.target().id();
265                    let source = self.graph.node_weight(ge.source()).ok_or(AdicShapeError::PetGraph)?;
266                    let target = self.graph.node_weight(ge.target()).ok_or(AdicShapeError::PetGraph)?;
267                    instructions.push(PathDInstruction::Move((source.x, source.y)));
268                    instructions.push(PathDInstruction::Line((target.x, target.y)));
269                } else {
270                    break;
271                }
272            }
273            all_instructions.push(instructions);
274
275        }
276
277        Ok(all_instructions)
278
279    }
280
281}
282
283impl DisplayShape for TreeShape {
284
285    /// Internal SVG elements generated from this shape
286    fn adic_els(&self) -> impl Iterator<Item=AdicEl> {
287
288        // Draw the tree
289        let tree_ins = self.tree_instructions().expect("tree instructions should succeed");
290        let tree_path = AdicEl::Path(PathEl{
291            class: Some("tree-path".to_string()),
292            d: tree_ins
293        });
294        // Draw the labels
295        // let labels = labeller.labels(&tree_diagram, num_depth, num_branch, Default::default());
296
297        // Draw the gold paths
298        let gold_paths = self.gold_branch_instructions()
299            .expect("gold branch instructions should succeed")
300            .into_iter()
301            .map(
302                |gold_ins| AdicEl::Path(PathEl{
303                    class: Some("gold-path".to_string()),
304                    d: gold_ins
305                })
306            )
307            .collect::<Vec<_>>();
308
309        // Wrap in svg
310        once(tree_path)
311            // .chain(labels)
312            .chain(gold_paths)
313
314    }
315
316    fn default_class(&self) -> String {
317        "adic-tree".to_string()
318    }
319
320    fn viewbox_width(&self) -> u32 {
321        self.options.viewbox_width
322    }
323    fn viewbox_height(&self) -> u32 {
324        self.options.viewbox_height
325    }
326}
327
328
329#[derive(Debug, Clone)]
330/// Data for each tree node, i.e. branch splitting
331pub struct TreeNode {
332    /// x-value for node
333    pub x: f64,
334    /// y-value for node
335    pub y: f64,
336    /// Depth into the directed tree, i.e. displacement from root node
337    pub depth: isize,
338}
339
340#[derive(Debug, Clone)]
341/// Data for each tree edge, i.e. branch
342pub struct TreeEdge {
343    /// Which branch is selected, going from the source to target
344    pub branch_choice: u32,
345}
346
347
348/// Adjust x & y for width and height
349fn adjust_size(graph: &mut TreeGraph, direction: Direction, width: f64, height: f64) {
350    match direction {
351        Up | Down => {
352            graph.node_weights_mut().for_each(|n| {
353                n.x = width * n.x;
354                n.y = height * n.y;
355            });
356        },
357        Left | Right => {
358            graph.node_weights_mut().for_each(|n| {
359                n.x = width * n.x;
360                n.y = height * n.y;
361            });
362        },
363    }
364}
365
366
367/// Create a "full tree graph", plotting the ENTIRE tree of possible adic numbers
368///
369/// # Errors
370/// Errors for (1) integer conversion failure, (2) inconsistent directions, and (3) petgraph inconsistency
371fn create_tree_graph(
372    p: u32,
373    depth: usize,
374    direction: Direction,
375    dangling_direction: Option<Direction>
376) -> Result<(TreeGraph, NodeIndex, Option<NodeIndex>), AdicShapeError> {
377
378    let mut graph = Graph::new();
379    let (root_length, reg_length) = calc_branch_lengths(p, depth, dangling_direction)?;
380    let (root_idx, dangling_idx) = root_tree(&mut graph, direction, dangling_direction, root_length)?;
381
382    let mut cur_branch_point = root_idx;
383    let mut cur_branch_choice = 0;
384    let mut cur_width = 1.;
385    let mut cur_node = graph.node_weight(cur_branch_point).ok_or(AdicShapeError::PetGraph)?;
386    let mut cur_edge_set: Vec<EdgeIndex> = vec![];
387    'tree_pos_loop: loop {
388
389        // If current depth is less than max, go deeper
390        if cur_node.depth < depth.try_into()? {
391
392            let adjust_choice = ((f64::from(cur_branch_choice) + 0.5) / f64::from(p) - 0.5) * cur_width;
393            let adjust_depth = reg_length;
394
395            let (new_idx, edge_idx) = add_relative_branch(
396                &mut graph, cur_branch_point, cur_branch_choice,
397                direction, adjust_choice, adjust_depth,
398            )?;
399
400            cur_branch_point = new_idx;
401            cur_branch_choice = 0;
402            cur_width = cur_width / f64::from(p);
403            cur_node = graph.node_weight(new_idx).ok_or(AdicShapeError::PetGraph)?;
404            cur_edge_set.push(edge_idx);
405
406        }
407        // Else, pop up until the next branch choice is available or we're done with the graph
408        else {
409
410            while (cur_node.depth >= depth.try_into()?) || (cur_branch_choice == p - 1) {
411
412                // If we're at the root, we're done
413                if cur_node.depth == 0 {
414                    break 'tree_pos_loop;
415                }
416
417                let old_edge_idx = cur_edge_set.pop().ok_or(AdicShapeError::PetGraph)?;
418                cur_branch_point = graph.edge_endpoints(old_edge_idx).ok_or(AdicShapeError::PetGraph)?.0;
419                cur_branch_choice = graph.edge_weight(old_edge_idx).ok_or(AdicShapeError::PetGraph)?.branch_choice;
420                cur_width = cur_width * f64::from(p);
421
422                cur_node = graph.node_weight(cur_branch_point).ok_or(AdicShapeError::PetGraph)?;
423
424            }
425
426            cur_branch_choice += 1;
427
428        }
429
430    }
431
432    Ok((graph, root_idx, dangling_idx))
433
434}
435
436
437/// Create a "zoomed tree graph", following the digits of `adic_data` without plotting the ENTIRE tree
438///
439/// # Errors
440/// Errors for (1) integer conversion failure, (2) inconsistent directions, and (3) petgraph inconsistency
441fn create_zoomed_tree_graph(
442    adic_data: impl AdicInteger,
443    depth: usize,
444    direction: Direction,
445    dangling_direction: Option<Direction>
446) -> Result<(TreeGraph, NodeIndex, Option<NodeIndex>), AdicShapeError> {
447
448    let p = adic_data.p();
449
450    let mut graph = Graph::new();
451    let (root_length, reg_length) = calc_branch_lengths(p, depth, dangling_direction)?;
452    let (root_idx, dangling_idx) = root_tree(&mut graph, direction, dangling_direction, root_length)?;
453
454    let mut next_branch_point = root_idx;
455    let mut next_choice_pos = 0.5;
456    let choices = adic_data.into_digits().chain(repeat(0)).take(depth-1);
457    for (num_digit, choice) in choices.into_iter().enumerate() {
458
459        let cur_branch_point = next_branch_point;
460        let cur_choice_pos = next_choice_pos;
461        next_choice_pos = (f64::from(choice) + 0.5) / f64::from(p);
462        let branch_width = 1.;
463        let branch_length = reg_length;
464        let unchosen_width_scale = 0.4;
465        let unchosen_length_scale = 0.6;
466        let twig_width_scale = 0.05;
467        let twig_length_scale = 0.2;
468
469        // Draw branches from current branch point up for each possible choice
470        for branch in (0..p) {
471
472            // Add node and edge from branch point to the possibility
473            let new_width =  branch_width * if branch == choice { 1. } else { unchosen_width_scale };
474            let new_length = branch_length * if branch == choice { 1. } else { unchosen_length_scale };
475
476            let adjust_choice = ((f64::from(branch) + 0.5) / f64::from(p) - 0.5) * new_width;
477            let adjust_choice = adjust_choice + if branch == choice {
478                (0.5 - cur_choice_pos)
479            } else {
480                let main_branch_adjust = unchosen_length_scale * (next_choice_pos - cur_choice_pos);
481                let choice_adjust = (0.5 * f64::from(p-1) - f64::from(choice)) / f64::from(p) * branch_width * unchosen_width_scale;
482                main_branch_adjust + choice_adjust
483            };
484            let adjust_depth = new_length;
485
486            let (next_idx, _edge_idx) = add_relative_branch(
487                &mut graph, cur_branch_point, branch,
488                direction, adjust_choice, adjust_depth,
489            )?;
490
491            // Add short branches for every sub-choice if it's not the RIGHT choice
492            if branch == choice {
493
494                if num_digit + 2 == depth {
495                    // Add one more fan of short branches for last choice
496                    for twig_choice in (0..p) {
497                        let final_choice_pos = cur_choice_pos;
498                        let twig_width = branch_width * twig_width_scale;
499                        let adjust_choice = ((f64::from(twig_choice) + 0.5) / f64::from(p) - 0.5) * twig_width;
500                        let adjust_choice = adjust_choice + twig_width * (0.5 - final_choice_pos);
501                        let adjust_depth = branch_length * twig_length_scale;
502                        let (_leaf_idx, _twig_idx) = add_relative_branch(
503                            &mut graph, next_idx, twig_choice,
504                            direction, adjust_choice, adjust_depth,
505                        )?;
506                    }
507                } else {
508                    next_branch_point = next_idx;
509                }
510
511            } else {
512
513                for twig_choice in (0..p) {
514
515                    let adjust_choice = ((f64::from(twig_choice) + 0.5) / f64::from(p) - 0.5) * branch_width * twig_width_scale;
516                    let adjust_depth = branch_length * twig_length_scale;
517                    let (_leaf_idx, _twig_idx) = add_relative_branch(
518                        &mut graph, next_idx, twig_choice,
519                        direction, adjust_choice, adjust_depth,
520                    )?;
521
522                }
523
524            }
525
526        }
527
528    }
529
530    Ok((graph, root_idx, dangling_idx))
531
532}
533
534
535/// Calculate `reg_length` and `root_length` of tree
536///
537/// # Errors
538/// Errors for integer conversion failure
539fn calc_branch_lengths(
540    p: u32, num_levels: usize, dangling_direction: Option<Direction>
541) -> Result<(f64, f64), AdicShapeError> {
542    let f64_levels = f64::from(u32::try_from(num_levels)?);
543    if dangling_direction.is_some() {
544        // Root has a larger angle, smaller length
545        // root_length * (p - 1)/2 = reg_length
546        // root_length + reg_length * num_levels = 1
547        // root_length * (1 + (p - 1) / 2 * num_levels) = 1
548        let root_length = 2.  / (2. + (f64::from(p) - 1.) * f64_levels);
549        let reg_length = (1. - root_length) / f64_levels;
550        Ok((root_length, reg_length))
551    } else {
552        let root_length = 0.;
553        let reg_length = 1. / f64_levels;
554        Ok((root_length, reg_length))
555    }
556}
557
558/// Add root node and possibly dangling node if `dangling_direction` is given
559///
560/// # Errors
561/// Error if `root_direction` is inconsistent with `direction`, i.e. in the SAME direction
562fn root_tree(
563    graph: &mut TreeGraph, direction: Direction, dangling_direction: Option<Direction>,
564    root_length: f64,
565) -> Result<(NodeIndex, Option<NodeIndex>), AdicShapeError> {
566
567    if let Some(root_direction) = dangling_direction {
568
569        let (x1, y1, x2, y2) = root_node_pos(direction, root_direction, root_length)?;
570
571        let some_dangling_idx = graph.add_node(TreeNode {
572            x: x1, y: y1, depth: -1,
573        });
574        let dangling_idx = Some(some_dangling_idx);
575        let root_idx = graph.add_node(TreeNode{
576            x: x2, y: y2, depth: 0,
577        });
578        graph.add_edge(some_dangling_idx, root_idx, TreeEdge{
579            branch_choice: 0,
580        });
581        Ok((root_idx, dangling_idx))
582
583    } else {
584
585        // With no root, just start from the center of the left side
586        let (x, y) = match direction {
587            Up => (0.5, 1.),
588            Down => (0.5, 0.),
589            Left => (1., 0.5),
590            Right => (0., 0.5),
591        };
592        let root_idx = graph.add_node(TreeNode{
593            x, y, depth: 0,
594        });
595        Ok((root_idx, None))
596
597    }
598
599}
600
601/// Add root node with total width and `root_length` height,
602///  pointing straight to the actual start of the tree.
603///
604/// # Errors
605/// Error if `root_direction` is inconsistent with `direction`, i.e. in the SAME direction
606fn root_node_pos(
607    direction: Direction, root_direction: Direction, root_length: f64
608) -> Result<(f64, f64, f64, f64), AdicShapeError> {
609    // Note this is inconsistent with the above calculation of angle; width and height would be larger.
610    // But these probably work together just fine, since this first node will not really be used.
611    let pos = match (direction, root_direction) {
612        (Up, Left) => (0., 1., 0.5, 1. - root_length),
613        (Up, Down) => (0.5, 1., 0.5, 1. - root_length),
614        (Up, Right) => (1., 1., 0.5, 1. - root_length),
615        (Down, Left) => (0., 0., 0.5, root_length),
616        (Down, Up) => (0.5, 0., 0.5, root_length),
617        (Down, Right) => (1., 0., 0.5, root_length),
618        (Left, Up) => (1., 0., 1. - root_length, 0.5),
619        (Left, Right) => (1., 0.5, 1. - root_length, 0.5),
620        (Left, Down) => (1., 1., 1. - root_length, 0.5),
621        (Right, Up) => (0., 0., root_length, 0.5),
622        (Right, Left) => (0., 0.5, root_length, 0.5),
623        (Right, Down) => (0., 1., root_length, 0.5),
624        _ => {
625            return Err(AdicShapeError::ImproperConfig(
626                "Cannot have a dangling root in the same direction as the tree's growth".to_string()
627            ));
628        }
629    };
630    Ok(pos)
631}
632
633
634/// Add a branch to `graph` with branch num `p`
635/// Relative to `origin_idx`, fanning out in `direction` with `new_width` fan width and `new_length` fan length
636/// Adjust fan width center by `adjust_choice`
637///
638/// # Errors
639/// Errors if `graph` cannot find `origin_idx`
640fn add_relative_branch(
641    graph: &mut TreeGraph, origin_idx: NodeIndex, branch_choice: u32, direction: Direction,
642    adjust_choice: f64, adjust_depth: f64,
643) -> Result<(NodeIndex, EdgeIndex), AdicShapeError> {
644    let origin_bp = graph.node_weight(origin_idx).ok_or(AdicShapeError::PetGraph)?;
645    let (new_x, new_y) = match direction {
646        Up => (origin_bp.x + adjust_choice, origin_bp.y - adjust_depth),
647        Down => (origin_bp.x - adjust_choice, origin_bp.y + adjust_depth),
648        Left => (origin_bp.x - adjust_depth, origin_bp.y - adjust_choice),
649        Right => (origin_bp.x + adjust_depth, origin_bp.y + adjust_choice),
650    };
651
652    // Add node and edge from branch point to the possibility
653    let new_idx = graph.add_node(TreeNode{
654        x: new_x, y: new_y,
655        depth: origin_bp.depth + 1,
656    });
657    let edge_idx = graph.add_edge(origin_idx, new_idx, TreeEdge {
658        branch_choice,
659    });
660    Ok((new_idx, edge_idx))
661}
662
663
664
665#[cfg(test)]
666mod test {
667    use adic::uadic;
668    use super::{TreeShape, TreeShapeOptions};
669
670    #[test]
671    fn correct_numbers() {
672
673        let shape_options = TreeShapeOptions::default();
674
675        let tree_shape = TreeShape::full_tree(5, 6, shape_options).unwrap();
676        assert_eq!(5, tree_shape.p);
677        assert_eq!(0, tree_shape.gold_branches.len());
678
679        let adic_data = uadic!(5, [3, 2, 4, 1, 4, 1, 2]);
680        let tree_shape = TreeShape::adic_number_full_tree(&adic_data, 6, shape_options).unwrap();
681        assert_eq!(5, tree_shape.p);
682        assert_eq!(1, tree_shape.gold_branches.len());
683
684        let gold_branch = &tree_shape.gold_branches[0];
685        assert_eq!(6, gold_branch.len());
686        assert_eq!(3, gold_branch[0]);
687        assert_eq!(2, gold_branch[1]);
688        assert_eq!(4, gold_branch[2]);
689        assert_eq!(1, gold_branch[3]);
690        assert_eq!(4, gold_branch[4]);
691        assert_eq!(1, gold_branch[5]);
692
693        let adic_data = uadic!(5, [3, 2, 4, 1, 4, 1, 2]);
694        let tree_shape = TreeShape::zoomed_tree(&adic_data, 6, shape_options).unwrap();
695        assert_eq!(5, tree_shape.p);
696        assert_eq!(1, tree_shape.gold_branches.len());
697
698        let gold_branch = &tree_shape.gold_branches[0];
699        assert_eq!(6, gold_branch.len());
700        assert_eq!(3, gold_branch[0]);
701        assert_eq!(2, gold_branch[1]);
702        assert_eq!(4, gold_branch[2]);
703        assert_eq!(1, gold_branch[3]);
704        assert_eq!(4, gold_branch[4]);
705        assert_eq!(1, gold_branch[5]);
706
707    }
708
709    #[test]
710    fn correct_bounds() {
711
712        let shape_options = TreeShapeOptions::default();
713
714        let tree_shape = TreeShape::full_tree(5, 6, shape_options).unwrap();
715        assert!(0. <= tree_shape.graph.node_weights().map(|nw| nw.x).min_by(f64::total_cmp).unwrap());
716        assert!(100. >= tree_shape.graph.node_weights().map(|nw| nw.x).max_by(f64::total_cmp).unwrap());
717        assert!(0. <= tree_shape.graph.node_weights().map(|nw| nw.y).min_by(f64::total_cmp).unwrap());
718        assert!(100. >= tree_shape.graph.node_weights().map(|nw| nw.y).max_by(f64::total_cmp).unwrap());
719
720        let adic_data = uadic!(5, [3, 2, 4, 1, 4, 1, 2]);
721        let tree_shape = TreeShape::adic_number_full_tree(&adic_data, 6, shape_options).unwrap();
722        assert!(0. <= tree_shape.graph.node_weights().map(|nw| nw.x).min_by(f64::total_cmp).unwrap());
723        assert!(100. >= tree_shape.graph.node_weights().map(|nw| nw.x).max_by(f64::total_cmp).unwrap());
724        assert!(0. <= tree_shape.graph.node_weights().map(|nw| nw.y).min_by(f64::total_cmp).unwrap());
725        assert!(100. >= tree_shape.graph.node_weights().map(|nw| nw.y).max_by(f64::total_cmp).unwrap());
726
727        let adic_data = uadic!(5, [3, 2, 4, 1, 4, 1, 2]);
728        let tree_shape = TreeShape::zoomed_tree(&adic_data, 6, shape_options).unwrap();
729        assert!(0. <= tree_shape.graph.node_weights().map(|nw| nw.x).min_by(f64::total_cmp).unwrap());
730        assert!(100. >= tree_shape.graph.node_weights().map(|nw| nw.x).max_by(f64::total_cmp).unwrap());
731        assert!(0. <= tree_shape.graph.node_weights().map(|nw| nw.y).min_by(f64::total_cmp).unwrap());
732        assert!(100. >= tree_shape.graph.node_weights().map(|nw| nw.y).max_by(f64::total_cmp).unwrap());
733
734    }
735
736    #[test]
737    fn graph_stats() {
738
739        let shape_options = TreeShapeOptions::default();
740
741        let tree_shape = TreeShape::full_tree(5, 4, shape_options).unwrap();
742        let expected_num_branches = 625 + 125 + 25 + 5 + 1;
743        assert_eq!(expected_num_branches + 1, tree_shape.graph.node_count());
744        assert_eq!(expected_num_branches, tree_shape.graph.edge_count());
745        assert_eq!(625 + 125 + 25 + 5 + 1 + 1, tree_shape.graph.node_count());
746        assert_eq!(625 + 125 + 25 + 5 + 1, tree_shape.graph.edge_count());
747        assert_eq!(1, tree_shape.graph.node_weights().filter(|nw| nw.depth == -1).count());
748        assert_eq!(1, tree_shape.graph.node_weights().filter(|nw| nw.depth == 0).count());
749        assert_eq!(5, tree_shape.graph.node_weights().filter(|nw| nw.depth == 1).count());
750        assert_eq!(25, tree_shape.graph.node_weights().filter(|nw| nw.depth == 2).count());
751        assert_eq!(125, tree_shape.graph.node_weights().filter(|nw| nw.depth == 3).count());
752        assert_eq!(625, tree_shape.graph.node_weights().filter(|nw| nw.depth == 4).count());
753        assert_eq!((expected_num_branches-1)/5 + 1, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 0).count());
754        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 1).count());
755        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 2).count());
756        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 3).count());
757        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 4).count());
758
759        let adic_data = uadic!(5, [3, 2, 4, 1, 4, 1, 2]);
760        let tree_shape = TreeShape::adic_number_full_tree(&adic_data, 4, shape_options).unwrap();
761        let expected_num_branches = 625 + 125 + 25 + 5 + 1;
762        assert_eq!(expected_num_branches + 1, tree_shape.graph.node_count());
763        assert_eq!(expected_num_branches, tree_shape.graph.edge_count());
764        assert_eq!(1, tree_shape.graph.node_weights().filter(|nw| nw.depth == -1).count());
765        assert_eq!(1, tree_shape.graph.node_weights().filter(|nw| nw.depth == 0).count());
766        assert_eq!(5, tree_shape.graph.node_weights().filter(|nw| nw.depth == 1).count());
767        assert_eq!(25, tree_shape.graph.node_weights().filter(|nw| nw.depth == 2).count());
768        assert_eq!(125, tree_shape.graph.node_weights().filter(|nw| nw.depth == 3).count());
769        assert_eq!(625, tree_shape.graph.node_weights().filter(|nw| nw.depth == 4).count());
770        assert_eq!((expected_num_branches-1)/5 + 1, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 0).count());
771        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 1).count());
772        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 2).count());
773        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 3).count());
774        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 4).count());
775
776        let adic_data = uadic!(5, [3, 2, 4, 1, 4, 1, 2]);
777        let tree_shape = TreeShape::zoomed_tree(&adic_data, 4, shape_options).unwrap();
778        let expected_num_branches = 5 + 20 + 5 + 20 + 5 + 20 + 5 + 1;
779        assert_eq!(expected_num_branches + 1, tree_shape.graph.node_count());
780        assert_eq!(expected_num_branches, tree_shape.graph.edge_count());
781        assert_eq!(1, tree_shape.graph.node_weights().filter(|nw| nw.depth == -1).count());
782        assert_eq!(1, tree_shape.graph.node_weights().filter(|nw| nw.depth == 0).count());
783        assert_eq!(5, tree_shape.graph.node_weights().filter(|nw| nw.depth == 1).count());
784        assert_eq!(20 + 5, tree_shape.graph.node_weights().filter(|nw| nw.depth == 2).count());
785        assert_eq!(20 + 5, tree_shape.graph.node_weights().filter(|nw| nw.depth == 3).count());
786        assert_eq!(20 + 5, tree_shape.graph.node_weights().filter(|nw| nw.depth == 4).count());
787        assert_eq!((expected_num_branches-1)/5 + 1, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 0).count());
788        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 1).count());
789        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 2).count());
790        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 3).count());
791        assert_eq!((expected_num_branches-1)/5, tree_shape.graph.edge_weights().filter(|ew| ew.branch_choice == 4).count());
792
793    }
794
795}