binomial_iter/
lib.rs

1//! This crate provides tools to iteratively compute the binomial coefficient.
2
3use std::ops;
4
5#[inline(always)]
6fn gcd(mut u: u32, mut v: u32) -> u32 {
7    if u == 0 || v == 0 { return 1 } // This is mathematically not necessarily
8                                     // but acceptable for our uses (and better
9                                     // than returning 0.
10
11    while v > 0 {
12        let t = u;
13        u = v;
14        v = t % v;
15    }
16    u
17}
18
19/// Calculate (a * b) / c after removing the gcd. This function should only be
20/// used if the result is guaranteed to be an integer.
21#[inline(always)]
22fn mul_div_gcd(mut a: u32, mut b: u32, mut c: u32) -> Option<u32> {
23    let g = gcd(a, c);
24    a /= g;
25    c /= g;
26    let g = gcd(b, c);
27    b /= g;
28    c /= g;
29    a.checked_mul(b).and_then(|ab| ab.checked_div(c))
30}
31
32fn binom(n: u32, k: u32) -> u32 {
33    if k == 0 || k == n {
34        1
35    } else if n < k {
36        0
37    } else {
38        mul_div_gcd(binom(n - 1, k - 1), n, k).expect(&format!("cannot calculate `{}` choose `{}`, would overflow", n, k))
39    }
40}
41
42/// Provides methods to calculate the binomial coefficient for the next
43/// higher/lower `n`/`k`.
44#[derive(Copy, Clone, PartialEq, Eq)]
45pub struct BinomialIter {
46    n: u32,
47    k: u32,
48    binom: u32,
49}
50
51impl BinomialIter {
52    /// Create a new `BinomialIter`. This will calculate the binomial
53    /// coefficient once using the recursive definition.
54    ///
55    /// # Panics
56    /// If `k > n`
57    #[inline]
58    pub fn new(n: u32, k: u32) -> BinomialIter {
59        assert!(k <= n, "k <= is currently no supported");
60
61        BinomialIter {
62            n: n,
63            k: k,
64            binom: binom(n, k),
65        }
66    }
67
68    /// Access the current value of `n`.
69    #[inline]
70    pub fn n(&self) -> u32 { self.n }
71
72    /// Access the current value of `k`.
73    #[inline]
74    pub fn k(&self) -> u32 { self.k }
75
76    /// Access the current value of `n` choose `k`.
77    #[inline]
78    pub fn binom(&self) -> u32 { self.binom }
79
80    /// Increase `n` by one and update the internal state accordingly.
81    ///
82    /// Returns `None` when calculating `n + 1` choose `k` would overflow,
83    /// otherwise `Some((n + 1, binom))`.
84    #[inline]
85    pub fn inc_n(&mut self) -> Option<(u32, u32)> {
86        match mul_div_gcd(self.binom, self.n + 1, self.n + 1 - self.k) {
87            Some(binom) => {
88                self.n += 1;
89                self.binom = binom;
90                Some((self.n, binom))
91            }
92            _ => None,
93        }
94    }
95
96    /// Decrease `n` by one and update the internal state accordingly.
97    ///
98    /// Returns `None` when calculating `n - 1` choose `k` would overflow or
99    /// `n - 1 < k`, otherwise `Some((n - 1, binom))`.
100    #[inline]
101    pub fn dec_n(&mut self) -> Option<(u32, u32)> {
102        match mul_div_gcd(self.binom, self.n - self.k, self.n) {
103            Some(binom) if self.n > self.k => {
104                self.n -= 1;
105                self.binom = binom;
106                Some((self.n, binom))
107            }
108            _ => None,
109        }
110    }
111
112    /// Increase `k` by one and update the internal state accordingly.
113    ///
114    /// Returns `None` when calculating `n` choose `k + 1` would overflow or
115    /// `n < k + 1`, otherwise `Some((k + 1, binom))`.
116    #[inline]
117    pub fn inc_k(&mut self) -> Option<(u32, u32)> {
118        match mul_div_gcd(self.binom, self.n - self.k, self.k + 1) {
119            Some(binom) if self.n > self.k => {
120                self.k += 1;
121                self.binom = binom;
122                Some((self.k, binom))
123            }
124            _ => None
125        }
126    }
127
128    /// Decrease `k` by one and update the internal state accordingly.
129    ///
130    /// Returns `None` when calculating `n` choose `k - 1` would overflow or
131    /// `k - 1 < 0`, otherwise `Some((k - 1, binom))`
132    #[inline]
133    pub fn dec_k(&mut self) -> Option<(u32, u32)> {
134        match mul_div_gcd(self.binom, self.k, self.n - self.k + 1) {
135            Some(binom) if self.k > 0 => {
136                self.k -= 1;
137                self.binom = binom;
138                Some((self.k, binom))
139            }
140            _ => None
141        }
142    }
143}
144
145macro_rules! def_iter {{
146    $(#[$($iter_doc:meta)*])*
147    > $Iter:ident: $nk:ident, $nfn:ident;
148    $(#[$($cfn_doc:meta)*])*
149    > $cfn:ident
150} => {
151    $(#[$($iter_doc)*])*
152    pub struct $Iter {
153        inner: BinomialIter,
154        first: bool,
155    }
156
157    impl BinomialIter {
158        $(#[$($cfn_doc)*])*
159        #[inline]
160        pub fn $cfn(self) -> $Iter {
161            $Iter {
162                inner: self,
163                first: true,
164            }
165        }
166    }
167
168    impl Iterator for $Iter {
169        type Item = (u32, u32);
170
171        #[inline]
172        fn next(&mut self) -> Option<(u32, u32)> {
173            if self.first {
174                self.first = false;
175                Some((self.inner.$nk, self.inner.binom))
176            } else {
177                self.inner.$nfn()
178            }
179        }
180    }
181
182    impl ops::Deref for $Iter {
183        type Target = BinomialIter;
184
185        fn deref(&self) -> &BinomialIter {
186            &self.inner
187        }
188    }
189
190    impl ops::DerefMut for $Iter {
191        fn deref_mut(&mut self) -> &mut BinomialIter {
192            &mut self.inner
193        }
194    }
195}}
196
197def_iter! {
198    /// An iterator which wraps a `BinomialIter` and returns the result of it's
199    /// `inc_n` method when `next` is called.
200    > IncNIter: n, inc_n;
201    /// Returns an iterator which wraps this `BinomialIter`, returns the current
202    /// value of `n` and `binom` on the first call to `next` and the result of
203    /// calling `inc_n` on the underlying `BinominalIter` for subsequent calls
204    /// to next.
205    > iter_inc_n
206}
207
208def_iter! {
209    /// An iterator which wraps a `BinomialIter` and returns the result of it's
210    /// `dec_n` method when `next` is called.
211    > DecNIter: n, dec_n;
212    /// Returns an iterator which wraps this `BinomialIter`, returns the current
213    /// value of `n` and `binom` on the first call to `next` and the result of
214    /// calling `dec_n` on the underlying `BinominalIter` for subsequent calls
215    /// to next.
216    > iter_dec_n
217}
218
219def_iter! {
220    /// An iterator which wraps a `BinomialIter` and returns the result of it's
221    /// `inc_k` method when `next` is called.
222    > IncKIter: k, inc_k;
223    /// Returns an iterator which wraps this `BinomialIter`, returns the current
224    /// value of `k` and `binom` on the first call to `next` and the result of
225    /// calling `inc_k` on the underlying `BinominalIter` for subsequent calls
226    /// to next.
227    > iter_inc_k
228}
229
230def_iter! {
231    /// An iterator which wraps a `BinomialIter` and returns the result of it's
232    /// `dec_k` method when `next` is called.
233    > DecKIter: k, dec_k;
234    /// Returns an iterator which wraps this `BinomialIter`, returns the current
235    /// value of `k` and `binom` on the first call to `next` and the result of
236    /// calling `dec_k` on the underlying `BinominalIter` for subsequent calls
237    /// to next.
238    > iter_dec_k
239}
240
241#[cfg(test)]
242mod test;