malachite_nz/natural/arithmetic/
binomial_coefficient.rs1use crate::natural::arithmetic::div::limbs_hensel_div_limb_in_place;
16use crate::natural::arithmetic::div_exact::{
17 limbs_modular_div_schoolbook_in_place, limbs_modular_invert_limb,
18};
19use crate::natural::arithmetic::div_round::double_cmp;
20use crate::natural::arithmetic::factorial::{bit_to_n, limbs_odd_factorial, log_n_max};
21use crate::natural::arithmetic::mul::limb::limbs_slice_mul_limb_in_place;
22use crate::natural::arithmetic::mul::limbs_mul;
23use crate::natural::arithmetic::mul::product_of_limbs::limbs_product;
24use crate::natural::arithmetic::neg::limbs_neg_in_place;
25use crate::natural::arithmetic::shl::limbs_slice_shl_in_place;
26use crate::natural::{Natural, bit_to_limb_count_floor};
27use crate::platform::{
28 CENTRAL_BINOMIAL_2FAC_TABLE, Limb, ODD_CENTRAL_BINOMIAL_OFFSET,
29 ODD_CENTRAL_BINOMIAL_TABLE_LIMIT, ODD_FACTORIAL_EXTTABLE_LIMIT, ODD_FACTORIAL_TABLE_LIMIT,
30 ODD_FACTORIAL_TABLE_MAX, ONE_LIMB_ODD_CENTRAL_BINOMIAL_INVERSE_TABLE,
31 ONE_LIMB_ODD_CENTRAL_BINOMIAL_TABLE, ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE,
32 ONE_LIMB_ODD_FACTORIAL_TABLE, TABLE_2N_MINUS_POPC_2N,
33};
34use alloc::vec::Vec;
35use core::cmp::{Ordering::*, max, min};
36use malachite_base::num::arithmetic::traits::{
37 AddMulAssign, BinomialCoefficient, DivAssignMod, DivExact, Parity, PowerOf2, Square,
38 WrappingAddAssign,
39};
40use malachite_base::num::basic::integers::PrimitiveInt;
41use malachite_base::num::basic::traits::{One, Zero};
42use malachite_base::num::conversion::traits::{ExactFrom, WrappingFrom};
43#[cfg(feature = "32_bit_limbs")]
44use malachite_base::num::factorization::prime_sieve::limbs_prime_sieve_u32;
45#[cfg(not(feature = "32_bit_limbs"))]
46use malachite_base::num::factorization::prime_sieve::limbs_prime_sieve_u64;
47use malachite_base::num::factorization::prime_sieve::{id_to_n, limbs_prime_sieve_size, n_to_bit};
48use malachite_base::num::logic::traits::{CountOnes, LeadingZeros, SignificantBits};
49
50const fn apply_mul_func(n: Limb, m: Limb) -> Limb {
52 match n {
53 1 => m,
54 2 => (m | 1) * ((m + 1) >> 1),
55 3 => {
56 let m01 = (m * (m + 1)) >> 1;
57 let m2 = m + 2;
58 m01 * m2
59 }
60 4 => {
61 let m03 = (m * (m + 3)) >> 1;
62 m03 * (m03 + 1)
63 }
64 5 => {
65 let m03 = (m * (m + 3)) >> 1;
66 let m034 = m03 * (m + 4);
67 (m03 + 1) * m034
68 }
69 6 => {
70 let m05 = m * (m + 5);
71 let m1234 = ((m05 + 5) * (m05 + 5)) >> 3;
72 m1234 * (m05 >> 1)
73 }
74 7 => {
75 let m05 = m * (m + 5);
76 let m1234 = ((m05 + 5) * (m05 + 5)) >> 3;
77 let m056 = (m05 * (m + 6)) >> 1;
78 m1234 * m056
79 }
80 8 => {
81 let m07 = m * (m + 7);
82 let m0257 = (m07 * (m07 + 10)) >> 3;
83 let m1346 = m07 + 9 + m0257;
84 m0257 * m1346
85 }
86 _ => panic!(),
87 }
88}
89
90const M: Limb = 8;
91
92const SOME_THRESHOLD: usize = 20;
93
94pub_test! {limbs_binomial_coefficient_limb_limb_bdiv(n: Limb, k: Limb) -> Vec<Limb> {
97 assert!(k > Limb::wrapping_from(ODD_FACTORIAL_TABLE_LIMIT));
98 let max_n = 1 + usize::exact_from(n >> Limb::LOG_WIDTH);
99 let alloc = min(
100 SOME_THRESHOLD - 1 + max((3 * max_n) >> 1, SOME_THRESHOLD),
101 usize::exact_from(k),
102 ) + 1;
103 let mut big_scratch = vec![0; alloc + SOME_THRESHOLD + 1];
104 let (ns, ks) = big_scratch.split_at_mut(alloc);
105 let n_max = Limb::wrapping_from(log_n_max(n));
106 assert!(n_max <= M);
107 let mut k_max = Limb::wrapping_from(log_n_max(k));
108 assert!(k_max <= M);
109 assert!(k >= M);
110 assert!(n >= k);
111 let mut i = n - k + 1;
112 ns[0] = 1;
113 let mut n_len = 1;
114 let mut num_fac = 1;
115 let mut j = Limb::wrapping_from(ODD_FACTORIAL_TABLE_LIMIT + 1);
116 let mut jjj = ODD_FACTORIAL_TABLE_MAX;
117 assert_eq!(
118 ONE_LIMB_ODD_FACTORIAL_TABLE[ODD_FACTORIAL_TABLE_LIMIT],
119 ODD_FACTORIAL_TABLE_MAX
120 );
121 loop {
122 ks[0] = jjj;
123 let mut k_len = 1;
124 let mut t = k + 1 - j;
125 k_max = min(k_max, t);
126 while k_max != 0 && k_len < SOME_THRESHOLD {
127 jjj = apply_mul_func(k_max, j);
128 j += k_max;
129 jjj >>= jjj.trailing_zeros();
130 let cy = limbs_slice_mul_limb_in_place(&mut ks[..k_len], jjj);
131 ks[k_len] = cy;
132 if cy != 0 {
133 k_len += 1;
134 }
135 t = k + 1 - j;
136 k_max = min(k_max, t);
137 }
138 num_fac = j - num_fac;
139 while num_fac != 0 {
140 let n_max_now = min(n_max, num_fac);
141 let mut iii = apply_mul_func(n_max_now, i);
142 i.wrapping_add_assign(n_max_now);
143 iii >>= iii.trailing_zeros();
144 let carry = limbs_slice_mul_limb_in_place(&mut ns[..n_len], iii);
145 ns[n_len] = carry;
146 if carry != 0 {
147 n_len += 1;
148 }
149 num_fac -= n_max_now;
150 }
151 if ns[n_len - 1] >= ks[k_len - 1] {
152 n_len += 1;
153 }
154 n_len -= k_len;
155 let d_inv = limbs_modular_invert_limb(ks[0]);
156 limbs_modular_div_schoolbook_in_place(ns, &ks[..min(k_len, n_len)], d_inv.wrapping_neg());
157 limbs_neg_in_place(&mut ns[..n_len]);
158 if k_max == 0 {
159 break;
160 }
161 num_fac = j;
162 jjj = apply_mul_func(k_max, j);
163 j += k_max;
164 jjj >>= jjj.trailing_zeros();
165 }
166 let ones = CountOnes::count_ones(n - k) + CountOnes::count_ones(k) - CountOnes::count_ones(n);
168 if ones != 0 {
169 assert!(ones < Limb::WIDTH);
170 let carry = limbs_slice_shl_in_place(&mut ns[..n_len], ones);
171 ns[n_len] = carry;
172 if carry != 0 {
173 n_len += 1;
174 }
175 }
176 if ns[n_len - 1] == 0 {
177 n_len -= 1;
178 }
179 let mut ns = big_scratch;
180 ns.truncate(n_len);
181 ns
182}}
183
184const TCNT_TAB: [u8; 8] = [0, 1, 1, 2, 2, 4, 4, 6];
188
189pub_test! {limbs_binomial_coefficient_limb_limb_small_k(n: Limb, k: Limb) -> Vec<Limb> {
192 let n_max = Limb::wrapping_from(log_n_max(n));
193 let mut n_max = min(n_max, M);
194 let mut i = n - k + 1;
195 let k_u = usize::exact_from(k);
196 assert!(k_u <= ODD_FACTORIAL_TABLE_LIMIT);
197 let mut i2_count = TABLE_2N_MINUS_POPC_2N[(k_u >> 1) - 1];
198 let factorial_inverse = ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE[k_u - 2];
199 if n_max >= k {
200 return vec![
201 (apply_mul_func(k, i).wrapping_mul(factorial_inverse))
202 >> (i2_count - TCNT_TAB[k_u - 1]),
203 ];
204 }
205 let alloc =
206 bit_to_limb_count_floor(n.significant_bits() * u64::exact_from(k)) + 3;
207 let mut out = vec![0; alloc];
208 out[0] = apply_mul_func(n_max, i);
209 let mut out_len = 1;
210 i += n_max;
211 i2_count -= TCNT_TAB[usize::exact_from(n_max - 1)];
212 let mut num_fac = k - n_max;
213 while num_fac != 0 {
214 n_max = min(n_max, num_fac);
215 let iii = apply_mul_func(n_max, i);
216 i.wrapping_add_assign(n_max);
217 i2_count -= TCNT_TAB[usize::exact_from(n_max - 1)];
218 let carry = limbs_slice_mul_limb_in_place(&mut out[..out_len], iii);
219 out[out_len] = carry;
220 if carry != 0 {
221 out_len += 1;
222 }
223 num_fac -= n_max;
224 }
225 assert!(out_len < alloc);
226 limbs_hensel_div_limb_in_place(
227 &mut out[..out_len],
228 ONE_LIMB_ODD_FACTORIAL_TABLE[k_u],
229 factorial_inverse,
230 u64::from(i2_count),
231 );
232 while *out.last().unwrap() == 0 {
233 out.pop();
234 }
235 out
236}}
237
238pub_test! {limbs_binomial_coefficient_limb_limb_basecase(n: Limb, k: Limb) -> Limb {
243 assert!(n <= ODD_FACTORIAL_EXTTABLE_LIMIT as Limb);
244 assert!(n >= k + 2);
245 assert!(k >= 2);
246 let n = usize::wrapping_from(n);
247 let k = usize::wrapping_from(k);
248 let diff = n - k;
249 (ONE_LIMB_ODD_FACTORIAL_TABLE[n]
250 .wrapping_mul(ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE[k - 2])
251 .wrapping_mul(ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE[diff - 2]))
252 << (TABLE_2N_MINUS_POPC_2N[(n >> 1) - 1]
253 - TABLE_2N_MINUS_POPC_2N[(k >> 1) - 1]
254 - TABLE_2N_MINUS_POPC_2N[(diff >> 1) - 1])
255}}
256
257pub(crate) const BIN_UIUI_RECURSIVE_SMALLDC: bool = Limb::WIDTH > u32::WIDTH;
258
259pub_test! {limbs_binomial_coefficient_limb_limb_small_k_divide_and_conquer(
267 mut n: Limb,
268 mut k: Limb,
269) -> Vec<Limb> {
270 let half_k = k >> 1;
271 let mut out = if !BIN_UIUI_RECURSIVE_SMALLDC || half_k <= ODD_FACTORIAL_TABLE_LIMIT as Limb {
272 limbs_binomial_coefficient_limb_limb_small_k(n, half_k)
273 } else {
274 limbs_binomial_coefficient_limb_limb_small_k_divide_and_conquer(n, half_k)
275 };
276 k -= half_k;
277 n -= half_k;
278 let mut out_len = out.len();
279 if n <= ODD_FACTORIAL_EXTTABLE_LIMIT as Limb {
280 out.push(0);
281 let carry = limbs_slice_mul_limb_in_place(
282 &mut out[..out_len],
283 limbs_binomial_coefficient_limb_limb_basecase(n, k),
284 );
285 out[out_len] = carry;
286 if carry != 0 {
287 out_len += 1;
288 }
289 } else {
290 let t = if !BIN_UIUI_RECURSIVE_SMALLDC || k <= ODD_FACTORIAL_TABLE_LIMIT as Limb {
291 limbs_binomial_coefficient_limb_limb_small_k(n, k)
292 } else {
293 limbs_binomial_coefficient_limb_limb_small_k_divide_and_conquer(n, k)
294 };
295 let out_copy = out[..out_len].to_vec();
296 out = limbs_mul(&out_copy, &t);
297 out_len = out.len();
298 }
299 let k_u = usize::exact_from(k);
300 let mut shift = CENTRAL_BINOMIAL_2FAC_TABLE[k_u - ODD_CENTRAL_BINOMIAL_OFFSET];
301 if k != half_k {
302 shift -= 1;
304 }
305 let k_offset = k_u - ODD_CENTRAL_BINOMIAL_OFFSET;
306 limbs_hensel_div_limb_in_place(
307 &mut out[..out_len],
308 ONE_LIMB_ODD_CENTRAL_BINOMIAL_TABLE[k_offset],
309 ONE_LIMB_ODD_CENTRAL_BINOMIAL_INVERSE_TABLE[k_offset],
310 shift,
311 );
312 while *out.last().unwrap() == 0 {
313 out.pop();
314 }
315 out
316}}
317
318fn limbs_approx_sqrt(x: Limb) -> Limb {
327 assert!(x > 2);
328 let s = (Limb::WIDTH - LeadingZeros::leading_zeros(x)) >> 1;
329 (Limb::power_of_2(s) + (x >> s)) >> 1
330}
331
332pub(crate) const BIN_GOETGHELUCK_THRESHOLD: Limb = 512;
333
334pub_test! {
340#[allow(clippy::useless_conversion)]
341limbs_binomial_coefficient_limb_limb_goetgheluck(n: Limb, k: Limb) -> Vec<Limb> {
342 assert!(BIN_GOETGHELUCK_THRESHOLD >= 13);
343 assert!(n >= 25);
344 let n_64 = u64::from(n);
345 let k_64 = u64::from(k);
346 let mut sieve = vec![0; limbs_prime_sieve_size::<Limb>(n_64)];
347 #[cfg(feature = "32_bit_limbs")]
348 let count = limbs_prime_sieve_u32(&mut sieve, n_64) + 1;
349 #[cfg(not(feature = "32_bit_limbs"))]
350 let count = limbs_prime_sieve_u64(&mut sieve, n) + 1;
351 let mut factors = vec![0; usize::exact_from(count / log_n_max(n) + 1)];
352 let mut max_prod = Limb::MAX / n;
353 let mut prod = Limb::power_of_2(
355 CountOnes::count_ones(n - k) + CountOnes::count_ones(k) - CountOnes::count_ones(n),
356 );
357 let mut j = 0;
358 let mut a = n;
359 let mut b = k;
360 let mut mb = 0;
361 if prod > max_prod {
362 factors[j] = prod;
364 j += 1;
365 prod = 1;
366 }
367 while a >= 3 {
368 mb += b.div_assign_mod(3);
369 let ma = a.div_assign_mod(3);
370 if ma < mb {
371 mb = 1;
372 prod *= 3;
373 } else {
374 mb = 0;
375 }
376 }
377 let s = n_to_bit(u64::from(limbs_approx_sqrt(n)));
379 assert!(bit_to_n(s + 1).square() > n_64);
380 let half_n_bit = n_to_bit(n_64 >> 1);
381 assert!(s <= half_n_bit);
382 let mut index = 0;
383 let mut mask = 1;
384 for i in 1..=s + 1 {
385 if sieve[index] & mask == 0 {
386 let prime = Limb::exact_from(id_to_n(i));
387 let mut a = n;
388 let mut b = k;
389 let mut mb = 0;
390 if prod > max_prod {
391 factors[j] = prod;
392 j += 1;
393 prod = 1;
394 }
395 while a >= prime {
396 mb += b.div_assign_mod(prime);
397 let ma = a.div_assign_mod(prime);
398 if ma < mb {
399 mb = 1;
400 prod *= prime;
401 } else {
402 mb = 0;
403 }
404 }
405 }
406 mask <<= 1;
407 if mask == 0 {
408 mask = 1;
409 index += 1;
410 }
411 }
412 assert!(max_prod <= Limb::MAX >> 1);
413 max_prod <<= 1;
414 for i in s + 2..=half_n_bit + 1 {
415 if sieve[index] & mask == 0 {
416 let prime = Limb::exact_from(id_to_n(i));
417 if n % prime < k % prime {
418 if prod > max_prod {
419 factors[j] = prod;
420 j += 1;
421 prod = prime;
422 } else {
423 prod *= prime;
424 }
425 }
426 }
427 mask <<= 1;
428 if mask == 0 {
429 mask = 1;
430 index += 1;
431 }
432 }
433 max_prod >>= 1;
434 let n_bit = n_to_bit(n_64);
436 let n_minus_k_bit = n_to_bit(n_64 - k_64);
437 assert!(n_minus_k_bit < n_bit);
438 let i = n_minus_k_bit + 1;
439 let mut index = bit_to_limb_count_floor(i);
440 let mut mask = Limb::power_of_2(i & Limb::WIDTH_MASK);
441 for i in i + 1..=n_bit + 1 {
442 if sieve[index] & mask == 0 {
443 let prime = Limb::exact_from(id_to_n(i));
444 if prod > max_prod {
445 factors[j] = prod;
446 j += 1;
447 prod = prime;
448 } else {
449 prod *= prime;
450 }
451 }
452 mask <<= 1;
453 if mask == 0 {
454 mask = 1;
455 index += 1;
456 }
457 }
458 assert_ne!(j, 0);
459 factors[j] = Limb::wrapping_from(prod);
460 j += 1;
461 let mut r = Vec::new();
462 let (size, new_r) = limbs_product(&mut r, &mut factors[..j]);
463 r = new_r.unwrap();
464 r.truncate(size);
465 r
466}}
467
468const BIN_UIUI_ENABLE_SMALLDC: bool = true;
469
470pub_test! {binomial_coefficient_limb_limb(n: Limb, mut k: Limb) -> Natural {
473 if n < k {
474 Natural::ZERO
475 } else {
476 k = min(k, n - k);
478 if k == 0 {
479 Natural::ONE
480 } else if k == 1 {
481 Natural::from(n)
482 } else if n <= ODD_FACTORIAL_EXTTABLE_LIMIT as Limb {
483 Natural::from(limbs_binomial_coefficient_limb_limb_basecase(n, k))
485 } else if k <= ODD_FACTORIAL_TABLE_LIMIT as Limb {
486 Natural::from_owned_limbs_asc(limbs_binomial_coefficient_limb_limb_small_k(n, k))
487 } else if BIN_UIUI_ENABLE_SMALLDC
488 && k <= (if BIN_UIUI_RECURSIVE_SMALLDC {
489 ODD_CENTRAL_BINOMIAL_TABLE_LIMIT
490 } else {
491 ODD_FACTORIAL_TABLE_LIMIT
492 } as Limb)
493 << 1
494 {
495 Natural::from_owned_limbs_asc(
496 limbs_binomial_coefficient_limb_limb_small_k_divide_and_conquer(n, k),
497 )
498 } else if k >= BIN_GOETGHELUCK_THRESHOLD && k > n >> 4 {
499 Natural::from_owned_limbs_asc(limbs_binomial_coefficient_limb_limb_goetgheluck(n, k))
501 } else {
502 Natural::from_owned_limbs_asc(limbs_binomial_coefficient_limb_limb_bdiv(n, k))
503 }
504 }
505}}
506
507fn binomial_coefficient_hmul_nbnpk(n: &Natural, mut k: Limb) -> Natural {
514 assert_ne!(k, 0);
515 assert_ne!(*n, 0u32);
516 k -= 1;
517 (((n + Natural::from(k)).square() + n) >> 1u32)
518 - Natural::from(k + (k & 1)) * Natural::from(k >> 1)
519}
520
521fn binomial_coefficient_raising_factorial_4_rec(
523 r: &mut Natural,
524 p: &mut Natural,
525 big_p: &mut Natural,
526 k: Limb,
527 lk: Limb,
528) {
529 assert!(k >= lk);
530 if k - lk < 5 {
531 for i in (lk + 1..=k).rev() {
532 let four_i = i << 2;
533 *p += Natural::from(four_i + 2);
534 big_p.add_mul_assign(&*p, Natural::from(four_i));
535 *big_p -= Natural::from(i);
536 *r *= &*big_p;
537 }
538 } else {
539 let m = ((k + lk) >> 1) + 1;
540 binomial_coefficient_raising_factorial_4_rec(r, p, big_p, k, m);
541 let four_m = m << 2;
542 *p += Natural::from(four_m + 2);
543 big_p.add_mul_assign(&*p, Natural::from(four_m));
544 *big_p -= Natural::from(m);
545 let mut t = big_p.clone();
546 binomial_coefficient_raising_factorial_4_rec(&mut t, p, big_p, m - 1, lk);
547 *r *= t;
548 }
549}
550
551fn binomial_coefficient_raising_factorial_4(mut n: Natural, mut k: Limb) -> Natural {
553 assert!(k >= 2);
554 n += Natural::ONE;
555 let mut r = Natural::ZERO;
556 if k.odd() {
557 r = n.clone();
558 n += Natural::ONE;
559 }
560 k >>= 1;
561 let mut p = binomial_coefficient_hmul_nbnpk(&n, k);
562 if k.odd() {
563 if r != 0u32 {
564 r *= &p;
565 } else {
566 r = p.clone();
567 }
568 p += Natural::from(k - 1);
569 }
570 k >>= 1;
571 if k == 0 {
572 return r;
573 }
574 let mut t = binomial_coefficient_hmul_nbnpk(&p, k);
575 if r != 0u32 {
576 r *= &t;
577 } else {
578 r = t.clone();
579 }
580 if k > 1 {
581 p -= Natural::from(k);
582 binomial_coefficient_raising_factorial_4_rec(&mut r, &mut p, &mut t, k - 1, 0);
583 }
584 r
585}
586
587fn binomial_coefficient_helper(n: Natural, k: Limb) -> Natural {
590 assert_ne!(k, 0);
591 if k < 2 {
592 n
593 } else if let Ok(small_n) = Limb::try_from(&n) {
594 binomial_coefficient_limb_limb(small_n, k)
595 } else {
596 (binomial_coefficient_raising_factorial_4(n - Natural::from(k), k)
597 >> (k - (k >> 1) - (k >> 2))
598 .checked_sub(Limb::wrapping_from(CountOnes::count_ones(k)))
599 .unwrap())
600 .div_exact(Natural::from_owned_limbs_asc(limbs_odd_factorial(
601 usize::exact_from(k),
602 false,
603 )))
604 }
605}
606
607impl BinomialCoefficient for Natural {
608 fn binomial_coefficient(n: Self, mut k: Self) -> Self {
652 if k > n {
653 return Self::ZERO;
654 }
655 if k == 0u32 || n == k {
656 return Self::ONE;
657 }
658 if double_cmp(&k, &n) == Greater {
659 k = &n - &k;
660 }
661 binomial_coefficient_helper(n, Limb::try_from(&k).expect("k is too large"))
662 }
663}
664
665impl<'a> BinomialCoefficient<&'a Self> for Natural {
666 fn binomial_coefficient(n: &'a Self, k: &'a Self) -> Self {
711 if k > n {
712 return Self::ZERO;
713 }
714 if *k == 0u32 || n == k {
715 return Self::ONE;
716 }
717 let k = if double_cmp(k, n) == Greater {
718 Limb::try_from(&(n - k))
719 } else {
720 Limb::try_from(k)
721 }
722 .expect("k is too large");
723 binomial_coefficient_helper(n.clone(), k)
724 }
725}