1
+ // # EXAMPLE DEFINITION
2
+ //
3
+ // This example demonstrates a use case where value of a node is defined
4
+ // as a function of the values of its children. Since the value of a child
5
+ // of the node also depends on values of its own children, it follows that
6
+ // the value of a node is a function of values of all of its descendants.
7
+ //
8
+ // The task is to compute and set all values of a tree given the values of
9
+ // the leaves.
10
+ //
11
+ // This is a interesting and common case in terms of requiring mutable
12
+ // recursive traversal over the tree that can be handled with different
13
+ // approaches. Some of these are demonstrated in this example.
14
+
1
15
use orx_tree:: * ;
2
16
use std:: fmt:: Display ;
3
17
4
- const INPUTS_COUNT : usize = 2 ;
5
-
6
18
#[ derive( Debug , Clone , Copy ) ]
7
19
enum Instruction {
8
20
Input ( usize ) ,
@@ -43,11 +55,11 @@ impl Display for InstructionNode {
43
55
}
44
56
45
57
#[ derive( Debug ) ]
46
- struct MyTree {
58
+ struct Instructions {
47
59
tree : DynTree < InstructionNode > ,
48
60
}
49
61
50
- impl MyTree {
62
+ impl Instructions {
51
63
fn example ( ) -> Self {
52
64
let mut tree = DynTree :: new ( InstructionNode :: new ( Instruction :: AddI { val : 100.0 } , 0.0 ) ) ;
53
65
@@ -66,32 +78,32 @@ impl MyTree {
66
78
67
79
Self { tree }
68
80
}
69
-
70
- fn execute_rec ( & mut self , inputs : & [ f32 ] , node_idx : NodeIdx < Dyn < InstructionNode > > ) -> f32 {
71
- let node = self . tree . node ( & node_idx) ;
72
-
73
- let children_ids = node. children ( ) . map ( |child| child. idx ( ) ) . collect :: < Vec < _ > > ( ) ;
74
- let mut children = vec ! [ ] ;
75
-
76
- for node in children_ids {
77
- let value = self . execute_rec ( inputs, node) ;
78
- children. push ( value) ;
79
- }
80
-
81
- let mut node = self . tree . node_mut ( & node_idx) ;
82
-
83
- let new_value = match node. data ( ) . instruction {
84
- Instruction :: Input ( i) => inputs[ i] ,
85
- Instruction :: Add => children. into_iter ( ) . sum ( ) ,
86
- Instruction :: AddI { val } => children. into_iter ( ) . sum :: < f32 > ( ) + val,
87
- } ;
88
- ( * node. data_mut ( ) ) . value = new_value;
89
-
90
- new_value
91
- }
92
81
}
93
82
94
- fn execute < ' a > (
83
+ /// Demonstrates manual mutable and recursive traversal over the tree.
84
+ ///
85
+ /// Notice that we can freely walk the tree while always having a single
86
+ /// mutable reference to one node. This satisfies the borrow checker rules
87
+ /// and further allows for calling the function recursively.
88
+ ///
89
+ /// Note also that, although it is not necessary in this scenario, we are
90
+ /// free to change the shape of the tree during our walk by adding nodes,
91
+ /// moving around or pruning subtrees, etc. In other words, it enables the
92
+ /// greatest freedom while it requires us to make sure that we do not have
93
+ /// errors, such as out-of-bounds errors with the `into_child_mut` call.
94
+ ///
95
+ /// * Pros
96
+ /// * Complete freedom to mutate the nodes and the tree structure during
97
+ /// the walk.
98
+ /// * No intermediate allocation is required; borrow checker rules are
99
+ /// satisfied without the need to collect indices.
100
+ /// * Cons
101
+ /// * Implementor is required to define the walk. This example demonstrates
102
+ /// a depth-first walk due to the recursive calls, which is straightforward
103
+ /// to implement.
104
+ /// * Due to lack of tail-call optimization in rust, this function is likely
105
+ /// to encounter stack overflow for very deep trees.
106
+ fn recursive_traversal_over_nodes < ' a > (
95
107
inputs : & [ f32 ] ,
96
108
mut node : NodeMut < ' a , Dyn < InstructionNode > > ,
97
109
) -> ( NodeMut < ' a , Dyn < InstructionNode > > , f32 ) {
@@ -100,7 +112,7 @@ fn execute<'a>(
100
112
let mut children_sum = 0.0 ;
101
113
for i in 0 ..num_children {
102
114
let child = node. into_child_mut ( i) . unwrap ( ) ;
103
- let ( child, child_value) = execute ( inputs, child) ;
115
+ let ( child, child_value) = recursive_traversal_over_nodes ( inputs, child) ;
104
116
children_sum += child_value;
105
117
node = child. into_parent_mut ( ) . unwrap ( ) ;
106
118
}
@@ -116,43 +128,109 @@ fn execute<'a>(
116
128
( node, new_value)
117
129
}
118
130
119
- fn test_implementation ( method : & str , f : impl FnOnce ( & [ f32 ] , & mut MyTree ) ) {
120
- let inputs = [ 10.0 , 20.0 ] ;
131
+ /// Demonstrates recursive mutable traversal by internally collecting and storing
132
+ /// the child node indices.
133
+ ///
134
+ /// This simplifies the borrow relations and allows for the recursive calls only
135
+ /// having a single mutable reference to the tree; however, each recursive call
136
+ /// requires an internal allocation.
137
+ ///
138
+ /// * Pros
139
+ /// * Complete freedom to mutate the nodes and the tree structure during
140
+ /// the walk.
141
+ /// * Cons
142
+ /// * Requires to collect indices and results into an internal vector for each
143
+ /// recursive call, requiring additional allocation.
144
+ /// * Implementor is required to define the walk. This example demonstrates
145
+ /// a depth-first walk due to the recursive calls, which is straightforward
146
+ /// to implement.
147
+ /// * Due to lack of tail-call optimization in rust, this function is likely
148
+ /// to encounter stack overflow for very deep trees.
149
+ fn recursive_traversal_over_indices (
150
+ tree : & mut DynTree < InstructionNode > ,
151
+ inputs : & [ f32 ] ,
152
+ node_idx : NodeIdx < Dyn < InstructionNode > > ,
153
+ ) -> f32 {
154
+ let node = tree. node ( & node_idx) ;
155
+
156
+ let children_ids: Vec < _ > = node. children ( ) . map ( |child| child. idx ( ) ) . collect ( ) ;
157
+ let children: Vec < _ > = children_ids
158
+ . into_iter ( )
159
+ . map ( |node| recursive_traversal_over_indices ( tree, inputs, node) )
160
+ . collect ( ) ;
121
161
122
- let mut tree = MyTree :: example ( ) ;
162
+ let mut node = tree . node_mut ( & node_idx ) ;
123
163
124
- println ! ( "\n \n # {}" , method) ;
125
- println ! ( "\n inputs = {:?}\n " , & inputs) ;
126
- println ! ( "Before execute:\n {}\n " , & tree. tree) ;
127
- f ( & inputs, & mut tree) ;
128
- println ! ( "After execute:\n {}\n " , & tree. tree) ;
164
+ let new_value = match node. data ( ) . instruction {
165
+ Instruction :: Input ( i) => inputs[ i] ,
166
+ Instruction :: Add => children. into_iter ( ) . sum ( ) ,
167
+ Instruction :: AddI { val } => children. into_iter ( ) . sum :: < f32 > ( ) + val,
168
+ } ;
169
+ ( * node. data_mut ( ) ) . value = new_value;
170
+
171
+ new_value
129
172
}
130
173
131
- fn main ( ) {
132
- test_implementation ( "IMPL OVER CHILDREN INDICES" , |inputs, tree| {
133
- tree. execute_rec ( inputs, tree. tree . root ( ) . idx ( ) ) ;
174
+ /// Demonstrates the use of [`recursive_set`] method:
175
+ ///
176
+ /// *Recursively sets the data of all nodes belonging to the subtree rooted
177
+ /// at this node using the compute_data function.*
178
+ ///
179
+ /// This function fits perfectly to this and similar scenarios where we want
180
+ /// to compute values of all nodes of a tree such that the value of a node
181
+ /// depends on the values of all of its descendants, and hence the name
182
+ /// *recursive*.
183
+ ///
184
+ /// * Pros
185
+ /// * More expressive in the sense that the implementor only defines how the
186
+ /// value of a node should be computed given its prior value and values of
187
+ /// its children. Iteration is abstracted away.
188
+ /// * Despite the name, the implementation actually does not require recursive
189
+ /// function calls; and hence, can work with trees of arbitrary depth without
190
+ /// the risk of stack overflow. Instead, it internally uses the [`PostOrder`]
191
+ /// traverser.
192
+ /// * Cons
193
+ /// * It only allows to set the data of the nodes; however, does not allow for
194
+ /// structural mutations.
195
+ ///
196
+ /// [`recursive_set`]: orx_tree::NodeMut::recursive_set
197
+ /// [`PostOrder`]: orx_tree::PostOrder
198
+ fn recursive_set ( inputs : & [ f32 ] , mut node : NodeMut < Dyn < InstructionNode > > ) {
199
+ node. recursive_set ( |node_data, children_data| {
200
+ let instruction = node_data. instruction ;
201
+ let children_sum: f32 = children_data. iter ( ) . map ( |x| x. value ) . sum ( ) ;
202
+ let value = match node_data. instruction {
203
+ Instruction :: Input ( i) => inputs[ i] ,
204
+ Instruction :: Add => children_sum,
205
+ Instruction :: AddI { val } => val + children_sum,
206
+ } ;
207
+
208
+ InstructionNode { instruction, value }
134
209
} ) ;
210
+ }
211
+
212
+ fn main ( ) {
213
+ fn test_implementation ( method : & str , f : impl FnOnce ( & [ f32 ] , & mut Instructions ) ) {
214
+ let inputs = [ 10.0 , 20.0 ] ;
215
+ let mut instructions = Instructions :: example ( ) ;
216
+ println ! ( "\n \n ### {}" , method) ;
217
+ f ( & inputs, & mut instructions) ;
218
+ println ! ( "\n {}\n " , & instructions. tree) ;
219
+ }
135
220
136
221
test_implementation (
137
- "IMPL WITH INTO_CHILD_MUT & INTO_PARENT_MUT" ,
138
- |inputs, tree| {
139
- execute ( & inputs, tree. tree . root_mut ( ) ) ;
222
+ "recursive_traversal_over_indices" ,
223
+ |inputs, instructions| {
224
+ let root_idx = instructions. tree . root ( ) . idx ( ) ;
225
+ recursive_traversal_over_indices ( & mut instructions. tree , inputs, root_idx) ;
140
226
} ,
141
227
) ;
142
228
143
- test_implementation ( "IMPL recursive_set" , |inputs, tree| {
144
- tree. tree
145
- . root_mut ( )
146
- . recursive_set ( |node_data, children_data| {
147
- let instruction = node_data. instruction ;
148
- let children_sum: f32 = children_data. iter ( ) . map ( |x| x. value ) . sum ( ) ;
149
- let value = match node_data. instruction {
150
- Instruction :: Input ( i) => inputs[ i] ,
151
- Instruction :: Add => children_sum,
152
- Instruction :: AddI { val } => val + children_sum,
153
- } ;
154
-
155
- InstructionNode { instruction, value }
156
- } ) ;
229
+ test_implementation ( "recursive_traversal_over_nodes" , |inputs, instructions| {
230
+ recursive_traversal_over_nodes ( & inputs, instructions. tree . root_mut ( ) ) ;
231
+ } ) ;
232
+
233
+ test_implementation ( "recursive_set" , |inputs, instructions| {
234
+ recursive_set ( inputs, instructions. tree . root_mut ( ) ) ;
157
235
} ) ;
158
236
}
0 commit comments