smooth_numbers/lib.rs
1/*! Algorithms to generate smooth numbers.
2
3See the definition of *smooth number* on
4[Wikipedia](https://en.wikipedia.org/wiki/Smooth_number) and
5[MathWorld](https://mathworld.wolfram.com/SmoothNumber.html).
6
7# Examples
8
9Generate the first 10 3-smooth numbers, i.e. numbers of the form `2^i * 3^j`:
10```
11use smooth_numbers::smooth;
12assert_eq!(smooth(3, 10), [1, 2, 3, 4, 6, 8, 9, 12, 16, 18]);
13```
14
15Generate the first 10 5-smooth numbers, i.e. numbers of the form `2^i * 3^j * 5^k`:
16```
17use smooth_numbers::smooth;
18assert_eq!(smooth(5, 10), [1, 2, 3, 4, 5, 6, 8, 9, 10, 12]);
19```
20
21Generate the first 10 numbers of the form `2^i * 5^j`:
22```
23use smooth_numbers::with_primes;
24assert_eq!(with_primes(&[2, 5], 10), [1, 2, 4, 5, 8, 10, 16, 20, 25, 32]);
25```
26*/
27
28#![cfg_attr(docsrs, feature(doc_auto_cfg))]
29
30/** Generates the first `n` numbers in the Pratt's sequence.
31
32Pratt's sequence is the sequence of numbers of the form `2^i * 3^j`,
33with `i` and `j` natural numbers. These are also called [3-smooth numbers] and
34they are indexed in OEIS as [A003586](https://oeis.org/A003586).
35
36They provide the best-known sequence of gaps for [Shellsort] (best worst-case time complexity).
37
38[`pratt`]`(n)` is equivalent to [`smooth`]`(3, n)`, but faster.
39
40[3-smooth numbers]: https://mathworld.wolfram.com/SmoothNumber.html
41[Shellsort]: https://en.wikipedia.org/wiki/Shellsort#Gap_sequences
42*/
43pub fn pratt(n: usize) -> Vec<u64> {
44 if n == 0 {
45 return Vec::new();
46 }
47
48 let mut v = Vec::with_capacity(n);
49 v.push(1);
50
51 let mut two = 0;
52 let mut three = 0;
53
54 for _ in 1..n {
55 let times_two = 2 * v[two];
56 let times_three = 3 * v[three];
57 match (times_two).cmp(×_three) {
58 std::cmp::Ordering::Less => {
59 v.push(times_two);
60 two += 1;
61 }
62 std::cmp::Ordering::Equal => {
63 v.push(times_two);
64 two += 1;
65 three += 1;
66 }
67 std::cmp::Ordering::Greater => {
68 v.push(times_three);
69 three += 1;
70 }
71 }
72 }
73 v
74}
75
76/** Generates the first `n` `k`-smooth numbers, i.e. numbers whose prime factors
77 are smaller than or equal to `k`.
78
79See the definition of *smooth number* on
80[Wikipedia](https://en.wikipedia.org/wiki/Smooth_number) and
81[MathWorld](https://mathworld.wolfram.com/SmoothNumber.html).
82
83# Examples
84
85With `k < 2`, the numbers cannot have any prime factor,
86hence the only smooth number in this case is `1`.
87
88```
89# use smooth_numbers::smooth;
90assert_eq!(smooth(0, 0), []);
91assert_eq!(smooth(0, 1), [1]);
92assert_eq!(smooth(0, 10), [1]);
93assert_eq!(smooth(1, 10), [1]);
94```
95
96With `k == 2`, the numbers can only have the prime factor `2`,
97hence we obtain the sequence of the powers of `2`.
98
99```
100# use smooth_numbers::smooth;
101assert_eq!(smooth(2, 10), [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]);
102```
103
104With `k == 3`, the numbers can only have the prime factors `2` and `3`,
105hence we obtain the sequence of the numbers of the form `2^i * 3^j`,
106also known as Pratt's sequence.
107See the [`pratt`] function for a specialized algorithm to generate this sequence.
108
109```
110# use smooth_numbers::smooth;
111assert_eq!(smooth(3, 10), [1, 2, 3, 4, 6, 8, 9, 12, 16, 18]);
112```
113*/
114pub fn smooth(k: usize, n: usize) -> Vec<u64> {
115 if n == 0 {
116 return Vec::new();
117 }
118
119 if k < 2 {
120 return vec![1];
121 }
122
123 if k == 2 {
124 let mut v = Vec::with_capacity(n);
125 v.push(1);
126 let mut x = 1;
127 for _ in 1..n {
128 x *= 2;
129 v.push(x);
130 }
131 return v;
132 }
133
134 let sieve = primal::Sieve::new(k);
135 let primes: Vec<u64> = sieve
136 .primes_from(2)
137 .take_while(|&p| p <= k)
138 .map(|p| p as u64)
139 .collect();
140
141 with_primes(&primes, n)
142}
143
144/** Generates the first `n` smooth numbers whose prime factors are among `primes`.
145
146# Examples
147
148If `primes` is empty, the numbers cannot have any prime factor,
149hence the only smooth number in this case is `1`.
150
151```
152# use smooth_numbers::with_primes;
153assert_eq!(with_primes(&[], 0), []);
154assert_eq!(with_primes(&[], 1), [1]);
155assert_eq!(with_primes(&[], 10), [1]);
156```
157
158If `primes` contains a single element, the numbers can only have the prime factor `primes[0]`,
159hence we obtain the sequence of the powers of `primes[0]`.
160
161```
162# use smooth_numbers::with_primes;
163assert_eq!(with_primes(&[2], 10), [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]);
164```
165
166If `primes == &[2, 3]`, the numbers can only have the prime factors `2` and `3`,
167hence we obtain the sequence of the numbers of the form `2^i * 3^j`,
168also known as Pratt's sequence.
169See the [`pratt`] function for a specialized algorithm to generate this sequence.
170
171```
172# use smooth_numbers::with_primes;
173assert_eq!(with_primes(&[2, 3], 10), [1, 2, 3, 4, 6, 8, 9, 12, 16, 18]);
174```
175*/
176pub fn with_primes(primes: &[u64], n: usize) -> Vec<u64> {
177 if n == 0 {
178 return Vec::new();
179 }
180
181 let num_primes = primes.len();
182
183 if num_primes == 0 {
184 return vec![1];
185 }
186
187 if num_primes == 1 {
188 let mut v = Vec::with_capacity(n);
189 v.push(1);
190 let mut x = 1;
191 for _ in 1..n {
192 x *= primes[0];
193 v.push(x);
194 }
195 return v;
196 }
197
198 let mut indices: Vec<usize> = vec![0; num_primes];
199 let mut v = Vec::with_capacity(n);
200 v.push(1);
201
202 for _ in 1..n {
203 let new = primes
204 .iter()
205 .zip(&indices)
206 .map(|(p, &j)| p * v[j])
207 .min()
208 .expect("cannot find next smooth number");
209 v.push(new);
210 for j in 0..num_primes {
211 if primes[j] * v[indices[j]] == new {
212 indices[j] += 1;
213 }
214 }
215 }
216 v
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222
223 #[test]
224 fn pratt_has_correct_length() {
225 for n in [0, 1, 10, 100] {
226 assert_eq!(pratt(n).len(), n);
227 }
228 }
229
230 #[test]
231 fn pratt_has_correct_values() {
232 assert_eq!(pratt(10), [1, 2, 3, 4, 6, 8, 9, 12, 16, 18]);
233 assert_eq!(pratt(100).last(), Some(&93312));
234 // this is the largest possible
235 assert_eq!(pratt(1343).last(), Some(&17748888853923495936));
236 assert_eq!(pratt(1344).last(), Some(&17991041643939889152));
237 }
238
239 #[test]
240 #[should_panic(expected = "attempt to multiply with overflow")]
241 // #[should_panic(expected = "index out of bounds")] // with `overflow-checks = false`
242 fn pratt_first_to_overflow() {
243 let _ = pratt(1345).last();
244 }
245
246 #[test]
247 fn smooth_has_correct_length() {
248 for n in [0, 1, 10, 64] {
249 assert_eq!(smooth(2, n).len(), n);
250 }
251 for n in [0, 1, 10, 100] {
252 assert_eq!(smooth(3, n).len(), n);
253 assert_eq!(smooth(5, n).len(), n);
254 }
255 }
256
257 #[test]
258 fn smooth_has_correct_values() {
259 assert_eq!(smooth(2, 10), [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]);
260 assert_eq!(smooth(3, 10), [1, 2, 3, 4, 6, 8, 9, 12, 16, 18]);
261 assert_eq!(smooth(3, 100).last(), Some(&93312));
262 // this is the largest possible
263 assert_eq!(smooth(3, 1343).last(), Some(&17748888853923495936));
264 assert_eq!(smooth(3, 1344).last(), Some(&17991041643939889152));
265 }
266
267 #[test]
268 #[should_panic(expected = "attempt to multiply with overflow")]
269 fn smooth_1_first_to_overflow() {
270 let _ = smooth(2, 65).last();
271 }
272
273 #[test]
274 #[should_panic(expected = "attempt to multiply with overflow")]
275 fn smooth_2_first_to_overflow() {
276 let _ = smooth(3, 1345).last();
277 }
278
279 #[test]
280 fn with_primes_has_correct_length() {
281 for n in [0, 1, 10, 64] {
282 assert_eq!(with_primes(&[2], n).len(), n);
283 }
284 for n in [0, 1, 10, 100] {
285 assert_eq!(with_primes(&[2, 3], n).len(), n);
286 assert_eq!(with_primes(&[2, 3, 5], n).len(), n);
287 }
288 }
289
290 #[test]
291 fn with_primes_has_correct_values() {
292 assert_eq!(
293 with_primes(&[2], 10),
294 [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
295 );
296 assert_eq!(with_primes(&[2, 3], 10), [1, 2, 3, 4, 6, 8, 9, 12, 16, 18]);
297 assert_eq!(with_primes(&[2, 3], 100).last(), Some(&93312));
298 // this is the largest possible
299 assert_eq!(
300 with_primes(&[2, 3], 1343).last(),
301 Some(&17748888853923495936)
302 );
303 assert_eq!(
304 with_primes(&[2, 3], 1344).last(),
305 Some(&17991041643939889152)
306 );
307 assert_eq!(
308 with_primes(&[2, 5], 10),
309 [1, 2, 4, 5, 8, 10, 16, 20, 25, 32]
310 );
311 }
312
313 #[test]
314 #[should_panic(expected = "attempt to multiply with overflow")]
315 fn with_primes_1_first_to_overflow() {
316 let _ = with_primes(&[2], 65).last();
317 }
318
319 #[test]
320 #[should_panic(expected = "attempt to multiply with overflow")]
321 fn with_primes_2_first_to_overflow() {
322 let _ = with_primes(&[2, 3], 1345).last();
323 }
324}