number_encoding/
multinadics.rs

1// Copyright 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//! Multinomial number system
16//!
17//! See [wikipedia] for more information.
18//!
19//! [wikipedia]: https://en.wikipedia.org/wiki/Multinomial_theorem#Multinomial_coefficients
20
21#[cfg(feature = "alloc")]
22use alloc::vec::Vec;
23
24/// Applies the multiset permutation of the value `p` to the slice `xs`.
25///
26/// The applied multiset permutation can be encoded with [`encode`] to get back `p`.
27///
28/// ```rust
29/// # use number_encoding::multinadics::{decode_mut, encode};
30/// # let mut xs = [0, 0, 0, 1, 1, 2];
31/// # let p = 15;
32/// decode_mut(&mut xs, p);
33/// assert_eq!(encode(&xs), p);
34/// ```
35///
36/// See [`decode`] for a version that allocates a vector for the permutation.
37///
38/// # Panics
39///
40/// Panics in debug mode if `xs` is not non-decreasing or `p` is out of range.
41pub fn decode_mut<T: Ord>(xs: &mut [T], mut p: usize) {
42    let mut m = crate::multinomial(xs);
43    debug_assert!(crate::is_ordered_multiset(xs), "Failed precondition");
44    debug_assert!(p < m, "Failed precondition");
45    let n = xs.len();
46    for i in 0 .. n {
47        let mut c = i;
48        let mut k = 1;
49        for j in i + 1 .. n {
50            if xs[j] == xs[j - 1] {
51                k += 1;
52                continue;
53            }
54            let s = m * k / (n - i);
55            if p < s {
56                break;
57            }
58            p -= s;
59            c = j;
60            k = 1;
61        }
62        m = m * k / (n - i);
63        xs[i ..= c].rotate_right(1);
64    }
65    debug_assert_eq!(m, 1);
66    debug_assert_eq!(p, 0);
67}
68
69/// Returns the multiset permutation of the value `p` to the slice `xs`.
70///
71/// The returned multiset permutation can be encoded with [`encode`] to get back `p`.
72///
73/// ```rust
74/// # use number_encoding::multinadics::{decode, encode};
75/// # let xs = [0, 0, 0, 1, 1, 2];
76/// # let p = 15;
77/// let xs = decode(&xs, p);
78/// assert_eq!(encode(&xs), p);
79/// ```
80///
81/// See [`decode_mut`] for a version that applies the multiset permutation to the slice.
82///
83/// # Panics
84///
85/// Panics in debug mode if `xs` is not non-decreasing or `p` is out of range.
86///
87/// # Examples
88///
89/// ```rust
90/// # use number_encoding::multinadics::decode;
91/// assert_eq!(decode(&[0, 0, 1], 0), &[0, 0, 1]);
92/// assert_eq!(decode(&[0, 0, 1], 1), &[0, 1, 0]);
93/// assert_eq!(decode(&[0, 0, 1], 2), &[1, 0, 0]);
94/// ```
95#[cfg(feature = "alloc")]
96pub fn decode<T: Clone + Ord>(xs: &[T], p: usize) -> Vec<T> {
97    let mut xs = xs.to_vec();
98    decode_mut(&mut xs[..], p);
99    xs
100}
101
102#[test]
103fn decode_ok() {
104    fn test(xs: &[usize], p: usize, e: &[usize]) {
105        let r = decode(xs, p);
106        assert_eq!(r, e, "xs={xs:?} p={p}");
107    }
108    test(&[], 0, &[]);
109    test(&[0], 0, &[0]);
110    test(&[0, 1], 0, &[0, 1]);
111    test(&[0, 1], 1, &[1, 0]);
112    test(&[0, 0], 0, &[0, 0]);
113    test(&[0, 0, 1], 0, &[0, 0, 1]);
114    test(&[0, 0, 1], 1, &[0, 1, 0]);
115    test(&[0, 0, 1], 2, &[1, 0, 0]);
116    test(&[0, 0, 1, 1], 0, &[0, 0, 1, 1]);
117    test(&[0, 0, 1, 1], 1, &[0, 1, 0, 1]);
118    test(&[0, 0, 1, 1], 2, &[0, 1, 1, 0]);
119    test(&[0, 0, 1, 1], 3, &[1, 0, 0, 1]);
120    test(&[0, 0, 1, 1], 4, &[1, 0, 1, 0]);
121    test(&[0, 0, 1, 1], 5, &[1, 1, 0, 0]);
122    test(&[0, 0, 0, 1, 1, 2], 0, &[0, 0, 0, 1, 1, 2]);
123    test(&[0, 0, 0, 1, 1, 2], 1, &[0, 0, 0, 1, 2, 1]);
124    test(&[0, 0, 0, 1, 1, 2], 2, &[0, 0, 0, 2, 1, 1]);
125    test(&[0, 0, 0, 1, 1, 2], 3, &[0, 0, 1, 0, 1, 2]);
126    test(&[0, 0, 0, 1, 1, 2], 4, &[0, 0, 1, 0, 2, 1]);
127    test(&[0, 0, 0, 1, 1, 2], 5, &[0, 0, 1, 1, 0, 2]);
128    test(&[0, 0, 0, 1, 1, 2], 6, &[0, 0, 1, 1, 2, 0]);
129    test(&[0, 0, 0, 1, 1, 2], 7, &[0, 0, 1, 2, 0, 1]);
130    test(&[0, 0, 0, 1, 1, 2], 8, &[0, 0, 1, 2, 1, 0]);
131    test(&[0, 0, 0, 1, 1, 2], 9, &[0, 0, 2, 0, 1, 1]);
132    test(&[0, 0, 0, 1, 1, 2], 10, &[0, 0, 2, 1, 0, 1]);
133}
134
135/// Returns the value of a multiset permutation.
136///
137/// The returned value can be decoded with [`decode`] to get back `xs`.
138///
139/// ```rust
140/// # use number_encoding::multinadics::{decode, encode};
141/// # let xs = &[0, 1, 1, 0, 2, 0];
142/// let mut ys = xs.to_vec();
143/// ys.sort();
144/// let p = encode(xs);
145/// assert_eq!(decode(&ys, p), xs);
146/// ```
147///
148/// # Examples
149///
150/// ```rust
151/// # use number_encoding::multinadics::encode;
152/// assert_eq!(encode(&[0, 0, 1]), 0);
153/// assert_eq!(encode(&[0, 1, 0]), 1);
154/// assert_eq!(encode(&[1, 0, 0]), 2);
155/// ```
156pub fn encode<T: Ord>(xs: &[T]) -> usize {
157    let n = xs.len();
158    let mut m = crate::multinomial(xs);
159    let mut r = 0;
160    for i in 0 .. n {
161        for j in i + 1 .. n {
162            if xs[j] >= xs[i] || xs[i + 1 .. j].contains(&xs[j]) {
163                continue;
164            }
165            let k = xs[j ..].iter().filter(|&x| x == &xs[j]).count();
166            r += m * k / (n - i);
167        }
168        let k = xs[i ..].iter().filter(|&x| x == &xs[i]).count();
169        m = m * k / (n - i);
170    }
171    debug_assert_eq!(m, 1);
172    r
173}
174
175#[test]
176fn encode_ok() {
177    fn test(xs: &[usize], p: usize) {
178        assert_eq!(encode(xs), p, "xs={xs:?}");
179    }
180    test(&[], 0);
181    test(&[0], 0);
182    test(&[0, 1], 0);
183    test(&[1, 0], 1);
184    test(&[0, 0], 0);
185    test(&[0, 0, 1], 0);
186    test(&[0, 1, 0], 1);
187    test(&[1, 0, 0], 2);
188    test(&[0, 0, 1, 1], 0);
189    test(&[0, 1, 0, 1], 1);
190    test(&[0, 1, 1, 0], 2);
191    test(&[1, 0, 0, 1], 3);
192    test(&[1, 0, 1, 0], 4);
193    test(&[1, 1, 0, 0], 5);
194}
195
196/// Iterates over all multiset permutations of a slice.
197///
198/// The multiset permutations are iterated in value order:
199///
200/// ```rust
201/// # use number_encoding::multinadics::{Iter, encode};
202/// # let mut xs = [0, 0, 0, 1, 1, 2];
203/// let mut iter = Iter::new(&mut xs);
204/// let mut i = 0;
205/// while let Some(xs) = iter.next() {
206///     assert_eq!(encode(xs), i);
207///     i += 1;
208/// }
209/// ```
210///
211/// If the iteration goes to the end (i.e. [`next`](Iter::next) returns `None`), then the slice is
212/// restored to its initial value (i.e. non-decreasing):
213///
214/// ```rust
215/// # use number_encoding::multinadics::Iter;
216/// # let mut xs = [0, 0, 0, 1, 1, 2];
217/// let saved_xs = xs.clone();
218/// let mut iter = Iter::new(&mut xs);
219/// while iter.next().is_some() {}
220/// assert_eq!(xs, saved_xs);
221/// ```
222///
223/// # Examples
224///
225/// ```rust
226/// # use number_encoding::multinadics::Iter;
227/// # fn process(xs: &[usize]) {}
228/// # let mut xs = [0, 0, 0, 1, 1, 2];
229/// let mut iter = Iter::new(&mut xs);
230/// while let Some(xs) = iter.next() {
231///     process(xs);
232/// }
233/// ```
234pub struct Iter<'a, T> {
235    data: &'a mut [T],
236    state: IterState,
237}
238
239enum IterState {
240    New,
241    Running,
242    Done,
243}
244
245impl<'a, T: Ord> Iter<'a, T> {
246    /// Constructs an iterator with a non-decreasing slice.
247    ///
248    /// # Panics
249    ///
250    /// Panics in debug mode if `xs` is not non-decreasing.
251    pub fn new(xs: &mut [T]) -> Iter<T> {
252        debug_assert!(crate::is_ordered_multiset(xs));
253        Iter { data: xs, state: IterState::New }
254    }
255
256    /// Returns the next permutation.
257    ///
258    /// If iteration is over, returns `None`.
259    #[allow(clippy::should_implement_trait)]
260    pub fn next(&mut self) -> Option<&[T]> {
261        match self.state {
262            IterState::New => self.state = IterState::Running,
263            IterState::Running => {
264                if self.advance() {
265                    self.state = IterState::Done;
266                }
267            }
268            IterState::Done => (),
269        }
270        match self.state {
271            IterState::New => unreachable!(),
272            IterState::Running => Some(self.data),
273            IterState::Done => None,
274        }
275    }
276
277    fn advance(&mut self) -> bool {
278        let n = self.data.len();
279        if n == 0 {
280            return true;
281        }
282        let mut i = n - 1;
283        while i > 0 && self.data[i - 1] >= self.data[i] {
284            i -= 1;
285        }
286        if i == 0 {
287            self.data.reverse();
288            return true;
289        }
290        self.data[i ..].reverse();
291        let k = self.data[i ..].iter().position(|x| x > &self.data[i - 1]).unwrap();
292        self.data.swap(i - 1, i + k);
293        false
294    }
295}
296
297#[test]
298fn iter_ok() {
299    fn test(r: &[&[usize]]) {
300        let mut xs = r[0].to_vec();
301        let mut iter = Iter::new(&mut xs);
302        let mut i = 0;
303        while let Some(xs) = iter.next() {
304            assert_eq!(xs, r[i]);
305            assert_eq!(encode(xs), i);
306            i += 1;
307        }
308        assert_eq!(r.len(), i);
309        assert_eq!(xs, r[0]);
310    }
311    test(&[&[]]);
312    test(&[&[0]]);
313    test(&[&[0, 1], &[1, 0]]);
314    test(&[&[0, 0, 1], &[0, 1, 0], &[1, 0, 0]]);
315    test(&[&[0, 1, 2], &[0, 2, 1], &[1, 0, 2], &[1, 2, 0], &[2, 0, 1], &[2, 1, 0]]);
316    test(&[
317        &[0, 0, 1, 1],
318        &[0, 1, 0, 1],
319        &[0, 1, 1, 0],
320        &[1, 0, 0, 1],
321        &[1, 0, 1, 0],
322        &[1, 1, 0, 0],
323    ]);
324}