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;