number_encoding/
combinadics.rs

1// Copyright 2019-2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Combinatorial number system
16//!
17//! See [wikipedia] for more information.
18//!
19//! [wikipedia]: https://en.wikipedia.org/wiki/Combinatorial_number_system
20
21#[cfg(feature = "alloc")]
22use alloc::vec;
23#[cfg(feature = "alloc")]
24use alloc::vec::Vec;
25use core::borrow::BorrowMut;
26
27/// Writes the combination of a value to a slice.
28///
29/// The written combination can be encoded with [`encode`] to get back `n`.
30///
31/// ```rust
32/// # use number_encoding::combinadics::{decode_mut, encode};
33/// # let n = 5;
34/// # let k = 3;
35/// let mut xs = vec![0; k];
36/// decode_mut(n, k, &mut xs);
37/// assert_eq!(encode(&xs), n);
38/// ```
39///
40/// See [`decode`] for a version that allocates a vector for the combination.
41///
42/// # Panics
43///
44/// Panics in debug mode if `n > 0 && k == 0`.
45pub fn decode_mut(mut n: usize, mut k: usize, r: &mut [usize]) {
46    debug_assert_eq!(r.len(), k, "Failed precondition");
47    debug_assert!(k > 0 || n == 0, "Failed precondition");
48    while k > 0 {
49        let mut i = k;
50        let mut x = 1;
51        while x <= n {
52            i += 1;
53            x *= i;
54            x /= i - k;
55        }
56        x *= i - k;
57        x /= i;
58        i -= 1;
59        n -= x;
60        k -= 1;
61        r[k] = i;
62    }
63}
64
65/// Returns the combination of a value.
66///
67/// The returned combination can be encoded with [`encode`] to get back `n`.
68///
69/// ```rust
70/// # use number_encoding::combinadics::{decode, encode};
71/// let n = 5;
72/// let k = 3;
73/// let xs = decode(n, k);
74/// assert_eq!(encode(&xs), 5);
75/// ```
76///
77/// See [`decode_mut`] for a version that writes the combination to a provided slice.
78///
79/// # Panics
80///
81/// Panics in debug mode if `n > 0 && k == 0`.
82///
83/// # Examples
84///
85/// ```rust
86/// # use number_encoding::combinadics::decode;
87/// assert_eq!(decode(0, 3), &[0, 1, 2]);
88/// assert_eq!(decode(1, 3), &[0, 1, 3]);
89/// assert_eq!(decode(2, 3), &[0, 2, 3]);
90/// ```
91#[cfg(feature = "alloc")]
92pub fn decode(n: usize, k: usize) -> Vec<usize> {
93    let mut r = vec![0; k];
94    decode_mut(n, k, &mut r);
95    r
96}
97
98#[test]
99fn decode_ok() {
100    fn test(n: usize, k: usize, r: &[usize]) {
101        assert_eq!(decode(n, k), r, "n={n} k={k}");
102    }
103    test(0, 0, &[]);
104    test(0, 1, &[0]);
105    test(1, 1, &[1]);
106    test(2, 1, &[2]);
107    test(0, 2, &[0, 1]);
108    test(1, 2, &[0, 2]);
109    test(2, 2, &[1, 2]);
110    test(3, 2, &[0, 3]);
111    test(0, 3, &[0, 1, 2]);
112    test(1, 3, &[0, 1, 3]);
113    test(2, 3, &[0, 2, 3]);
114    test(3, 3, &[1, 2, 3]);
115    test(4, 3, &[0, 1, 4]);
116    test(5, 3, &[0, 2, 4]);
117    test(6, 3, &[1, 2, 4]);
118    test(7, 3, &[0, 3, 4]);
119    test(8, 3, &[1, 3, 4]);
120    test(9, 3, &[2, 3, 4]);
121    test(10, 3, &[0, 1, 5]);
122}
123
124/// Returns the value of a combination.
125///
126/// The returned value can be decoded with [`decode`] to get back `xs`.
127///
128/// ```rust
129/// # use number_encoding::combinadics::{decode, encode};
130/// # let xs = &[0, 2, 4];
131/// let k = xs.len();
132/// let n = encode(xs);
133/// assert_eq!(decode(n, k), xs);
134/// ```
135///
136/// # Panics
137///
138/// Panics in debug mode if `xs` is not increasing.
139///
140/// # Examples
141///
142/// ```rust
143/// # use number_encoding::combinadics::encode;
144/// assert_eq!(encode(&[0, 1, 2]), 0);
145/// assert_eq!(encode(&[0, 1, 3]), 1);
146/// assert_eq!(encode(&[0, 2, 3]), 2);
147/// assert_eq!(encode(&[1, 2, 3]), 3);
148/// assert_eq!(encode(&[0, 1, 4]), 4);
149/// assert_eq!(encode(&[0, 2, 4]), 5);
150/// ```
151pub fn encode(xs: &[usize]) -> usize {
152    debug_assert!(crate::is_ordered_set(xs), "Failed precondition");
153    let mut r = 0;
154    for (i, &x) in xs.iter().enumerate() {
155        r += crate::combination(x, i + 1);
156    }
157    r
158}
159
160#[test]
161fn encode_ok() {
162    fn test(xs: &[usize], r: usize) {
163        assert_eq!(encode(xs), r, "xs={xs:?}");
164    }
165    test(&[], 0);
166    test(&[0], 0);
167    test(&[1], 1);
168    test(&[0, 1], 0);
169    test(&[0, 2], 1);
170    test(&[1, 2], 2);
171    test(&[0, 3], 3);
172    test(&[0, 1, 2], 0);
173    test(&[0, 1, 3], 1);
174    test(&[0, 2, 3], 2);
175    test(&[1, 2, 3], 3);
176    test(&[0, 1, 4], 4);
177    test(&[0, 2, 4], 5);
178    test(&[1, 2, 4], 6);
179    test(&[0, 3, 4], 7);
180    test(&[1, 3, 4], 8);
181    test(&[2, 3, 4], 9);
182    test(&[0, 1, 5], 10);
183}
184
185/// Iterates over all k-combinations.
186///
187/// The k-combinations are iterated in value order:
188///
189/// ```rust
190/// # use number_encoding::combinadics::{Iter, encode};
191/// # use number_encoding::combination;
192/// # let n = 5;
193/// # let k = 3;
194/// let mut iter = Iter::new(k);
195/// for i in 0 .. combination(n, k) {
196///     assert_eq!(encode(iter.get()), i);
197///     iter.advance();
198/// }
199/// ```
200///
201/// # Examples
202///
203/// To iterate over all `k`-combinations in a set of `n` elements:
204///
205/// ```rust
206/// # use number_encoding::combinadics::Iter;
207/// # use number_encoding::combination;
208/// # fn process(xs: &[usize]) {}
209/// # let n = 5;
210/// # let k = 3;
211/// let mut iter = Iter::new(k);
212/// for _ in 0 .. combination(n, k) {
213///     process(iter.get());
214///     iter.advance();
215/// }
216/// ```
217///
218/// In a no-std environment, you can pass a buffer of size `K`:
219///
220/// ```rust
221/// # use number_encoding::combinadics::Iter;
222/// # const K: usize = 3;
223/// let mut buffer = [0usize; K];
224/// let mut iter = Iter::new_with_buffer(&mut buffer[..]);
225/// ```
226pub struct Iter<T: BorrowMut<[usize]>> {
227    data: T,
228}
229
230#[cfg(feature = "alloc")]
231impl Iter<Vec<usize>> {
232    /// Constructs an iterator.
233    pub fn new(k: usize) -> Iter<Vec<usize>> {
234        Iter { data: (0 .. k).collect() }
235    }
236}
237
238impl<T: BorrowMut<[usize]>> Iter<T> {
239    /// Constructs an iterator with a buffer.
240    pub fn new_with_buffer(mut buffer: T) -> Iter<T> {
241        for (i, x) in buffer.borrow_mut().iter_mut().enumerate() {
242            *x = i;
243        }
244        Iter { data: buffer }
245    }
246
247    /// Constructs an iterator starting from a given k-combination.
248    ///
249    /// # Panics
250    ///
251    /// Panics in debug mode if `xs` is not increasing.
252    pub fn new_from(xs: T) -> Iter<T> {
253        debug_assert!(crate::is_ordered_set(xs.borrow()), "Failed precondition");
254        Iter { data: xs }
255    }
256
257    /// Returns the current combination.
258    pub fn get(&self) -> &[usize] {
259        self.data.borrow()
260    }
261
262    /// Advances to the next combination.
263    pub fn advance(&mut self) {
264        let k = self.data.borrow().len();
265        for i in 0 .. k {
266            self.data.borrow_mut()[i] += 1;
267            if i == k - 1 || self.data.borrow()[i] < self.data.borrow()[i + 1] {
268                break;
269            }
270            self.data.borrow_mut()[i] = i;
271        }
272    }
273}
274
275#[test]
276fn iter_ok() {
277    fn test(k: usize, r: &[&[usize]]) {
278        let mut iter = Iter::new(k);
279        for (i, &r) in r.iter().enumerate() {
280            assert_eq!(iter.get(), r);
281            assert_eq!(encode(r), i);
282            iter.advance();
283        }
284    }
285    test(0, &[&[]]);
286    test(1, &[&[0], &[1], &[2]]);
287    test(2, &[&[0, 1], &[0, 2], &[1, 2], &[0, 3], &[1, 3], &[2, 3]]);
288    test(
289        3,
290        &[
291            &[0, 1, 2],
292            &[0, 1, 3],
293            &[0, 2, 3],
294            &[1, 2, 3],
295            &[0, 1, 4],
296            &[0, 2, 4],
297            &[1, 2, 4],
298            &[0, 3, 4],
299            &[1, 3, 4],
300            &[2, 3, 4],
301            &[0, 1, 5],
302            &[0, 2, 5],
303            &[1, 2, 5],
304        ],
305    );
306}
307
308#[test]
309fn iter_new_from_ok() {
310    fn test(xs: &[usize], r: &[&[usize]]) {
311        let mut iter = Iter::new_from(xs.to_vec());
312        let start = encode(xs);
313        for (i, &r) in r.iter().enumerate() {
314            assert_eq!(iter.get(), r);
315            assert_eq!(encode(r), start + i);
316            iter.advance();
317        }
318    }
319    test(&[], &[&[]]);
320    test(&[2], &[&[2], &[3], &[4]]);
321    test(&[0, 3], &[&[0, 3], &[1, 3], &[2, 3]]);
322    test(
323        &[0, 2, 4],
324        &[
325            &[0, 2, 4],
326            &[1, 2, 4],
327            &[0, 3, 4],
328            &[1, 3, 4],
329            &[2, 3, 4],
330            &[0, 1, 5],
331            &[0, 2, 5],
332            &[1, 2, 5],
333        ],
334    );
335}