Просмотр исходного кода

script/research/dark-forest: min capacity logic added, to double bound the tree

aggstam 2 лет назад
Родитель
Сommit
9bcc383b8e

+ 11 - 2
script/research/dark-forest/src/error.rs

@@ -31,6 +31,15 @@ pub enum DarkTreeError {
     #[error("Invalid DarkLeaf children index found for leaf: {0}")]
     InvalidLeafChildrenIndexes(usize),
 
-    #[error("DarkTree capacity have been exceeded")]
-    CapacityExceeded,
+    #[error("Invalid DarkTree min capacity found: {0} (Expected: >= 1)")]
+    InvalidMinCapacity(usize),
+
+    #[error("DarkTree min capacity has not been exceeded")]
+    MinCapacityNotExceeded,
+
+    #[error("Invalid DarkTree max capacity found: {0} (Expected: >= {1})")]
+    InvalidMaxCapacity(usize, usize),
+
+    #[error("DarkTree max capacity has been exceeded")]
+    MaxCapacityExceeded,
 }

+ 65 - 16
script/research/dark-forest/src/lib.rs

@@ -83,6 +83,14 @@ struct DarkTree<T> {
     leaf: DarkLeaf<T>,
     /// Vector containing all tree's branches(children tree)
     children: Vec<DarkTree<T>>,
+    /// Min capacity of the tree, including all children nodes
+    /// recursively from the root. Since root is always present,
+    /// min capacity must always be >= 1. This is enforced by
+    /// the root, so children nodes don't have to set it up.
+    /// If children nodes children(recursively) make us not exceed
+    /// that min capacity, we will be able to catch it using
+    /// .check_min_capacity() or .integrity_check().
+    min_capacity: usize,
     /// Optional max capacity of the tree, including all children
     /// nodes recursively from the root. None indicates no
     /// capacity restrictions. This is enforced by the root,
@@ -90,15 +98,30 @@ struct DarkTree<T> {
     /// nodes children(recursively) make us exceed that capacity,
     /// we will be able to catch it using .check_capacity() or
     /// .integrity_check().
-    capacity: Option<usize>,
+    max_capacity: Option<usize>,
 }
 
 impl<T> DarkTree<T> {
     /// Initialize a [`DarkTree`], using provided data to
     /// generate its root.
-    fn new(data: T, children: Vec<DarkTree<T>>, capacity: Option<usize>) -> DarkTree<T> {
+    fn new(
+        data: T,
+        children: Vec<DarkTree<T>>,
+        min_capacity: Option<usize>,
+        max_capacity: Option<usize>,
+    ) -> DarkTree<T> {
+        // Setup min capacity
+        let min_capacity = if let Some(min_capacity) = min_capacity {
+            if min_capacity == 0 {
+                1
+            } else {
+                min_capacity
+            }
+        } else {
+            1
+        };
         let leaf = DarkLeaf::new(data);
-        Self { leaf, children, capacity }
+        Self { leaf, children, min_capacity, max_capacity }
     }
 
     /// Build the [`DarkTree`] indexes and perform an
@@ -116,11 +139,20 @@ impl<T> DarkTree<T> {
         self.iter().count()
     }
 
-    /// Check if configured capacity have been exceeded.
-    fn check_capacity(&self) -> DarkTreeResult<()> {
-        if let Some(capacity) = self.capacity {
-            if self.len() >= capacity {
-                return Err(DarkTreeError::CapacityExceeded)
+    /// Check if configured min capacity have been exceeded.
+    fn check_min_capacity(&self) -> DarkTreeResult<()> {
+        if self.len() < self.min_capacity {
+            return Err(DarkTreeError::MinCapacityNotExceeded)
+        }
+
+        Ok(())
+    }
+
+    /// Check if configured max capacity have been exceeded.
+    fn check_max_capacity(&self) -> DarkTreeResult<()> {
+        if let Some(max_capacity) = self.max_capacity {
+            if self.len() >= max_capacity {
+                return Err(DarkTreeError::MaxCapacityExceeded)
             }
         }
 
@@ -128,12 +160,12 @@ impl<T> DarkTree<T> {
     }
 
     /// Append a new child node to the [`DarkTree`],
-    /// if capacity has not been exceeded. This call
+    /// if max capacity has not been exceeded. This call
     /// doesn't update the indexes, so either .index()
     /// or .build() must be called after it.
     fn append(&mut self, child: DarkTree<T>) -> DarkTreeResult<()> {
-        // Check current capacity
-        self.check_capacity()?;
+        // Check current max capacity
+        self.check_max_capacity()?;
 
         // Append the new child
         self.children.push(child);
@@ -198,12 +230,29 @@ impl<T> DarkTree<T> {
 
     /// Verify current [`DarkTree`]'s leafs indexes validity,
     /// based on DFS post-order traversal order. Additionally,
-    /// check that capacity has not been exceeded. This call
-    /// assumes it was triggered for the root of the tree,
-    /// which has no parent index.
+    /// check that min and max capacities have been properly
+    /// configured, min capacity has been exceeded and max
+    /// capacity has not. This call assumes it was triggered
+    /// for the root of the tree, which has no parent index.
     fn integrity_check(&self) -> DarkTreeResult<()> {
-        // Check current capacity
-        self.check_capacity()?;
+        // Check current min capacity is valid
+        if self.min_capacity < 1 {
+            return Err(DarkTreeError::InvalidMinCapacity(self.min_capacity))
+        }
+
+        // Check currect max capacity is not less than
+        // current min capacity
+        if let Some(max_capacity) = self.max_capacity {
+            if self.min_capacity > max_capacity {
+                return Err(DarkTreeError::InvalidMaxCapacity(max_capacity, self.min_capacity))
+            }
+        }
+
+        // Check current min capacity
+        self.check_min_capacity()?;
+
+        // Check current max capacity
+        self.check_max_capacity()?;
 
         // Check each leaf index
         for (index, leaf) in self.iter().enumerate() {

+ 132 - 46
script/research/dark-forest/src/tests.rs

@@ -40,42 +40,58 @@ fn generate_tree() -> DarkTreeResult<(DarkTree<i32>, Vec<i32>)> {
                 vec![
                     DarkTree::new(
                         2,
-                        vec![DarkTree::new(0, vec![], None), DarkTree::new(1, vec![], None)],
+                        vec![
+                            DarkTree::new(0, vec![], None, None),
+                            DarkTree::new(1, vec![], None, None),
+                        ],
+                        None,
                         None,
                     ),
-                    DarkTree::new(4, vec![DarkTree::new(3, vec![], None)], None),
-                    DarkTree::new(6, vec![DarkTree::new(5, vec![], None)], None),
+                    DarkTree::new(4, vec![DarkTree::new(3, vec![], None, None)], None, None),
+                    DarkTree::new(6, vec![DarkTree::new(5, vec![], None, None)], None, None),
                     DarkTree::new(
                         9,
-                        vec![DarkTree::new(7, vec![], None), DarkTree::new(8, vec![], None)],
+                        vec![
+                            DarkTree::new(7, vec![], None, None),
+                            DarkTree::new(8, vec![], None, None),
+                        ],
+                        None,
                         None,
                     ),
                 ],
                 None,
+                None,
             ),
             DarkTree::new(
                 14,
                 vec![
-                    DarkTree::new(12, vec![DarkTree::new(11, vec![], None)], None),
-                    DarkTree::new(13, vec![], None),
+                    DarkTree::new(12, vec![DarkTree::new(11, vec![], None, None)], None, None),
+                    DarkTree::new(13, vec![], None, None),
                 ],
                 None,
+                None,
             ),
             DarkTree::new(
                 21,
                 vec![
                     DarkTree::new(
                         17,
-                        vec![DarkTree::new(15, vec![], None), DarkTree::new(16, vec![], None)],
+                        vec![
+                            DarkTree::new(15, vec![], None, None),
+                            DarkTree::new(16, vec![], None, None),
+                        ],
+                        None,
                         None,
                     ),
-                    DarkTree::new(18, vec![], None),
-                    DarkTree::new(20, vec![DarkTree::new(19, vec![], None)], None),
+                    DarkTree::new(18, vec![], None, None),
+                    DarkTree::new(20, vec![DarkTree::new(19, vec![], None, None)], None, None),
                 ],
                 None,
+                None,
             ),
         ],
         None,
+        None,
     );
 
     tree.build()?;
@@ -178,7 +194,7 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
 
     // Verify performed mutation actually happened
     // on original tree. Additionally we verify all
-    // indexes are the expected one.
+    // indexes are the expected ones.
     assert_eq!(
         tree,
         DarkTree {
@@ -213,7 +229,8 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                         children_indexes: vec![]
                                     },
                                     children: vec![],
-                                    capacity: None,
+                                    min_capacity: 1,
+                                    max_capacity: None,
                                 },
                                 DarkTree {
                                     leaf: DarkLeaf {
@@ -223,10 +240,12 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                         children_indexes: vec![]
                                     },
                                     children: vec![],
-                                    capacity: None,
+                                    min_capacity: 1,
+                                    max_capacity: None,
                                 },
                             ],
-                            capacity: None,
+                            min_capacity: 1,
+                            max_capacity: None,
                         },
                         DarkTree {
                             leaf: DarkLeaf {
@@ -243,9 +262,11 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                     children_indexes: vec![]
                                 },
                                 children: vec![],
-                                capacity: None,
+                                min_capacity: 1,
+                                max_capacity: None,
                             },],
-                            capacity: None,
+                            min_capacity: 1,
+                            max_capacity: None,
                         },
                         DarkTree {
                             leaf: DarkLeaf {
@@ -262,9 +283,11 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                     children_indexes: vec![]
                                 },
                                 children: vec![],
-                                capacity: None,
+                                min_capacity: 1,
+                                max_capacity: None,
                             },],
-                            capacity: None,
+                            min_capacity: 1,
+                            max_capacity: None,
                         },
                         DarkTree {
                             leaf: DarkLeaf {
@@ -282,7 +305,8 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                         children_indexes: vec![]
                                     },
                                     children: vec![],
-                                    capacity: None,
+                                    min_capacity: 1,
+                                    max_capacity: None,
                                 },
                                 DarkTree {
                                     leaf: DarkLeaf {
@@ -292,13 +316,16 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                         children_indexes: vec![]
                                     },
                                     children: vec![],
-                                    capacity: None,
+                                    min_capacity: 1,
+                                    max_capacity: None,
                                 },
                             ],
-                            capacity: None,
+                            min_capacity: 1,
+                            max_capacity: None,
                         },
                     ],
