From ebe3f8597672f873c144e67810797015c0017a9f Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Fri, 17 Mar 2017 17:25:26 +0100 Subject: [PATCH 1/3] Implement multinomial --- integer/src/lib.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/integer/src/lib.rs b/integer/src/lib.rs index b84b7af..6230c84 100644 --- a/integer/src/lib.rs +++ b/integer/src/lib.rs @@ -16,6 +16,8 @@ extern crate num_traits as traits; +use std::ops::Add; + use traits::{Num, Signed}; pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { @@ -694,6 +696,22 @@ pub fn binomial(mut n: T, k: T) -> T { r } +/// Calculate the multinomial coefficient. +/// +/// Panics if no integers are specified. +pub fn multinomial(k: &[T]) -> T + where for<'a> T: Add<&'a T, Output = T> +{ + assert!(k.len() > 0, "need at least one integer"); + let mut r = T::one(); + let mut p = T::zero(); + for i in k { + p = p + i; + r = r * binomial(p.clone(), i.clone()); + } + r +} + #[test] fn test_lcm_overflow() { macro_rules! check { @@ -777,3 +795,76 @@ fn test_binomial() { check!(i64, 0, 0, 1); check!(i64, 2, 3, 0); } + +#[test] +fn test_multinomial() { + macro_rules! check_binomial { + ($t:ty, $k:expr) => { { + let n: $t = $k.iter().sum(); + let k: &[$t] = $k; + assert_eq!(k.len(), 2); + assert_eq!(multinomial(k), binomial(n, k[0])); + } } + } + + check_binomial!(u8, &[4, 5]); + + check_binomial!(i8, &[4, 5]); + + check_binomial!(u16, &[2, 98]); + check_binomial!(u16, &[4, 10]); + + check_binomial!(i16, &[2, 98]); + check_binomial!(i16, &[4, 10]); + + check_binomial!(u32, &[2, 98]); + check_binomial!(u32, &[11, 24]); + check_binomial!(u32, &[4, 10]); + + check_binomial!(i32, &[2, 98]); + check_binomial!(i32, &[11, 24]); + check_binomial!(i32, &[4, 10]); + + check_binomial!(u64, &[2, 98]); + check_binomial!(u64, &[11, 24]); + check_binomial!(u64, &[4, 10]); + + check_binomial!(i64, &[2, 98]); + check_binomial!(i64, &[11, 24]); + check_binomial!(i64, &[4, 10]); + + macro_rules! check_multinomial { + ($t:ty, $k:expr, $r:expr) => { { + let k: &[$t] = $k; + let expected: $t = $r; + assert_eq!(multinomial(k), expected); + } } + } + + check_multinomial!(u8, &[2, 1, 2], 30); + check_multinomial!(u8, &[2, 3, 0], 10); + + check_multinomial!(i8, &[2, 1, 2], 30); + check_multinomial!(i8, &[2, 3, 0], 10); + + check_multinomial!(u16, &[2, 1, 2], 30); + check_multinomial!(u16, &[2, 3, 0], 10); + + check_multinomial!(i16, &[2, 1, 2], 30); + check_multinomial!(i16, &[2, 3, 0], 10); + + check_multinomial!(u32, &[2, 1, 2], 30); + check_multinomial!(u32, &[2, 3, 0], 10); + + check_multinomial!(i32, &[2, 1, 2], 30); + check_multinomial!(i32, &[2, 3, 0], 10); + + check_multinomial!(u64, &[2, 1, 2], 30); + check_multinomial!(u64, &[2, 3, 0], 10); + + check_multinomial!(i64, &[2, 1, 2], 30); + check_multinomial!(i64, &[2, 3, 0], 10); + + check_multinomial!(u64, &[0], 1); + check_multinomial!(u64, &[12345], 1); +} From c408bd66052fafb55500a77a640ff39c034b2083 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Fri, 17 Mar 2017 18:21:06 +0100 Subject: [PATCH 2/3] Try to fix build on Rust 1.8 --- integer/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integer/src/lib.rs b/integer/src/lib.rs index 6230c84..dedbd94 100644 --- a/integer/src/lib.rs +++ b/integer/src/lib.rs @@ -800,7 +800,7 @@ fn test_binomial() { fn test_multinomial() { macro_rules! check_binomial { ($t:ty, $k:expr) => { { - let n: $t = $k.iter().sum(); + let n: $t = $k.iter().fold(0, |acc, &x| acc + x); let k: &[$t] = $k; assert_eq!(k.len(), 2); assert_eq!(multinomial(k), binomial(n, k[0])); From 3de345f91298def0e2499019cf3160caacb5fe72 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Mon, 20 Mar 2017 09:43:01 +0100 Subject: [PATCH 3/3] Don't panic when calculating multinomial --- integer/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/integer/src/lib.rs b/integer/src/lib.rs index dedbd94..0273641 100644 --- a/integer/src/lib.rs +++ b/integer/src/lib.rs @@ -697,12 +697,9 @@ pub fn binomial(mut n: T, k: T) -> T { } /// Calculate the multinomial coefficient. -/// -/// Panics if no integers are specified. pub fn multinomial(k: &[T]) -> T where for<'a> T: Add<&'a T, Output = T> { - assert!(k.len() > 0, "need at least one integer"); let mut r = T::one(); let mut p = T::zero(); for i in k { @@ -865,6 +862,7 @@ fn test_multinomial() { check_multinomial!(i64, &[2, 1, 2], 30); check_multinomial!(i64, &[2, 3, 0], 10); + check_multinomial!(u64, &[], 1); check_multinomial!(u64, &[0], 1); check_multinomial!(u64, &[12345], 1); }