Skip to content

Commit

Permalink
Merge pull request #15 from azizkayumov/stress
Browse files Browse the repository at this point in the history
Findmax random test
  • Loading branch information
azizkayumov committed Oct 4, 2023
2 parents 27afa67 + eac3641 commit 9c5717e
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 87 deletions.
122 changes: 37 additions & 85 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@
mod node;
mod path;
mod splay;

use splay::update_max;

use crate::{
node::{Node, Parent},
splay::splay,
splay::{splay, update_max},
};

pub struct LinkCutTree {
Expand All @@ -21,6 +18,10 @@ impl LinkCutTree {
Self { forest: nodes }
}

pub fn set_weight(&mut self, v: usize, weight: f64) {
self.forest[v].weight = weight;
}

// Constructs a path from a node to the root of the tree.
pub fn access(&mut self, v: usize) {
splay(&mut self.forest, v);
Expand Down Expand Up @@ -88,7 +89,6 @@ impl LinkCutTree {
#[cfg(test)]
mod tests {
use crate::node::Parent;
use rand::{seq::SliceRandom, Rng, SeedableRng};

#[test]
pub fn access_base_case() {
Expand Down Expand Up @@ -396,96 +396,48 @@ mod tests {

#[test]
pub fn findmax() {
let mut lctree = super::LinkCutTree::new(7);
lctree.forest[0].weight = 5.0;
let mut lctree = super::LinkCutTree::new(10);
lctree.forest[0].weight = 4.0;
lctree.forest[1].weight = 2.0;
lctree.forest[2].weight = 6.0;
lctree.forest[3].weight = 3.0;
lctree.forest[4].weight = 4.0;
lctree.forest[5].weight = 0.0;
lctree.forest[6].weight = 1.0;
lctree.forest[4].weight = 9.0;
lctree.forest[5].weight = 5.0;
lctree.forest[6].weight = 0.0;
lctree.forest[7].weight = 7.0;
lctree.forest[8].weight = 1.0;
lctree.forest[9].weight = 8.0;

// we form the following structure:
// 0(5)
// /
// 1(2)
// /
// 2(6)
// /
// 3(3)
// / \
// 4(4) 6(1)
// /
// 5(0)

// 0(4)
// / \
// 1(2) 5(5)
// / \ \
// 2(6) 3(3) 6(0)
// / \
// 4(9) 7(7)
// / \
// 8(1) 9(8)
lctree.link(1, 0);
lctree.link(2, 1);
lctree.link(3, 2);
lctree.link(4, 3);
lctree.link(5, 4);
lctree.link(6, 3);
lctree.link(3, 1);
lctree.link(4, 2);
lctree.link(5, 0);
lctree.link(6, 5);
lctree.link(7, 6);
lctree.link(8, 7);
lctree.link(9, 7);

assert_eq!(lctree.findmax(2), 2);
assert_eq!(lctree.findmax(6), 2);
// we check the node index with max weight in the path from each node to the root:
assert_eq!(lctree.findmax(0), 0);
assert_eq!(lctree.findmax(5), 2);
assert_eq!(lctree.findmax(3), 2);
assert_eq!(lctree.findmax(5), 5);
assert_eq!(lctree.findmax(1), 0);
assert_eq!(lctree.findmax(4), 2);

// we cut node 3 from its parent 2:
lctree.cut(3);
assert_eq!(lctree.findmax(5), 4);
assert_eq!(lctree.findmax(6), 3);
assert_eq!(lctree.findmax(4), 4);
assert_eq!(lctree.findmax(3), 3);
assert_eq!(lctree.findmax(8), 7);
assert_eq!(lctree.findmax(2), 2);
assert_eq!(lctree.findmax(1), 0);
assert_eq!(lctree.findmax(0), 0);
}

fn create_random_tree(n: usize, seed: u64) -> (Vec<(usize, usize)>, Vec<f64>, Vec<usize>) {
let mut rng = rand::rngs::StdRng::seed_from_u64(seed);

let mut edges = Vec::new();
let mut weights: Vec<f64> = (0..n).map(|i| i as f64).collect();
weights.shuffle(&mut rng);

let mut ground_truth = vec![0; n];
let mut in_tree = Vec::from([0]);
for i in 1..n {
let parent_idx = rng.gen_range(0..in_tree.len());
let parent = in_tree[parent_idx];
edges.push((i, parent));

ground_truth[i] = if weights[i] > weights[ground_truth[parent]] {
i
} else {
ground_truth[parent]
};
in_tree.push(i);
}

(edges, weights, ground_truth)
}

#[test]
pub fn findmax_random() {
let n = 100;
let seed = rand::thread_rng().gen();
let (edges, weights, ground_truth) = create_random_tree(n, seed);
let mut lctree = super::LinkCutTree::new(n);
for i in 0..n {
lctree.forest[i].weight = weights[i];
}

for (v, w) in edges {
lctree.link(v, w);
}

for _ in 0..n * 100 {
let v = rand::thread_rng().gen_range(0..n);
assert_eq!(lctree.findmax(v), ground_truth[v]);
}
assert_eq!(lctree.findmax(4), 4);
assert_eq!(lctree.findmax(7), 7);
assert_eq!(lctree.findmax(9), 9);
assert_eq!(lctree.findmax(3), 0);
assert_eq!(lctree.findmax(6), 5);
}
}
4 changes: 2 additions & 2 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ impl Node {
Parent::Root => "Root".to_string(),
};
format!(
"Node {{ idx: {}, left: {:?}, right: {:?}, parent: {:?}, max_weight_idx: {} }}",
self.idx, self.left, self.right, parent, self.max_weight_idx
"Node {{ idx: {}, left: {:?}, right: {:?}, parent: {parent:?}, max_weight_idx: {} }}",
self.idx, self.left, self.right, self.max_weight_idx
)
}
}
47 changes: 47 additions & 0 deletions tests/test_findmax_random.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use lctree::LinkCutTree;
use rand::{seq::SliceRandom, Rng, SeedableRng};

fn create_random_tree(n: usize, seed: u64) -> (Vec<(usize, usize)>, Vec<f64>, Vec<usize>) {
let mut rng = rand::rngs::StdRng::seed_from_u64(seed);

let mut edges = Vec::new();
let mut weights: Vec<f64> = (0..n).map(|i| i as f64).collect();
weights.shuffle(&mut rng);

let mut max_to_root = vec![0; n];
let mut in_tree = Vec::from([0]);
for i in 1..n {
let parent_idx = rng.gen_range(0..in_tree.len());
let parent = in_tree[parent_idx];
edges.push((i, parent));

max_to_root[i] = if weights[i] > weights[max_to_root[parent]] {
i
} else {
max_to_root[parent]
};
in_tree.push(i);
}

(edges, weights, max_to_root)
}

#[test]
pub fn findmax_random() {
let n = 100;
let seed = rand::thread_rng().gen();
let (edges, weights, max_to_root) = create_random_tree(n, seed);
let mut lctree = LinkCutTree::new(n);
for i in 0..n {
lctree.set_weight(i, weights[i]);
}

for (v, w) in edges {
lctree.link(v, w);
}

for _ in 0..n * 100 {
let v = rand::thread_rng().gen_range(0..n);
assert_eq!(lctree.findmax(v), max_to_root[v]);
}
}

0 comments on commit 9c5717e

Please sign in to comment.