-                    capacity: None,
+                    min_capacity: 1,
+                    max_capacity: None,
                 },
                 DarkTree {
                     leaf: DarkLeaf {
@@ -323,9 +350,11 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                     children_indexes: vec![]
                                 },
                                 children: vec![],
-                                capacity: None,
+                                min_capacity: 1,
+                                max_capacity: None,
                             },],
-                            capacity: None,
+                            min_capacity: 1,
+                            max_capacity: None,
                         },
                         DarkTree {
                             leaf: DarkLeaf {
@@ -335,10 +364,12 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                 children_indexes: vec![]
                             },
                             children: vec![],
-                            capacity: None,
+                            min_capacity: 1,
+                            max_capacity: None,
                         },
                     ],
-                    capacity: None,
+                    min_capacity: 1,
+                    max_capacity: None,
                 },
                 DarkTree {
                     leaf: DarkLeaf {
@@ -364,7 +395,8 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                         children_indexes: vec![]
                                     },
                                     children: vec![],
-                                    capacity: None,
+                                    min_capacity: 1,
+                                    max_capacity: None,
                                 },
                                 DarkTree {
                                     leaf: DarkLeaf {
@@ -374,10 +406,12 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                         children_indexes: vec![]
                                     },
                                     children: vec![],
-                                    capacity: None,
+                                    min_capacity: 1,
+                                    max_capacity: None,
                                 },
                             ],
