1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
use rand::Rng;
use std::ptr;
use std::mem;
use std::cmp::max;
use std::fmt;
use std::marker::Sync;

use super::network::NeuralNetwork;




/// a Node struct to represent a bidirectional binary tree
/// holding pointers to the parent and two children, the left and right child
/// The node also holds an input size which is the expected size of the input vector 
/// for the neural network held within the node. The output represetns the postion of the 
/// node, meaning that if it is a leaf, it will return the output from a get output function
#[derive(PartialEq)]
pub struct Node {
    pub parent: *mut Node,
    pub left_child: *mut Node,
    pub right_child: *mut Node,
    pub neural_network: NeuralNetwork,
    pub input_size: i32,
    pub output: u8
}



/// implement the node
impl Node {

    /// create a new node with a given input size and a list of possible output options 
    /// 
    /// From the list of output_options the node will choose an output,
    /// from the input_size the node will create a randomly generated 
    /// neural network.
    pub fn new(input_size: i32, output_options: &Vec<i32>) -> Self {
        let mut r = rand::thread_rng();
        let output = output_options[r.gen_range(0, output_options.len())] as u8;
        Node {
            parent: ptr::null_mut(),
            left_child: ptr::null_mut(),
            right_child: ptr::null_mut(),
            neural_network: NeuralNetwork::new(input_size).fill_random(),
            input_size,
            output
        }
    }



    /// return a node as a raw mutable pointer to a node
    /// this is a safe function however dereferencing the output is not
    /// also creating a box and putting it into raw includes a small amount of overhead 
    pub fn as_mut_ptr(self) -> *mut Node {
        Box::into_raw(Box::new(self))
    }



    /// return true if this node is the left child of it's parent, false if not
    pub fn check_left_child(&self, node: &Node) -> bool {
        if self.has_left_child() {
           unsafe {
               return *self.left_child == *node;
           }
        }
        false
    }



    /// return true if this node is the right child of it's parent, false if not
    pub fn check_right_child(&self, node: &Node) -> bool {
        if self.has_right_child() {
            unsafe {
                return *self.right_child == *node;
            }
        }
        false
    }



    /// return true if this node has no children, meaning it has no children.
    /// A node that is a leaf is the only node which can return an output.
    pub fn is_leaf(&self) -> bool {
        !self.has_left_child() && !self.has_right_child()
    }



    /// return true if this node has a valid left child and is not pointing to a null pointer
    pub fn has_left_child(&self) -> bool {
        self.left_child != ptr::null_mut()
    }



    /// return true if this node has a valid right child and is not pointing to a null pointer 
    pub fn has_right_child(&self) -> bool {
        self.right_child != ptr::null_mut()
    }



    /// return true if this node has a parent, false if not. 
    /// If it does not, then this node is the root of the tree.
    pub fn has_parent(&self) -> bool {
        self.parent != ptr::null_mut()
    }



    /// return the height of this node recursivley
    #[inline]    
    pub fn height(&self) -> i32 {
        unsafe {
            1 + max(
                Some(&*self.left_child).map_or(0, |node| node.height()),
                Some(&*self.right_child).map_or(0, |node| node.height())
            )
        }
    }



    /// return the depth of this node, meaning the number of levels down it is 
    /// from the root of the tree, recrsive.
    #[inline]    
    pub fn depth(&self) -> i32 {
        unsafe {
            if !self.has_parent() {
                return 0;
            }
            return 1 + (*self.parent).depth()
        }
    }



    /// return the size of the subtree recrusivley. 
    #[inline]    
    pub fn size(&self) -> i32 {
        let mut result = 1;
        if !self.is_leaf() {
            if self.has_left_child() {
                unsafe { result += (*self.left_child).size(); } 
            }
            if self.has_right_child() {
                unsafe { result += (*self.right_child).size(); }
            }
        }
        result
    }


   
    /// Return a thin copy of this node, meaning keep all information besides the family pointers,
    /// these are nulled-out in order to avoid dangling or circular references.
    #[inline]
    pub fn copy(&self) -> Node {
        Node {
            parent: ptr::null_mut(),
            left_child: ptr::null_mut(),
            right_child: ptr::null_mut(),
            neural_network: self.neural_network.clone(),
            input_size: self.input_size,
            output: self.output
        }
    }



    /// deep copy this node and it's subnodes. Recursivley traverse the tree in order and 
    /// thin copy the current node, then assign it's surroudning pointers recrusivley.
    #[inline]    
    pub fn deepcopy(&self) -> *mut Node {
        unsafe {
            let temp_copy = self.copy().as_mut_ptr();
            if self.has_left_child() {
                (*temp_copy).left_child = (*self.left_child).deepcopy();
                (*(*temp_copy).left_child).parent = temp_copy;
            }
            if self.has_right_child() {
                (*temp_copy).right_child = (*self.right_child).deepcopy();
                (*(*temp_copy).right_child).parent = temp_copy;
            }
            temp_copy
        }
    }



    /// Unsafe function.
    /// 
    /// Randomly insert a random node into the tree. Choose a boolean value randomly 
    /// and recurse the tree until a null_mut() pointer is found, then insert a new node.
    pub unsafe fn insert_random(&mut self, input_size: i32, output_options: &Vec<i32>) {
        match rand::random() {
            true => {
                if !self.has_left_child() {
                    self.left_child = Node::new(input_size, output_options).as_mut_ptr();
                    (*self.left_child).parent = self;
                    return
                }
                (*self.left_child).insert_random(input_size, output_options);
            },
            false => {
                if !self.has_right_child() {
                    self.right_child = Node::new(input_size, output_options).as_mut_ptr();
                    (*self.right_child).parent = self; 
                    return
                }
                (*self.right_child).insert_random(input_size, output_options);
            }
        }
    }



    /// Recrusively display the node and it's subnodes 
    /// Useful for visualizing the strucutre of the tree and debugging.
    /// Level is the depth of the tree, at the root it should be 0.
    pub fn display(&self, level: i32) {
        unsafe {
            if self.left_child != ptr::null_mut() {
                (*self.left_child).display(level + 1);
            }
            let tabs: String = (0..level)
                .map(|_| "\t")
                .collect::<Vec<_>>()
                .join("");
            println!("{}{:?}\n", tabs, self);
            if self.right_child != ptr::null_mut() {
                (*self.right_child).display(level + 1);
            }
        }
    }



}



/// This will recursivley drop all nodes in this node's 
/// subree. These are made out of raw pointers so they need to be 
/// dropped manually
impl Drop for Node {
    fn drop(&mut self) {  }
}




unsafe impl Send for Node {}

unsafe impl Sync for Node {}



/// implemented a display function for the node to display a simple representation of the node
impl fmt::Display for Node {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // let address: u64 = unsafe { mem::transmute(self) };
        write!(f, "Node=[{}]", self.output)
    }
}



/// implement debut for the node to give a little more information for the node and 
/// make it easier to trace through a tree when a tree is displayed
impl fmt::Debug for Node {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        unsafe {
            // let address: u64 = mem::transmute(self);
            // let left: u64 = if self.has_left_child() { mem::transmute(&*self.left_child) } else { 0x64 };
            // let right: u64 = if self.has_right_child() { mem::transmute(&*self.right_child) } else { 0x64 };
            write!(f, "Node=[{}]", self.output)
        }
    }
}