이것은 유명한 일반화 생일 문제 : 주어진 n=100 세트 중에서 무작위로, 균일하게 분포 "생일"가 개인 d=6 , 더 생일 이상 공유되지 않도록 기회 것입니다 가능성 m=20 개인이?
정확한 계산 은 답을 0.267로 산출합니다 (배정도) 이론을 스케치하고 일반 n , m , d에 대한 코드를 제공합니다 . 코드의 점근 적 타이밍은 O ( n 2 log ( d ) ) 로 매우 많은 생일 d에 적합하고 n 이 수천이될 때까지 합리적인 성능을 제공합니다. 이 시점에서 생일 패러독스를 2 명 이상으로 확장에서논의한 포아송 근사는 대부분의 경우 잘 작동해야합니다.0.267747907805267n,m,d.O(n2log(d))dn
솔루션 설명
d면 다이 의 독립적 인 롤의 결과에 대한 확률 생성 함수 (pgf) 는nd
d−nfn(x1,x2,…,xd)=d−n(x1+x2+⋯+xd)n.
계수 이 다항식의 팽창은 대향하는 방식의 숫자 부여 제가 정확하게 나타날 수있는 전자 나 , 시간 내가 = 1 , 2 , ... , D를 .xe11xe22⋯xeddieii=1,2,…,d.
우리의 관심을 어떤 얼굴로도 개 이하로 제한 하는 것은 f n 모듈러스 를 x m + 1 1 , x m + 1 2 , … , x m + 1 d에 의해 생성 된 이상적인 I 를 평가 하는 데 가장 중요합니다 . 이 평가를 수행하려면 이항 정리를 재귀 적으로 사용하여mfnIxm+11,xm+12,…,xm+1d.
에프엔( x1, … , x디)= ( ( x1+ ⋯ + x아르 자형) + ( xr + 1+ xr + 2+ ⋯ + x2 R) )엔= ∑k = 0엔( n케이) (x1+ ⋯ + x아르 자형)케이( xr + 1+ ⋯ + x2 R)n - k= ∑k = 0엔( n케이) f케이( x1, … , x아르 자형) fn - k( xr + 1, … , x2 R)
경우 짝수이다. f ( d ) n = f n ( 1 , 1 , … , 1 ) ( d 항)이라고 쓰면디= 2 (R)에프( d)엔= f엔( 1 , 1 , … , 1 )디
에프( 2 r )엔= ∑k = 0엔( n케이) f( r )케이에프( r )n - k.(ㅏ)
경우 홀수, 유사한 분해를 사용디= 2 (R) + 1
에프엔( x1, … , x디)= ( ( x1+ ⋯ + x2 R) + x2 r + 1)엔= ∑k = 0엔( n케이) f케이( x1, … , x2 R) fn - k( x2 r + 1) ,
기부
에프( 2 r + 1 )엔= ∑k = 0엔( n케이) f( 2 r )케이에프( 1 )n - k.(비)
두 경우 모두, 우리는 또한 모든 것을 모듈로 줄일 수 있습니다 쉽게로 시작하는 수행,나는
에프엔( x제이) ≅{ x엔0n ≤ mn > m모드나는,
재귀의 시작 값을 제공하고
에프( 1 )엔= { 10n ≤ mn > m
이것이 효율적으로 만드는 것은 분할에 의한 것입니다 의 동일한 크기의 두 그룹으로 변수 r에 변수 각각의 모든 변수 값을 설정 1 , 우리는 모든 것을 평가해야 한 번 결과를 하나 개의 그룹을 한 후 결합한다. 이것은 최대 컴퓨팅 요구 N + 1 그들 각각 필요한 용어 O ( N ) 조합에 대해 계산한다. 우리는 f ( r ) n 을 저장하기 위해 2D 배열이 필요하지 않습니다.디아르 자형1 ,n + 1O ( n )에프( r )엔 , 계산할 때 때문에 단 F에프( d)엔, 및f ( 1 ) n 이 필요합니다.에프( r )엔에프( 1 )엔
총 단계 수는 의 이진 확장에있는 자릿수 (공식 ( a ) 에서 동일한 그룹으로 분할을 계산 )와 확장에있는 단계 수 (모든 시간을 홀수로 계산) 식 ( b ) 의 적용을 요구하는 값에 직면 한다. 여전히 O ( log ( d ) ) 단계입니다.디( a )( b )O ( 로그( d) )
에서 R
10 년 된 워크 스테이션에서 작업은 0.007 초에 이루어졌다. 이 게시물 끝에 코드가 표시되어 있습니다. 오버플로가 발생하거나 언더 플로가 너무 많이 누적되는 것을 방지하기 위해 확률 자체가 아닌 확률의 로그를 사용합니다. 이를 통해 솔루션에서 인수 를 제거 할 수 있으므로 확률의 기초가되는 계수를 계산할 수 있습니다.디− n
이 절차는 전체 확률 시퀀스를 계산합니다. 쉽게 기회로 변경하는 방법을 공부하기 위해 할 수있는, 한 번에 N .에프0, f1, … , f엔엔
응용
일반화 된 생일 문제의 분포는 함수에 의해 계산됩니다 tmultinom.full
. 유일한 도전은 충돌 의 기회 가 너무 커지기 전에 참석 해야하는 사람들의 상한을 찾는 것 입니다. 다음 코드는 작은 n으로 시작하여 충분히 커질 때까지 두 배로 무차별 강제로 이를 수행합니다. 그러므로 전체 계산에는 O ( n 2 log가 필요함m + 1엔 시간 여기서 N 용액이다. n 부터 n 까지의 인원에 대한 확률의 전체 분포가 계산됩니다.O ( n2로그( n ) 로그( d) )엔엔
#
# The birthday problem: find the number of people where the chance of
# a collision of `m+1` birthdays first exceeds `alpha`.
#
birthday <- function(m=1, d=365, alpha=0.50) {
n <- 8
while((p <- tmultinom.full(n, m, d))[n] > alpha) n <- n * 2
return(p)
}
798birthday(7)
365
암호
# Compute the chance that in `n` independent rolls of a `d`-sided die,
# no side appears more than `m` times.
#
tmultinom <- function(n, m, d, count=FALSE) tmultinom.full(n, m, d, count)[n+1]
#
# Compute the chances that in 0, 1, 2, ..., `n` independent rolls of a
# `d`-sided die, no side appears more than `m` times.
#
tmultinom.full <- function(n, m, d, count=FALSE) {
if (n < 0) return(numeric(0))
one <- rep(1.0, n+1); names(one) <- 0:n
if (d <= 0 || m >= n) return(one)
if(count) log.p <- 0 else log.p <- -log(d)
f <- function(n, m, d) { # The recursive solution
if (d==1) return(one) # Base case
r <- floor(d/2)
x <- double(f(n, m, r), m) # Combine two equal values
if (2*r < d) x <- combine(x, one, m) # Treat odd `d`
return(x)
}
one <- c(log.p*(0:m), rep(-Inf, n-m)) # Reduction modulo x^(m+1)
double <- function(x, m) combine(x, x, m)
combine <- function(x, y, m) { # The Binomial Theorem
z <- sapply(1:length(x), function(n) { # Need all powers 0..n
z <- x[1:n] + lchoose(n-1, 1:n-1) + y[n:1]
z.max <- max(z)
log(sum(exp(z - z.max), na.rm=TRUE)) + z.max
})
return(z)
}
x <- exp(f(n, m, d)); names(x) <- 0:n
return(x)
}
대답은
print(tmultinom(100,20,6), digits=15)
0.267747907805267