-                            capacity: None,
+                            min_capacity: 1,
+                            max_capacity: None,
                         },
                         DarkTree {
                             leaf: DarkLeaf {
@@ -387,7 +421,8 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                 children_indexes: vec![]
                             },
                             children: vec![],
-                            capacity: None,
+                            min_capacity: 1,
+                            max_capacity: None,
                         },
                         DarkTree {
                             leaf: DarkLeaf {
@@ -404,15 +439,19 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
                                     children_indexes: vec![]
                                 },
                                 children: vec![],
-                                capacity: None,
+                                min_capacity: 1,
+                                max_capacity: None,
                             },],
-                            capacity: None,
+                            min_capacity: 1,
+                            max_capacity: None,
                         },
                     ],
-                    capacity: None,
+                    min_capacity: 1,
+                    max_capacity: None,
                 },
             ],
-            capacity: None,
+            min_capacity: 1,
+            max_capacity: None,
         }
     );
 
@@ -430,53 +469,100 @@ fn test_darktree_mut_iterator() -> DarkTreeResult<()> {
     Ok(())
 }
 
+#[test]
+pub fn test_darktree_min_capacity() -> DarkTreeResult<()> {
+    // Generate a new [`DarkTree`] with min capacity 0
+    let mut tree = DarkTree::new(0, vec![], Some(0), None);
+
+    // Verify that min capacity was properly setup to 1
+    assert_eq!(
+        tree,
+        DarkTree {
+            leaf: DarkLeaf { data: 0, index: 0, parent_index: None, children_indexes: vec![] },
+            children: vec![],
+            min_capacity: 1,
+            max_capacity: None
+        }
+    );
+
+    // Verify that building it will succeed, as capacity
+    // would have ben setup to 1
+    assert!(tree.build().is_ok());
+
+    // Generate a new [`DarkTree`] manually with
+    // min capacity 0
+    let mut tree = DarkTree {
+        leaf: DarkLeaf { data: 0, index: 0, parent_index: None, children_indexes: vec![] },
+        children: vec![],
+        min_capacity: 0,
+        max_capacity: None,
+    };
+
+    // Verify that building it will fail
+    assert!(tree.build().is_err());
+
+    // Thanks for reading
+    Ok(())
+}
+
 #[test]
 pub fn test_darktree_max_capacity() -> DarkTreeResult<()> {
-    // Generate a new [`DarkTree`] with capacity 2
-    let mut tree = DarkTree::new(0, vec![], Some(2));
+    // Generate a new [`DarkTree`] with max capacity 2
+    let mut tree = DarkTree::new(0, vec![], None, Some(2));
 
     // Append a new node
-    tree.append(DarkTree::new(1, vec![], None))?;
+    tree.append(DarkTree::new(1, vec![], None, None))?;
 
     // Try to append a new node
-    assert!(tree.append(DarkTree::new(2, vec![], None)).is_err());
+    assert!(tree.append(DarkTree::new(2, vec![], None, None)).is_err());
 
-    // Generate a new [`DarkTree`] with capacity 2
-    let mut new_tree = DarkTree::new(3, vec![], Some(2));
+    // Generate a new [`DarkTree`] with max capacity 2
+    let mut new_tree = DarkTree::new(3, vec![], None, Some(2));
 
     // Append the previous tree as a new node
     new_tree.append(tree)?;
 
-    // Check that capacity has been exceeded
-    assert!(new_tree.check_capacity().is_err());
+    // Check that max capacity has been exceeded
+    assert!(new_tree.check_max_capacity().is_err());
 
     // Generate a new [`DarkTree`] manually with
-    // capacity 1
+    // max capacity 1
     let mut tree = DarkTree {
         leaf: DarkLeaf { data: 0, index: 0, parent_index: None, children_indexes: vec![] },
         children: vec![
             DarkTree {
                 leaf: DarkLeaf { data: 0, index: 0, parent_index: None, children_indexes: vec![] },
                 children: vec![],
-                capacity: None,
+                min_capacity: 1,
+                max_capacity: None,
             },
             DarkTree {
                 leaf: DarkLeaf { data: 0, index: 0, parent_index: None, children_indexes: vec![] },
                 children: vec![],
-                capacity: None,
+                min_capacity: 1,
+                max_capacity: None,
             },
             DarkTree {
                 leaf: DarkLeaf { data: 0, index: 0, parent_index: None, children_indexes: vec![0] },
                 children: vec![],
-                capacity: None,
+                min_capacity: 1,
+                max_capacity: None,
             },
         ],
-        capacity: Some(1),
+        min_capacity: 1,
+        max_capacity: Some(1),
     };
 
     // Verify that building it will fail
     assert!(tree.build().is_err());
 
+    // Generate a new [`DarkTree`] with max capacity 0,
+    // which is less that current min capacity 1
+    let mut tree = DarkTree::new(0, vec![], None, Some(0));
+
+    // Verify that building it will fail
+    assert!(tree.build().is_err());
+
     // Thanks for reading
     Ok(())
 }