Skip to content

Commit

Permalink
include custom path aggr. usage
Browse files Browse the repository at this point in the history
  • Loading branch information
azizkayumov committed Nov 6, 2023
1 parent b1aeba8 commit d62b36c
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 73 deletions.
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,30 @@ impl Path for FindXor {
}

fn main() {
// We form a link-cut tree from the following rooted tree
// (the numbers in parentheses are the weights of the nodes):
// a(9)
// / \
// b(1) e(2)
// / \ \
// c(8) d(10) f(4)
let mut lctree: LinkCutTree<FindXor> = LinkCutTree::new();
...
let a = lctree.make_tree(9.);
let b = lctree.make_tree(1.);
let c = lctree.make_tree(8.);
let d = lctree.make_tree(10.);
let e = lctree.make_tree(2.);
let f = lctree.make_tree(4.);

lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);

// We find the xor of the weights on the path between c to f,
let result = lctree.path(c, f);
assert_eq!(result.xor, 8 ^ 1 ^ 9 ^ 2 ^ 4);
}
```

Expand Down
74 changes: 2 additions & 72 deletions tests/test_random.rs
Original file line number Diff line number Diff line change
@@ -1,81 +1,11 @@
use lctree::{FindMax, LinkCutTree};
use lctree::LinkCutTree;
use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng};
use rand_derive2::RandGen;
use std::collections::{HashMap, HashSet};

#[test]
pub fn basic_usage() {
// We form a link-cut tree from the following rooted tree:
// a
// / \
// b e
// / \ \
// c d f
let mut lctree = lctree::LinkCutTree::default();
let a = lctree.make_tree(0.0);
let b = lctree.make_tree(1.0);
let c = lctree.make_tree(2.0);
let d = lctree.make_tree(3.0);
let e = lctree.make_tree(4.0);
let f = lctree.make_tree(5.0);
lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);

// Checking connectivity:
assert!(lctree.connected(c, f)); // connected

// We cut node e from its parent a:
lctree.cut(e, a);

// The forest should now look like this:
// a
// /
// b e
// / \ \
// c d f

// We check connectivity again:
assert!(!lctree.connected(c, f)); // not connected anymore
}

#[test]
pub fn path_aggregation() {
// We form a link-cut tree from the following rooted tree
// (the numbers in parentheses are the weights of the nodes):
// a(9)
// / \
// b(1) e(2)
// / \ \
// c(8) d(0) f(4)

// Replace FindMax with FindMin or FindSum, depending on your usage:
let mut lctree: LinkCutTree<FindMax> = lctree::LinkCutTree::new();
let a = lctree.make_tree(9.);
let b = lctree.make_tree(1.);
let c = lctree.make_tree(8.);
let d = lctree.make_tree(0.);
let e = lctree.make_tree(2.);
let f = lctree.make_tree(4.);

lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);

// We find the node with max weight on the path between c to f,
// where a has the maximum weight of 9.0:
let heaviest_node = lctree.path(c, f);
assert_eq!(heaviest_node.idx, a);
assert_eq!(heaviest_node.weight, 9.0);
}

#[test]
pub fn validation() {
// These can be larger if you have time to spare (see tests/README.md)
// These can be larger if you have time to spare:
let num_nodes: usize = 100;
let num_operations: usize = 2000;

Expand Down
114 changes: 114 additions & 0 deletions tests/test_usage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use lctree::{FindMax, LinkCutTree, Path};

#[test]
pub fn basic_usage() {
// We form a link-cut tree from the following rooted tree:
// a
// / \
// b e
// / \ \
// c d f
let mut lctree = lctree::LinkCutTree::default();
let a = lctree.make_tree(0.);
let b = lctree.make_tree(0.);
let c = lctree.make_tree(0.);
let d = lctree.make_tree(0.);
let e = lctree.make_tree(0.);
let f = lctree.make_tree(0.);
lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);

// Checking connectivity:
assert!(lctree.connected(c, f)); // connected

// We cut node e from its parent a:
lctree.cut(e, a);

// The forest should now look like this:
// a
// /
// b e
// / \ \
// c d f

// We check connectivity again:
assert!(!lctree.connected(c, f)); // not connected anymore
}

#[test]
pub fn path_aggregation() {
// We form a link-cut tree from the following rooted tree
// (the numbers in parentheses are the weights of the nodes):
// a(9)
// / \
// b(1) e(2)
// / \ \
// c(8) d(10) f(4)

// Replace FindMax with FindMin or FindSum, depending on your usage:
let mut lctree: LinkCutTree<FindMax> = lctree::LinkCutTree::new();
let a = lctree.make_tree(9.);
let b = lctree.make_tree(1.);
let c = lctree.make_tree(8.);
let d = lctree.make_tree(10.);
let e = lctree.make_tree(2.);
let f = lctree.make_tree(4.);

lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);

// We find the node with max weight on the path between c to f,
// where a has the maximum weight of 9.0:
let heaviest_node = lctree.path(c, f);
assert_eq!(heaviest_node.idx, a);
assert_eq!(heaviest_node.weight, 9.0);
}

#[derive(Copy, Clone)]
pub struct FindXor {
pub xor: u64,
}

impl Path for FindXor {
fn default(weight: f64, _: usize) -> Self {
FindXor { xor: weight as u64 }
}

fn aggregate(&mut self, other: Self) {
self.xor ^= other.xor;
}
}

#[test]
pub fn custom_path_aggregation() {
// We form a link-cut tree from the following rooted tree
// (the numbers in parentheses are the weights of the nodes):
// a(9)
// / \
// b(1) e(2)
// / \ \
// c(8) d(10) f(4)
let mut lctree: LinkCutTree<FindXor> = LinkCutTree::new();
let a = lctree.make_tree(9.);
let b = lctree.make_tree(1.);
let c = lctree.make_tree(8.);
let d = lctree.make_tree(10.);
let e = lctree.make_tree(2.);
let f = lctree.make_tree(4.);

lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);

// We find the xor of the weights on the path between c to f,
let result = lctree.path(c, f);
assert_eq!(result.xor, 8 ^ 1 ^ 9 ^ 2 ^ 4);
}

0 comments on commit d62b36c

Please sign in to comment.