integer_partitions/
lib.rs

1//! Efficiently enumerate integer partitions.
2//!
3//! This is an implementation of a method described by
4//! [Jerome Kelleher](http://jeromekelleher.net/generating-integer-partitions.html),
5//! which takes a constant amount of time for each partition.
6
7#![deny(missing_docs)]
8
9/// Iterates over the partitions of a given positive integer.
10pub struct Partitions {
11    a: Vec<usize>,
12    k: usize,
13    y: usize,
14    next: State,
15}
16
17enum State {
18    A,
19    B { x: usize, l: usize },
20}
21
22impl Partitions {
23    /// Makes a new iterator.
24    #[inline]
25    pub fn new(n: usize) -> Partitions {
26        Partitions {
27            a: vec![0; n + 1],
28            k: if n == 0 { 0 } else { 1 },
29            y: if n == 0 { 0 } else { n - 1 },
30            next: State::A,
31        }
32    }
33
34    /// Advances the iterator and returns the next partition.
35    #[inline]
36    pub fn next(&mut self) -> Option<&[usize]> {
37        let Partitions {
38            ref mut a,
39            ref mut k,
40            ref mut y,
41            ref mut next
42        } = *self;
43
44        match *next {
45            State::A => {
46                if *k == 0 {
47                    if a.len() == 1 {
48                        a.pop();
49                        Some(&[])
50                    } else {
51                        None
52                    }
53                } else {
54                    *k -= 1;
55                    let x = a[*k] + 1;
56
57                    while 2 * x <= *y {
58                        a[*k] = x;
59                        *y -= x;
60                        *k += 1;
61                    }
62
63                    let l = *k + 1;
64
65                    if x <= *y {
66                        a[*k] = x;
67                        a[l] = *y;
68                        *next = State::B { x, l };
69                        Some(&a[..*k + 2])
70                    } else {
71                        a[*k] = x + *y;
72                        *y = x + *y - 1;
73                        Some(&a[..*k + 1])
74                    }
75                }
76            },
77            State::B { mut x, l } => {
78                x += 1;
79                *y -= 1;
80
81                if x <= *y {
82                    a[*k] = x;
83                    a[l] = *y;
84                    *next = State::B { x, l };
85                    Some(&a[..*k + 2])
86                } else {
87                    a[*k] = x + *y;
88                    *y = x + *y - 1;
89                    *next = State::A;
90                    Some(&a[..*k + 1])
91                }
92            },
93        }
94    }
95
96    /// Makes a new iterator, trying to avoid allocations.
97    ///
98    /// Any vector can be passed to this function, since its contents
99    /// will be cleared and it will be filled with zeroes, but note
100    /// that the vector will still reallocate if its capacity is less
101    /// than `n + 1`.
102    #[inline]
103    pub fn recycle(n: usize, mut vec: Vec<usize>) -> Partitions {
104        vec.clear();
105        vec.reserve(n + 1);
106        for _ in 0..(n + 1) {
107            vec.push(0);
108        }
109
110        Partitions {
111            a: vec,
112            k: if n == 0 { 0 } else { 1 },
113            y: if n == 0 { 0 } else { n - 1 },
114            next: State::A,
115        }
116    }
117
118    /// Destroys the iterator and returns a vector for further use.
119    ///
120    /// You only need to call this function if you want to reuse the
121    /// vector for something else. Its contents will be in an undefined
122    /// state, and so cannot be relied upon.
123    #[inline]
124    pub fn end(self) -> Vec<usize> {
125        self.a
126    }
127}
128
129#[test]
130fn oeis() {
131    //! Tests the first few entries of A000041.
132
133    let tests: &[usize] = &[
134        1, 1, 2, 3, 5, 7, 11, 15, 22,
135        30, 42, 56, 77, 101, 135, 176, 231,
136        297, 385, 490, 627, 792, 1002, 1255, 1575,
137        1958, 2436, 3010, 3718, 4565, 5604, 6842, 8349,
138        10143, 12310, 14883, 17977, 21637, 26015, 31185, 37338,
139        44583, 53174, 63261, 75175, 89134, 105558, 124754, 147273,
140        173525,
141    ];
142
143    for (i, &n) in tests.iter().enumerate() {
144        let mut p = Partitions::new(i);
145        let mut c = 0;
146
147        while let Some(x) = p.next() {
148            let sum: usize = x.iter().cloned().sum();
149            assert_eq!(sum, i);
150            c += 1;
151        }
152
153        assert_eq!(c, n);
154    }
155}