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}