scirs2_special/combinatorial.rs
1//! Combinatorial functions
2//!
3//! This module provides various combinatorial functions including:
4//! - Factorial and related functions
5//! - Binomial coefficients
6//! - Permutations and combinations
7//! - Stirling numbers
8//! - Bell numbers
9//! - Bernoulli numbers
10//! - Euler numbers
11
12use crate::error::{SpecialError, SpecialResult};
13use crate::gamma::gamma;
14use std::f64::consts::PI;
15
16/// Computes the factorial of a non-negative integer.
17///
18/// For large values, this uses the gamma function: n! = Γ(n+1).
19///
20/// # Arguments
21///
22/// * `n` - Non-negative integer
23///
24/// # Returns
25///
26/// * `SpecialResult<f64>` - The factorial value n!
27///
28/// # Examples
29///
30/// ```
31/// use scirs2_special::factorial;
32///
33/// assert_eq!(factorial(0).expect("test/example should not fail"), 1.0);
34/// assert_eq!(factorial(5).expect("test/example should not fail"), 120.0);
35/// assert_eq!(factorial(10).expect("test/example should not fail"), 3628800.0);
36/// ```
37#[allow(dead_code)]
38pub fn factorial(n: u32) -> SpecialResult<f64> {
39 if n <= 20 {
40 // Use direct calculation for small values
41 let mut result = 1.0;
42 for i in 1..=n {
43 result *= i as f64;
44 }
45 Ok(result)
46 } else {
47 // Use gamma function for larger values
48 Ok(gamma((n + 1) as f64))
49 }
50}
51
52/// Computes the double factorial of a non-negative integer.
53///
54/// Double factorial n!! is defined as:
55/// - For even n: n!! = n × (n-2) × (n-4) × ... × 2
56/// - For odd n: n!! = n × (n-2) × (n-4) × ... × 1
57/// - 0!! = 1 by convention
58///
59/// # Arguments
60///
61/// * `n` - Non-negative integer
62///
63/// # Returns
64///
65/// * `SpecialResult<f64>` - The double factorial value n!!
66///
67/// # Examples
68///
69/// ```
70/// use scirs2_special::double_factorial;
71///
72/// assert_eq!(double_factorial(0).expect("test/example should not fail"), 1.0);
73/// assert_eq!(double_factorial(5).expect("test/example should not fail"), 15.0); // 5 × 3 × 1
74/// assert_eq!(double_factorial(6).expect("test/example should not fail"), 48.0); // 6 × 4 × 2
75/// ```
76#[allow(dead_code)]
77pub fn double_factorial(n: u32) -> SpecialResult<f64> {
78 if n == 0 {
79 return Ok(1.0);
80 }
81
82 let mut result = 1.0;
83 let mut i = n;
84 while i > 0 {
85 result *= i as f64;
86 i = i.saturating_sub(2);
87 }
88 Ok(result)
89}
90
91/// Computes the double factorial n!! (alias for SciPy compatibility).
92///
93/// This is an alias for `double_factorial` to match SciPy's `factorial2` function.
94///
95/// # Arguments
96///
97/// * `n` - The number for which to compute the double factorial
98///
99/// # Returns
100///
101/// * `SpecialResult<f64>` - The double factorial n!!
102///
103/// # Examples
104///
105/// ```
106/// use scirs2_special::factorial2;
107///
108/// assert_eq!(factorial2(5).expect("test/example should not fail"), 15.0); // 5 × 3 × 1
109/// assert_eq!(factorial2(6).expect("test/example should not fail"), 48.0); // 6 × 4 × 2
110/// ```
111#[allow(dead_code)]
112pub fn factorial2(n: u32) -> SpecialResult<f64> {
113 double_factorial(n)
114}
115
116/// Computes the k-factorial (multi-factorial) of n.
117///
118/// The k-factorial of n is the product of positive integers up to n
119/// that are congruent to n modulo k.
120/// For example, the 3-factorial of 8 is 8×5×2.
121///
122/// # Arguments
123///
124/// * `n` - The number for which to compute the k-factorial
125/// * `k` - The step size (must be positive)
126///
127/// # Returns
128///
129/// * `SpecialResult<f64>` - The k-factorial of n
130///
131/// # Examples
132///
133/// ```
134/// use scirs2_special::factorialk;
135///
136/// assert_eq!(factorialk(8, 3).expect("test/example should not fail"), 80.0); // 8 × 5 × 2
137/// assert_eq!(factorialk(5, 2).expect("test/example should not fail"), 15.0); // 5 × 3 × 1
138/// assert_eq!(factorialk(6, 2).expect("test/example should not fail"), 48.0); // 6 × 4 × 2 (same as double factorial)
139/// ```
140#[allow(dead_code)]
141pub fn factorialk(n: u32, k: u32) -> SpecialResult<f64> {
142 if k == 0 {
143 return Err(crate::SpecialError::ValueError(
144 "k must be positive".to_string(),
145 ));
146 }
147
148 if n == 0 {
149 return Ok(1.0);
150 }
151
152 let mut result = 1.0;
153 let mut i = n;
154 while i > 0 {
155 result *= i as f64;
156 i = i.saturating_sub(k);
157 }
158 Ok(result)
159}
160
161/// Computes the binomial coefficient "n choose k".
162///
163/// The binomial coefficient C(n,k) = n! / (k! × (n-k)!) represents
164/// the number of ways to choose k items from n items.
165///
166/// # Arguments
167///
168/// * `n` - Total number of items
169/// * `k` - Number of items to choose
170///
171/// # Returns
172///
173/// * `SpecialResult<f64>` - The binomial coefficient C(n,k)
174///
175/// # Examples
176///
177/// ```
178/// use scirs2_special::binomial;
179///
180/// assert_eq!(binomial(5, 2).expect("test/example should not fail"), 10.0);
181/// assert_eq!(binomial(10, 3).expect("test/example should not fail"), 120.0);
182/// assert_eq!(binomial(7, 0).expect("test/example should not fail"), 1.0);
183/// assert_eq!(binomial(7, 7).expect("test/example should not fail"), 1.0);
184/// ```
185#[allow(dead_code)]
186pub fn binomial(n: u32, k: u32) -> SpecialResult<f64> {
187 if k > n {
188 return Ok(0.0);
189 }
190
191 if k == 0 || k == n {
192 return Ok(1.0);
193 }
194
195 // Use symmetry: C(n,k) = C(n,n-k)
196 let k = if k > n - k { n - k } else { k };
197
198 // For small values, use direct calculation to avoid precision issues
199 if n <= 30 {
200 let mut result = 1.0;
201 for i in 0..k {
202 result = result * (n - i) as f64 / (i + 1) as f64;
203 }
204 Ok(result)
205 } else {
206 // Use gamma function for larger values
207 let n_fact = gamma((n + 1) as f64);
208 let k_fact = gamma((k + 1) as f64);
209 let nk_fact = gamma((n - k + 1) as f64);
210 Ok(n_fact / (k_fact * nk_fact))
211 }
212}
213
214/// Computes the number of permutations of n items taken k at a time.
215///
216/// P(n,k) = n! / (n-k)! represents the number of ways to arrange
217/// k items from n items where order matters.
218///
219/// # Arguments
220///
221/// * `n` - Total number of items
222/// * `k` - Number of items to arrange
223///
224/// # Returns
225///
226/// * `SpecialResult<f64>` - The number of permutations P(n,k)
227///
228/// # Examples
229///
230/// ```
231/// use scirs2_special::permutations;
232///
233/// assert_eq!(permutations(5, 2).expect("test/example should not fail"), 20.0);
234/// assert_eq!(permutations(10, 3).expect("test/example should not fail"), 720.0);
235/// assert_eq!(permutations(7, 0).expect("test/example should not fail"), 1.0);
236/// ```
237#[allow(dead_code)]
238pub fn permutations(n: u32, k: u32) -> SpecialResult<f64> {
239 if k > n {
240 return Ok(0.0);
241 }
242
243 if k == 0 {
244 return Ok(1.0);
245 }
246
247 // For small values, use direct calculation
248 if n <= 30 {
249 let mut result = 1.0;
250 for i in 0..k {
251 result *= (n - i) as f64;
252 }
253 Ok(result)
254 } else {
255 // Use gamma function for larger values
256 let n_fact = gamma((n + 1) as f64);
257 let nk_fact = gamma((n - k + 1) as f64);
258 Ok(n_fact / nk_fact)
259 }
260}
261
262/// Computes the number of permutations (alias for SciPy compatibility).
263///
264/// This is an alias for `permutations` to match SciPy's `perm` function.
265///
266/// # Arguments
267///
268/// * `n` - Total number of items
269/// * `k` - Number of items to arrange
270///
271/// # Returns
272///
273/// * `SpecialResult<f64>` - The number of permutations P(n,k)
274///
275/// # Examples
276///
277/// ```
278/// use scirs2_special::perm;
279///
280/// assert_eq!(perm(5, 2).expect("test/example should not fail"), 20.0);
281/// assert_eq!(perm(10, 3).expect("test/example should not fail"), 720.0);
282/// ```
283#[allow(dead_code)]
284pub fn perm(n: u32, k: u32) -> SpecialResult<f64> {
285 permutations(n, k)
286}
287
288/// Computes the Stirling number of the first kind.
289///
290/// The unsigned Stirling number of the first kind s(n,k) counts
291/// the number of permutations of n elements with exactly k cycles.
292///
293/// # Arguments
294///
295/// * `n` - Number of elements
296/// * `k` - Number of cycles
297///
298/// # Returns
299///
300/// * `SpecialResult<f64>` - The unsigned Stirling number s(n,k)
301///
302/// # Examples
303///
304/// ```
305/// use scirs2_special::stirling_first;
306///
307/// assert_eq!(stirling_first(0, 0).expect("test/example should not fail"), 1.0);
308/// assert_eq!(stirling_first(4, 2).expect("test/example should not fail"), 11.0);
309/// assert_eq!(stirling_first(5, 3).expect("test/example should not fail"), 35.0);
310/// ```
311#[allow(dead_code)]
312pub fn stirling_first(n: u32, k: u32) -> SpecialResult<f64> {
313 if n == 0 && k == 0 {
314 return Ok(1.0);
315 }
316 if n == 0 || k == 0 || k > n {
317 return Ok(0.0);
318 }
319
320 // Use recurrence relation: s(n,k) = (n-1) * s(n-1,k) + s(n-1,k-1)
321 let mut dp = vec![vec![0.0; (k + 1) as usize]; (n + 1) as usize];
322 dp[0][0] = 1.0;
323
324 for i in 1..=n as usize {
325 for j in 1..=std::cmp::min(i, k as usize) {
326 dp[i][j] = (i - 1) as f64 * dp[i - 1][j] + dp[i - 1][j - 1];
327 }
328 }
329
330 Ok(dp[n as usize][k as usize])
331}
332
333/// Computes the Stirling number of the second kind.
334///
335/// The Stirling number of the second kind S(n,k) counts the number
336/// of ways to partition n elements into exactly k non-empty subsets.
337///
338/// # Arguments
339///
340/// * `n` - Number of elements
341/// * `k` - Number of subsets
342///
343/// # Returns
344///
345/// * `SpecialResult<f64>` - The Stirling number S(n,k)
346///
347/// # Examples
348///
349/// ```
350/// use scirs2_special::stirling_second;
351///
352/// assert_eq!(stirling_second(0, 0).expect("test/example should not fail"), 1.0);
353/// assert_eq!(stirling_second(4, 2).expect("test/example should not fail"), 7.0);
354/// assert_eq!(stirling_second(5, 3).expect("test/example should not fail"), 25.0);
355/// ```
356#[allow(dead_code)]
357pub fn stirling_second(n: u32, k: u32) -> SpecialResult<f64> {
358 if n == 0 && k == 0 {
359 return Ok(1.0);
360 }
361 if n == 0 || k == 0 || k > n {
362 return Ok(0.0);
363 }
364
365 // Use recurrence relation: S(n,k) = k * S(n-1,k) + S(n-1,k-1)
366 let mut dp = vec![vec![0.0; (k + 1) as usize]; (n + 1) as usize];
367 dp[0][0] = 1.0;
368
369 for i in 1..=n as usize {
370 for j in 1..=std::cmp::min(i, k as usize) {
371 dp[i][j] = j as f64 * dp[i - 1][j] + dp[i - 1][j - 1];
372 }
373 }
374
375 Ok(dp[n as usize][k as usize])
376}
377
378/// Computes the Stirling number of the second kind (alias for SciPy compatibility).
379///
380/// This is an alias for `stirling_second` to match SciPy's `stirling2` function.
381///
382/// # Arguments
383///
384/// * `n` - Number of elements
385/// * `k` - Number of subsets
386///
387/// # Returns
388///
389/// * `SpecialResult<f64>` - The Stirling number S(n,k)
390///
391/// # Examples
392///
393/// ```
394/// use scirs2_special::stirling2;
395///
396/// assert_eq!(stirling2(4, 2).expect("test/example should not fail"), 7.0);
397/// assert_eq!(stirling2(5, 3).expect("test/example should not fail"), 25.0);
398/// ```
399#[allow(dead_code)]
400pub fn stirling2(n: u32, k: u32) -> SpecialResult<f64> {
401 stirling_second(n, k)
402}
403
404/// Computes the Bell number B(n).
405///
406/// The Bell number B(n) counts the number of ways to partition
407/// a set of n elements into non-empty subsets.
408///
409/// # Arguments
410///
411/// * `n` - Number of elements
412///
413/// # Returns
414///
415/// * `SpecialResult<f64>` - The Bell number B(n)
416///
417/// # Examples
418///
419/// ```
420/// use scirs2_special::bell_number;
421///
422/// assert_eq!(bell_number(0).expect("test/example should not fail"), 1.0);
423/// assert_eq!(bell_number(1).expect("test/example should not fail"), 1.0);
424/// assert_eq!(bell_number(2).expect("test/example should not fail"), 2.0);
425/// assert_eq!(bell_number(3).expect("test/example should not fail"), 5.0);
426/// assert_eq!(bell_number(4).expect("test/example should not fail"), 15.0);
427/// ```
428#[allow(dead_code)]
429pub fn bell_number(n: u32) -> SpecialResult<f64> {
430 if n == 0 {
431 return Ok(1.0);
432 }
433
434 // B(n) = sum of S(n,k) for k from 0 to n
435 let mut result = 0.0;
436 for k in 0..=n {
437 result += stirling_second(n, k)?;
438 }
439 Ok(result)
440}
441
442/// Computes the Bernoulli number B(n).
443///
444/// The Bernoulli numbers are a sequence of rational numbers defined
445/// by the generating function t/(e^t - 1) = sum(B_n * t^n / n!).
446///
447/// This implementation returns the modern convention where B_1 = -1/2.
448///
449/// # Arguments
450///
451/// * `n` - Index of the Bernoulli number
452///
453/// # Returns
454///
455/// * `SpecialResult<f64>` - The Bernoulli number B(n)
456///
457/// # Examples
458///
459/// ```
460/// use scirs2_special::bernoulli_number;
461/// use approx::assert_relative_eq;
462///
463/// assert_eq!(bernoulli_number(0).expect("test/example should not fail"), 1.0);
464/// assert_relative_eq!(bernoulli_number(1).expect("test/example should not fail"), -0.5, epsilon = 1e-10);
465/// assert_relative_eq!(bernoulli_number(2).expect("test/example should not fail"), 1.0/6.0, epsilon = 1e-10);
466/// assert_eq!(bernoulli_number(3).expect("test/example should not fail"), 0.0); // Odd Bernoulli numbers are 0 (except B_1)
467/// ```
468#[allow(dead_code)]
469pub fn bernoulli_number(n: u32) -> SpecialResult<f64> {
470 if n == 0 {
471 return Ok(1.0);
472 }
473 if n == 1 {
474 return Ok(-0.5);
475 }
476 if n > 1 && n % 2 == 1 {
477 return Ok(0.0); // Odd Bernoulli numbers are zero (except B_1)
478 }
479
480 // For small even n, use known values
481 match n {
482 2 => return Ok(1.0 / 6.0),
483 4 => return Ok(-1.0 / 30.0),
484 6 => return Ok(1.0 / 42.0),
485 8 => return Ok(-1.0 / 30.0),
486 10 => return Ok(5.0 / 66.0),
487 12 => return Ok(-691.0 / 2730.0),
488 _ => {} // Fall through to the recurrence relation below
489 }
490
491 // For larger values, use recurrence relation
492 // B_n = -1/(n+1) * sum_{k=0}^{n-1} C(n+1,k) * B_k
493 let mut bernoulli = vec![0.0; (n + 1) as usize];
494 bernoulli[0] = 1.0;
495 if n >= 1 {
496 bernoulli[1] = -0.5;
497 }
498
499 for m in 2..=(n as usize) {
500 if m % 2 == 1 {
501 bernoulli[m] = 0.0;
502 continue;
503 }
504
505 let mut sum = 0.0;
506 for (k, &bernoulli_k) in bernoulli.iter().enumerate().take(m) {
507 let binom_coeff = binomial((m + 1) as u32, k as u32)?;
508 sum += binom_coeff * bernoulli_k;
509 }
510 bernoulli[m] = -sum / (m + 1) as f64;
511 }
512
513 Ok(bernoulli[n as usize])
514}
515
516/// Computes the Euler number E(n).
517///
518/// The Euler numbers are integers defined by the generating function
519/// sech(t) = 2/(e^t + e^(-t)) = sum(E_n * t^n / n!).
520/// Only even-indexed Euler numbers are non-zero.
521///
522/// # Arguments
523///
524/// * `n` - Index of the Euler number
525///
526/// # Returns
527///
528/// * `SpecialResult<f64>` - The Euler number E(n)
529///
530/// # Examples
531///
532/// ```
533/// use scirs2_special::euler_number;
534///
535/// assert_eq!(euler_number(0).expect("test/example should not fail"), 1.0);
536/// assert_eq!(euler_number(1).expect("test/example should not fail"), 0.0);
537/// assert_eq!(euler_number(2).expect("test/example should not fail"), -1.0);
538/// assert_eq!(euler_number(4).expect("test/example should not fail"), 5.0);
539/// ```
540#[allow(dead_code)]
541pub fn euler_number(n: u32) -> SpecialResult<f64> {
542 if n % 2 == 1 {
543 return Ok(0.0); // Odd Euler numbers are zero
544 }
545
546 // Known values for small even n
547 match n {
548 0 => return Ok(1.0),
549 2 => return Ok(-1.0),
550 4 => return Ok(5.0),
551 6 => return Ok(-61.0),
552 8 => return Ok(1385.0),
553 10 => return Ok(-50521.0),
554 _ => {} // Fall through to computation below
555 }
556
557 // For larger values, use more efficient algorithms
558 if n > 100 {
559 // For very large n, use asymptotic approximation
560 return euler_number_asymptotic(n as i32);
561 } else if n > 20 {
562 // For moderate values, use improved recurrence with rational arithmetic
563 return euler_number_improved_recurrence(n as i32);
564 }
565
566 // Use standard recurrence relation for small values
567 euler_number_standard_recurrence(n as i32)
568}
569
570/// Standard recurrence relation for Euler numbers (small n)
571#[allow(dead_code)]
572fn euler_number_standard_recurrence(n: i32) -> SpecialResult<f64> {
573 // Use recurrence relation based on generating function
574 let mut euler = vec![0.0; (n + 1) as usize];
575 euler[0] = 1.0;
576
577 for m in (2..=(n as usize)).step_by(2) {
578 let mut sum = 0.0;
579 for k in (0..m).step_by(2) {
580 let binom_coeff = binomial(m as u32, k as u32)?;
581 sum += binom_coeff * euler[k];
582 }
583 euler[m] = -sum;
584 }
585
586 Ok(euler[n as usize])
587}
588
589/// Improved recurrence relation for Euler numbers using rational arithmetic (moderate n)
590#[allow(dead_code)]
591fn euler_number_improved_recurrence(n: i32) -> SpecialResult<f64> {
592 // Use the recurrence relation with better numerical stability
593 // E_n = -sum_{k=0}^{n-1} C(n,k) * E_k for even n
594
595 if n % 2 == 1 {
596 return Ok(0.0); // Euler numbers are zero for odd indices
597 }
598
599 // For moderate values, use a more memory-efficient approach
600 // that doesn't store all intermediate values
601
602 let mut _prev_eulr = [0.0; 2]; // Only store last two values (reserved for future optimization)
603 _prev_eulr[0] = 1.0; // E_0 = 1
604
605 if n == 0 {
606 return Ok(1.0);
607 }
608
609 // Store a few more values for better efficiency
610 let mut euler_cache = vec![0.0; (n / 2 + 1) as usize];
611 euler_cache[0] = 1.0; // E_0 = 1
612
613 for m in (2..=n).step_by(2) {
614 let m_idx = (m / 2) as usize;
615 let mut sum = 0.0;
616
617 for k in (0..m).step_by(2) {
618 let k_idx = (k / 2) as usize;
619
620 // Use more efficient binomial coefficient computation
621 let binom_coeff = efficient_binomial(m as u32, k as u32)?;
622 sum += binom_coeff * euler_cache[k_idx];
623 }
624
625 euler_cache[m_idx] = -sum;
626 }
627
628 Ok(euler_cache[(n / 2) as usize])
629}
630
631/// Asymptotic approximation for Euler numbers (large n)
632#[allow(dead_code)]
633fn euler_number_asymptotic(n: i32) -> SpecialResult<f64> {
634 if n % 2 == 1 {
635 return Ok(0.0); // Euler numbers are zero for odd indices
636 }
637
638 // For large even n, use the asymptotic formula:
639 // |E_n| ~ 8 * sqrt(2/π) * (2^{n+2} * n! / π^{n+1}) * [1 + O(1/n)]
640
641 let n_f = n as f64;
642
643 // Use Stirling's approximation for n!
644 // ln(n!) ≈ n*ln(n) - n + 0.5*ln(2πn)
645 let ln_n_factorial = n_f * n_f.ln() - n_f + 0.5 * (2.0 * PI * n_f).ln();
646
647 // Calculate log of the asymptotic approximation to avoid overflow
648 // ln|E_n| ≈ ln(8) + 0.5*ln(2/π) + (n+2)*ln(2) + ln(n!) - (n+1)*ln(π)
649
650 let ln_8 = 8.0_f64.ln();
651 let ln_sqrt_2_over_pi = 0.5 * (2.0 / PI).ln();
652 let power_of_2_term = (n_f + 2.0) * 2.0_f64.ln();
653 let pi_power_term = -(n_f + 1.0) * PI.ln();
654
655 let ln_magnitude = ln_8 + ln_sqrt_2_over_pi + power_of_2_term + ln_n_factorial + pi_power_term;
656
657 // Check if the result would overflow
658 if ln_magnitude > 700.0 {
659 return Err(SpecialError::OverflowError(
660 "Euler number too large to represent as f64".to_string(),
661 ));
662 }
663
664 let magnitude = ln_magnitude.exp();
665
666 // Apply the correct sign: E_n = (-1)^{n/2} * |E_n|
667 let sign = if (n / 2) % 2 == 0 { 1.0 } else { -1.0 };
668
669 Ok(sign * magnitude)
670}
671
672/// More efficient binomial coefficient computation for moderate values
673#[allow(dead_code)]
674fn efficient_binomial(n: u32, k: u32) -> SpecialResult<f64> {
675 if k > n {
676 return Ok(0.0);
677 }
678
679 if k == 0 || k == n {
680 return Ok(1.0);
681 }
682
683 // Use symmetry to reduce computation
684 let k_use = if k > n - k { n - k } else { k };
685
686 // For larger values, use logarithmic computation to avoid overflow
687 if n > 30 {
688 use crate::gamma::gamma;
689
690 // C(n,k) = Γ(n+1) / (Γ(k+1) * Γ(n-k+1))
691 let ln_result = (gamma((n + 1) as f64).ln())
692 - (gamma((k_use + 1) as f64).ln())
693 - (gamma((n - k_use + 1) as f64).ln());
694
695 if ln_result > 700.0 {
696 return Err(SpecialError::OverflowError(
697 "Binomial coefficient too large".to_string(),
698 ));
699 }
700
701 Ok(ln_result.exp())
702 } else {
703 // Use the standard multiplication approach for smaller values
704 let mut result = 1.0;
705 for i in 0..k_use {
706 result *= (n - i) as f64;
707 result /= (i + 1) as f64;
708 }
709 Ok(result)
710 }
711}
712
713/// Combination function - alias for binomial coefficient
714///
715/// This function provides SciPy compatibility for `comb(n, k)`
716/// which is the number of ways to choose k items from n items.
717#[allow(dead_code)]
718pub fn comb(n: u32, k: u32) -> SpecialResult<f64> {
719 binomial(n, k)
720}
721
722#[cfg(test)]
723mod tests {
724 use super::*;
725 use approx::assert_relative_eq;
726
727 #[test]
728 fn test_factorial() {
729 assert_eq!(factorial(0).expect("test/example should not fail"), 1.0);
730 assert_eq!(factorial(1).expect("test/example should not fail"), 1.0);
731 assert_eq!(factorial(5).expect("test/example should not fail"), 120.0);
732 assert_eq!(
733 factorial(10).expect("test/example should not fail"),
734 3628800.0
735 );
736
737 // Test larger values using gamma function
738 assert_relative_eq!(
739 factorial(15).expect("test/example should not fail"),
740 1307674368000.0,
741 epsilon = 1.0
742 );
743 }
744
745 #[test]
746 fn test_double_factorial() {
747 assert_eq!(
748 double_factorial(0).expect("test/example should not fail"),
749 1.0
750 );
751 assert_eq!(
752 double_factorial(1).expect("test/example should not fail"),
753 1.0
754 );
755 assert_eq!(
756 double_factorial(2).expect("test/example should not fail"),
757 2.0
758 );
759 assert_eq!(
760 double_factorial(5).expect("test/example should not fail"),
761 15.0
762 ); // 5 × 3 × 1
763 assert_eq!(
764 double_factorial(6).expect("test/example should not fail"),
765 48.0
766 ); // 6 × 4 × 2
767 assert_eq!(
768 double_factorial(8).expect("test/example should not fail"),
769 384.0
770 ); // 8 × 6 × 4 × 2
771 }
772
773 #[test]
774 fn test_factorial2() {
775 assert_eq!(factorial2(0).expect("test/example should not fail"), 1.0);
776 assert_eq!(factorial2(5).expect("test/example should not fail"), 15.0); // 5 × 3 × 1
777 assert_eq!(factorial2(6).expect("test/example should not fail"), 48.0); // 6 × 4 × 2
778
779 // Test that factorial2 is the same as double_factorial
780 assert_eq!(
781 factorial2(8).expect("test/example should not fail"),
782 double_factorial(8).expect("test/example should not fail")
783 );
784 }
785
786 #[test]
787 fn test_factorialk() {
788 assert_eq!(factorialk(0, 1).expect("test/example should not fail"), 1.0);
789 assert_eq!(
790 factorialk(8, 3).expect("test/example should not fail"),
791 80.0
792 ); // 8 × 5 × 2
793 assert_eq!(
794 factorialk(5, 2).expect("test/example should not fail"),
795 15.0
796 ); // 5 × 3 × 1
797 assert_eq!(
798 factorialk(6, 2).expect("test/example should not fail"),
799 48.0
800 ); // 6 × 4 × 2 (same as double factorial)
801 assert_eq!(
802 factorialk(9, 4).expect("test/example should not fail"),
803 45.0
804 ); // 9 × 5 × 1
805
806 // Test k=1 (should be regular factorial)
807 assert_eq!(
808 factorialk(5, 1).expect("test/example should not fail"),
809 factorial(5).expect("test/example should not fail")
810 );
811
812 // Test error case
813 assert!(factorialk(5, 0).is_err());
814 }
815
816 #[test]
817 fn test_binomial() {
818 assert_eq!(binomial(5, 2).expect("test/example should not fail"), 10.0);
819 assert_eq!(
820 binomial(10, 3).expect("test/example should not fail"),
821 120.0
822 );
823 assert_eq!(binomial(7, 0).expect("test/example should not fail"), 1.0);
824 assert_eq!(binomial(7, 7).expect("test/example should not fail"), 1.0);
825 assert_eq!(binomial(5, 10).expect("test/example should not fail"), 0.0); // k > n
826
827 // Test symmetry
828 assert_eq!(
829 binomial(10, 3).expect("test/example should not fail"),
830 binomial(10, 7).expect("test/example should not fail")
831 );
832 }
833
834 #[test]
835 fn test_permutations() {
836 assert_eq!(
837 permutations(5, 2).expect("test/example should not fail"),
838 20.0
839 );
840 assert_eq!(
841 permutations(10, 3).expect("test/example should not fail"),
842 720.0
843 );
844 assert_eq!(
845 permutations(7, 0).expect("test/example should not fail"),
846 1.0
847 );
848 assert_eq!(
849 permutations(5, 10).expect("test/example should not fail"),
850 0.0
851 ); // k > n
852 }
853
854 #[test]
855 fn test_perm() {
856 assert_eq!(perm(5, 2).expect("test/example should not fail"), 20.0);
857 assert_eq!(perm(10, 3).expect("test/example should not fail"), 720.0);
858
859 // Test that perm is the same as permutations
860 assert_eq!(
861 perm(7, 3).expect("test/example should not fail"),
862 permutations(7, 3).expect("test/example should not fail")
863 );
864 }
865
866 #[test]
867 fn test_stirling_first() {
868 assert_eq!(
869 stirling_first(0, 0).expect("test/example should not fail"),
870 1.0
871 );
872 assert_eq!(
873 stirling_first(4, 2).expect("test/example should not fail"),
874 11.0
875 );
876 assert_eq!(
877 stirling_first(5, 3).expect("test/example should not fail"),
878 35.0
879 );
880 assert_eq!(
881 stirling_first(3, 0).expect("test/example should not fail"),
882 0.0
883 );
884 assert_eq!(
885 stirling_first(0, 3).expect("test/example should not fail"),
886 0.0
887 );
888 }
889
890 #[test]
891 fn test_stirling_second() {
892 assert_eq!(
893 stirling_second(0, 0).expect("test/example should not fail"),
894 1.0
895 );
896 assert_eq!(
897 stirling_second(4, 2).expect("test/example should not fail"),
898 7.0
899 );
900 assert_eq!(
901 stirling_second(5, 3).expect("test/example should not fail"),
902 25.0
903 );
904 assert_eq!(
905 stirling_second(3, 0).expect("test/example should not fail"),
906 0.0
907 );
908 assert_eq!(
909 stirling_second(0, 3).expect("test/example should not fail"),
910 0.0
911 );
912 }
913
914 #[test]
915 fn test_stirling2() {
916 assert_eq!(stirling2(4, 2).expect("test/example should not fail"), 7.0);
917 assert_eq!(stirling2(5, 3).expect("test/example should not fail"), 25.0);
918
919 // Test that stirling2 is the same as stirling_second
920 assert_eq!(
921 stirling2(6, 3).expect("test/example should not fail"),
922 stirling_second(6, 3).expect("test/example should not fail")
923 );
924 }
925
926 #[test]
927 fn test_bell_number() {
928 assert_eq!(bell_number(0).expect("test/example should not fail"), 1.0);
929 assert_eq!(bell_number(1).expect("test/example should not fail"), 1.0);
930 assert_eq!(bell_number(2).expect("test/example should not fail"), 2.0);
931 assert_eq!(bell_number(3).expect("test/example should not fail"), 5.0);
932 assert_eq!(bell_number(4).expect("test/example should not fail"), 15.0);
933 assert_eq!(bell_number(5).expect("test/example should not fail"), 52.0);
934 }
935
936 #[test]
937 fn test_bernoulli_number() {
938 assert_eq!(
939 bernoulli_number(0).expect("test/example should not fail"),
940 1.0
941 );
942 assert_relative_eq!(
943 bernoulli_number(1).expect("test/example should not fail"),
944 -0.5,
945 epsilon = 1e-10
946 );
947 assert_relative_eq!(
948 bernoulli_number(2).expect("test/example should not fail"),
949 1.0 / 6.0,
950 epsilon = 1e-10
951 );
952 assert_eq!(
953 bernoulli_number(3).expect("test/example should not fail"),
954 0.0
955 );
956 assert_relative_eq!(
957 bernoulli_number(4).expect("test/example should not fail"),
958 -1.0 / 30.0,
959 epsilon = 1e-10
960 );
961 assert_eq!(
962 bernoulli_number(5).expect("test/example should not fail"),
963 0.0
964 );
965 }
966
967 #[test]
968 fn test_euler_number() {
969 assert_eq!(euler_number(0).expect("test/example should not fail"), 1.0);
970 assert_eq!(euler_number(1).expect("test/example should not fail"), 0.0);
971 assert_eq!(euler_number(2).expect("test/example should not fail"), -1.0);
972 assert_eq!(euler_number(3).expect("test/example should not fail"), 0.0);
973 assert_eq!(euler_number(4).expect("test/example should not fail"), 5.0);
974 assert_eq!(
975 euler_number(6).expect("test/example should not fail"),
976 -61.0
977 );
978 }
979}