Skip to content

Commit 6df13eb

Browse files
Docs (#11)
* add doc check to CI * fail on missing docs and warnings * sample docs * fix rmq doc tests * update docs for rmq & fenwick * add dsu docs * add DOCUMENTATION guidelines * make docs more minimal * update the documentation guidelines to reflect more minimal docs * document graphs & update lca test * add numbers docs * complete docs * fix docs * code coverage? * unable to fix code coverage --------- Co-authored-by: Luke Videckis <lukevideckis@gmail.com> Co-authored-by: Cameron Custer <custer.cameron@gmail.com>
1 parent 502f8d6 commit 6df13eb

File tree

15 files changed

+261
-24
lines changed

15 files changed

+261
-24
lines changed

.github/workflows/ci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,42 @@ jobs:
1414
steps:
1515
- uses: actions/checkout@v3
1616
- uses: actions/setup-python@v4
17+
1718
- name: Set up Rust (nightly)
1819
run: |
1920
rustup install nightly
2021
rustup override set nightly
2122
rustup component add --toolchain nightly rustfmt clippy
23+
2224
- name: cargo fmt
2325
run: cargo fmt --all -- --check
26+
2427
- name: cargo clippy
2528
run: cargo clippy --all-targets --all-features -- -D warnings
29+
2630
- name: cargo build
2731
run: cargo build
32+
2833
- name: cargo test
2934
run: cargo test
3035

36+
- name: cargo doc
37+
run: RUSTDOCFLAGS="-D warnings -D missing_docs" cargo doc --all
38+
3139
library_checker_aizu_tests:
3240
runs-on: ubuntu-latest
3341
steps:
3442
- uses: actions/checkout@v3
3543
- uses: actions/setup-python@v4
44+
3645
- name: Set up Rust (nightly)
3746
run: |
3847
rustup install nightly
3948
rustup override set nightly
4049
rustup component add --toolchain nightly rustfmt clippy
4150
cargo install cargo-binutils
4251
rustup component add llvm-tools-preview
52+
4353
- name: install oj-verify submodule
4454
run: |
4555
git submodule init
@@ -49,6 +59,7 @@ jobs:
4959
cd ..
5060
# clear submodule afterwards to not run tests in verification-helper
5161
git submodule deinit --all -f
62+
5263
- name: run tests
5364
# regarding `--jobs 4`: github CI runs with 4 cores
5465
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories
@@ -63,6 +74,7 @@ jobs:
6374
# since all tests are rerun on every commit anyways, there's no need for
6475
# the .verify-helper/timestamps.remote.json file
6576
run: oj-verify all --tle 20 --jobs 4 --timeout 21600
77+
6678
# https://doc.rust-lang.org/rustc/instrument-coverage.html
6779
# - name: code coverage
6880
# run: |

README.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
### Mission
1+
# Mission
22
To provide a collection of algorithms and data structures useful for competitive programming in Rust.
33

4-
### Focus
4+
# Focus
55
This library is written to be optimized for online contests \[Codeforces, AtCoder, etc.\]
66

77
Therefore the code is written with these three pillars:
@@ -11,14 +11,14 @@ Therefore the code is written with these three pillars:
1111

1212
Note: the code is **not** written for ICPC style contests and is **not** optimized for code length.
1313

14-
### Rust CF Blogs
14+
## Rust CF Blogs
1515

1616
- https://codeforces.com/blog/entry/67391
1717
- https://codeforces.com/blog/entry/103794
1818
- https://codeforces.com/blog/entry/111573
1919
- https://codeforces.com/blog/entry/125439
2020

21-
### Other Rust CP Repos
21+
## Other Rust CP Repos
2222

2323
- https://github.com/rust-lang-ja/ac-library-rs
2424
- https://github.com/EgorKulikov/rust_algo
@@ -27,3 +27,13 @@ Note: the code is **not** written for ICPC style contests and is **not** optimiz
2727
- https://github.com/qitoy/rust-library
2828
- https://github.com/stuart0035/procon-lib-rs
2929

30+
## Contributing
31+
32+
We're open to all feedback. You can submit an issue or email us at
33+
```
34+
lrvideckis@gmail.com
35+
```
36+
```
37+
custer.cameron@gmail.com
38+
```
39+

examples/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,8 @@
44
- when using both sites name the files `[algo]_yosupo.rs` and `[algo]_aizu.rs`
55
- when only testing a specific function or componenet of some algorithm name the file `[algo]_[component].rs`
66

7+
# Documentation Guidelines
8+
- use the `///` syntax for documentation
9+
- for structs, enums, traits, and standalone functions, provide an example testing every method
10+
- for member functions explain what the function does and provide the time and space complexity
11+

examples/graphs/lca_yosupo.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,35 @@ fn main() {
1010
}
1111

1212
// forest with an undirected tree and a rooted directed tree
13-
let mut adj = vec![vec![]; n + n];
14-
for v in 1..n {
13+
let mut undir_for = vec![vec![]; n + n];
14+
let mut dir = vec![vec![]; n];
15+
for c in 1..n {
1516
input! {
1617
p: usize,
1718
}
1819

1920
// undirected tree
20-
adj[p].push(v);
21-
adj[v].push(p);
21+
for &(u, v) in [(p, c), (p + n, c + n)].iter() {
22+
undir_for[u].push(v);
23+
undir_for[v].push(u);
24+
}
2225

2326
// directed tree
24-
adj[n + p].push(n + v);
27+
dir[p].push(c);
2528
}
2629

27-
let lca = LCA::new(&adj);
30+
let undir_lca = LCA::new(&undir_for);
31+
let dir_lca = LCA::new(&dir);
2832
for _ in 0..q {
2933
input! {
3034
u: usize,
3135
v: usize,
3236
}
33-
let res_undir = lca.lca(u, v);
34-
let res_dir = lca.lca(n + u, n + v) - n;
35-
assert!(res_undir == res_dir);
36-
println!("{}", res_undir);
37+
let res_undir1 = undir_lca.lca(u, v);
38+
let res_undir2 = undir_lca.lca(u + n, v + n) - n;
39+
let res_dir = dir_lca.lca(u, v);
40+
assert_eq!(res_undir1, res_undir2);
41+
assert_eq!(res_undir1, res_dir);
42+
println!("{}", res_dir);
3743
}
3844
}

src/data_structures/dsu.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,38 @@
1+
//! # Disjoint Set Union
2+
3+
/// # Example
4+
/// ```
5+
/// use programming_team_code_rust::data_structures::dsu::DSU;
6+
///
7+
/// let mut dsu = DSU::new(10);
8+
/// assert_eq!(dsu.same(1, 2), false);
9+
/// dsu.unite(1, 3);
10+
/// dsu.unite(2, 4);
11+
/// assert_eq!(dsu.same(1, 4), false);
12+
/// dsu.unite(2, 3);
13+
/// assert_eq!(dsu.same(1, 4), true);
14+
/// assert_eq!(dsu.leader(3), 2);
15+
/// assert_eq!(dsu.leader(5), 5);
16+
/// ```
117
pub struct DSU {
218
e: Vec<i32>,
319
}
20+
421
impl DSU {
22+
/// Create a new DSU with n elements
23+
///
24+
/// # Complexity
25+
/// - Time: O(n)
26+
/// - Space: O(n)
527
pub fn new(n: usize) -> Self {
628
DSU { e: vec![-1; n] }
729
}
30+
31+
/// Get the leader of the group that x belongs to
32+
///
33+
/// # Complexity
34+
/// - Time: O(α(n))
35+
/// - Space: O(1)
836
pub fn leader(&mut self, x: usize) -> usize {
937
if self.e[x] < 0 {
1038
x
@@ -15,9 +43,23 @@ impl DSU {
1543
r
1644
}
1745
}
46+
47+
/// Check if x and y belong to the same group
48+
///
49+
/// # Complexity
50+
/// - Time: O(α(n))
51+
/// - Space: O(1)
1852
pub fn same(&mut self, x: usize, y: usize) -> bool {
1953
self.leader(x) == self.leader(y)
2054
}
55+
56+
/// Unite the groups that x and y belong to
57+
/// Returns true if x and y were in different groups
58+
/// Returns false if x and y were in the same group
59+
///
60+
/// # Complexity
61+
/// - Time: O(α(n))
62+
/// - Space: O(1)
2163
pub fn unite(&mut self, x: usize, y: usize) -> bool {
2264
let mut x = self.leader(x);
2365
let mut y = self.leader(y);

src/data_structures/fenwick.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,57 @@
1+
//! # Fenwick Tree (Binary Indexed Tree)
2+
3+
/// # Example
4+
/// ```
5+
/// use programming_team_code_rust::data_structures::fenwick::Fenwick;
6+
///
7+
/// let mut fenwick = Fenwick::new(5);
8+
/// fenwick.add(1, 3);
9+
/// fenwick.add(2, 2);
10+
/// fenwick.add(3, 1);
11+
/// assert_eq!(fenwick.sum(1..3), 5);
12+
/// ```
113
pub struct Fenwick<T> {
214
ary: Vec<T>,
315
}
16+
417
impl<T: Clone + Default + std::ops::AddAssign<T>> Fenwick<T> {
18+
/// Creates a new Fenwick Tree with size n
19+
///
20+
/// # Complexity
21+
/// - Time: O(n)
22+
/// - Space: O(n)
523
pub fn new(n: usize) -> Self {
624
Fenwick {
725
ary: vec![T::default(); n],
826
}
927
}
10-
pub fn accum(&self, mut idx: usize) -> T {
28+
29+
fn accum(&self, mut idx: usize) -> T {
1130
let mut sum = T::default();
1231
while idx > 0 {
1332
sum += self.ary[idx - 1].clone();
1433
idx &= idx - 1;
1534
}
1635
sum
1736
}
18-
/// performs data[idx] += val;
37+
38+
/// Increments the value at `idx` by `val`
39+
///
40+
/// # Complexity
41+
/// - Time: O(log n)
42+
/// - Space: O(1)
1943
pub fn add(&mut self, mut idx: usize, val: T) {
2044
while idx < self.ary.len() {
2145
self.ary[idx] += val.clone();
2246
idx |= idx + 1;
2347
}
2448
}
25-
/// Returns data[l] + ... + data[r - 1].
49+
50+
/// Query the sum of the range [range.start, range.end)
51+
///
52+
/// # Complexity
53+
/// - Time: O(log n)
54+
/// - Space: O(1)
2655
pub fn sum(&self, range: std::ops::Range<usize>) -> T
2756
where
2857
T: std::ops::Sub<Output = T>,

src/data_structures/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//! # Data Structures
12
pub mod dsu;
23
pub mod fenwick;
34
pub mod rmq;

src/data_structures/rmq.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
1+
//! # Range Minimum Query
2+
3+
/// # Example
4+
/// ```
5+
/// use programming_team_code_rust::data_structures::rmq::RMQ;
6+
///
7+
/// let a = [1, 3, 2, 4, 5];
8+
/// let rmq = RMQ::new(&a, std::cmp::min);
9+
/// assert_eq!(rmq.query(0..5), 1);
10+
/// assert_eq!(rmq.query(1..4), 2);
11+
/// ```
112
pub struct RMQ<T> {
213
t: Vec<Vec<T>>,
314
op: fn(T, T) -> T,
415
}
16+
517
impl<T: Copy> RMQ<T> {
18+
/// Create a new RMQ instance
19+
///
20+
/// # Complexity (n = a.len())
21+
/// - Time: O(n log n)
22+
/// - Space: O(n log n)
623
pub fn new(a: &[T], op: fn(T, T) -> T) -> Self {
724
let mut t = vec![a.to_owned(); 1];
825
let mut i = 0;
@@ -17,6 +34,11 @@ impl<T: Copy> RMQ<T> {
1734
Self { t, op }
1835
}
1936

37+
/// Query the range [range.start, range.end)
38+
///
39+
/// # Complexity
40+
/// - Time: O(1)
41+
/// - Space: O(1)
2042
pub fn query(&self, range: std::ops::Range<usize>) -> T {
2143
let lg = range.len().ilog2() as usize;
2244
(self.op)(self.t[lg][range.start], self.t[lg][range.end - (1 << lg)])

src/graphs/dijk.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,34 @@
1-
use std::cmp::Reverse;
2-
use std::collections::BinaryHeap;
1+
//! # Dijkstra's algorithm
32
3+
/// # Example
4+
/// ```
5+
/// use programming_team_code_rust::graphs::dijk::dijk;
6+
///
7+
/// let adj = vec![
8+
/// vec![(1, 1), (2, 4)],
9+
/// vec![(2, 2), (3, 5)],
10+
/// vec![(3, 1)],
11+
/// vec![],
12+
/// vec![(0, 7)],
13+
/// vec![(1, 3), (3, 2)],
14+
/// vec![(0, 2), (2, 3)],
15+
/// vec![(1, 2), (4, 2)],
16+
/// ];
17+
///
18+
/// let dist = dijk(&adj, 0);
19+
/// assert_eq!(dist, vec![0, 1, 3, 4, u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
20+
/// ```
21+
///
22+
/// # Complexity
23+
/// - V: number of vertices
24+
/// - E: number of edges
25+
/// - Time: O(V + E log E)
26+
/// - Space: O(V + E)
427
pub fn dijk(adj: &[Vec<(usize, u64)>], s: usize) -> Vec<u64> {
28+
use std::cmp::Reverse;
529
let n = adj.len();
630
let mut dist = vec![u64::MAX; n];
7-
let mut q = BinaryHeap::new();
31+
let mut q = std::collections::BinaryHeap::new();
832
q.push(Reverse((0, s)));
933
while let Some(Reverse((d, u))) = q.pop() {
1034
if dist[u] <= d {

0 commit comments

Comments
 (0)