combinadics/lib.rs
1//! This crate provides methods to de- and encode numbers in the [combinatorial
2//! number system](https://en.wikipedia.org/wiki/Combinatorial_number_system),
3//! sometime referred to as "combinadics".
4
5#![cfg_attr(feature = "nightly", feature(test))]
6#[cfg(feature = "nightly")] extern crate test as rust_test;
7
8extern crate binomial_iter;
9
10use binomial_iter::{BinomialIter, DecNIter};
11
12/// Iterates through all choices decoded from the given `N` and `k` in
13/// descending order.
14#[allow(non_snake_case)]
15pub struct DecodeIter {
16 N: u32,
17 // The `n` holds the state for the 'remaining' iteration, see `next`.
18 n: u32,
19 bin: DecNIter,
20}
21
22/// Returns an iterator over the choices decoded from the given `N` and `k`.
23/// The choices will be returned by the iterator in descending order.
24///
25/// # Panics
26/// If `k == 0`
27#[allow(non_snake_case)]
28pub fn decode(N: u32, k: u32) -> DecodeIter {
29 assert!(k > 0, "invalid argument: `k == 0`");
30
31 let mut bin = BinomialIter::new(k, k);
32
33 // find the largest possible n
34 while bin.binom() < N {
35 bin.inc_n().expect("N too large to decode");
36 }
37
38 DecodeIter {
39 N: N,
40 n: bin.n(), // Initialize n to it's largest possible bin.n
41 bin: bin.iter_dec_n(),
42 }
43}
44
45impl Iterator for DecodeIter {
46 type Item = u32;
47
48 #[inline]
49 fn next(&mut self) -> Option<u32> {
50 // find the next choice
51 while let Some((n, binom)) = self.bin.next() {
52 if binom <= self.N {
53 self.bin.dec_k();
54 self.N -= binom;
55 return Some(n);
56 }
57 }
58
59 // `BinomialIter` does not support `n < k` so there may still be some
60 // choices left, to be precise, all `x < bin.n` still need to be printed.
61 // The first time this path is reached, initialize `self.n`.
62 if self.n > self.bin.n() {
63 self.n = self.bin.n();
64 }
65
66 if self.n > 0 {
67 self.n -= 1;
68 Some(self.n)
69 } else {
70 None
71 }
72 }
73}
74
75#[cfg(all(test, feature = "nightly"))]
76mod bench;
77
78#[cfg(test)]
79mod test;