Это обобщение известной проблемы дня рождения : если человек, у которых есть случайные, равномерно распределенные «дни рождения» среди набора возможностей, какова вероятность того, что ни один день рождения не разделен более чем человек?д = 6 м = 20n=100d=6m=20
Точный расчет дает ответ (с двойной точностью). Я набросаю теорию и приведу код для общих Асимптотическая синхронизация кода - что делает его пригодным для очень большого числа дней рождения и обеспечивает разумную производительность, пока не исчисляется тысячами. В этот момент приближение Пуассона, обсуждавшееся при распространении парадокса дня рождения на более чем 2 человека, должно работать хорошо в большинстве случаев.0.267747907805267n,m,d.O(n2log(d))dn
Объяснение решения
Функция генерации вероятности (pgf) для результатов независимых бросков кубика с сторонойnd
d−nfn(x1,x2,…,xd)=d−n(x1+x2+⋯+xd)n.
Коэффициент в разложении этого многочлена дает количество способов, с помощью которых могу появиться ровно раз, я е я я = 1 , 2 , ... , д .xe11xe22⋯xeddieii=1,2,…,d.
Ограничение нашего интереса не более чем появлениями любого лица равносильно оценке по модулю идеала порожденного Чтобы выполнить эту оценку, рекурсивно используйте теорему о биномf n I x m + 1 1 , x m + 1 2 , … , x m + 1 d .mfnIxm+11,xm+12,…,xm+1d.
fn(x1,…,xd)=((x1+⋯+xr)+(xr+1+xr+2+⋯+x2r))n=∑k=0n(nk)(x1+⋯+xr)k(xr+1+⋯+x2r)n−k=∑k=0n(nk)fk(x1,…,xr)fn−k(xr+1,…,x2r)
когда четно. Написание ( терминов), мы имеемd=2rf(d)n=fn(1,1,…,1)d
f(2r)n=∑k=0n(nk)f(r)kf(r)n−k.(a)
Если нечетно, используйте аналогичное разложениеd=2r+1
fn(x1,…,xd)=((x1+⋯+x2r)+x2r+1)n=∑k=0n(nk)fk(x1,…,x2r)fn−k(x2r+1),
дающий
f(2r+1)n=∑k=0n(nk)f(2r)kf(1)n−k.(b)
В обоих случаях мы также можем уменьшить все по модулю , что легко выполняется, начиная сI
fn(xj)≅{xn0n≤mn>mmodI,
предоставление начальных значений для рекурсии,
f(1)n={10n≤mn>m
Что делает это эффективным, так это то, что, разбивая переменные на две равные по размеру группы переменных каждая и устанавливая все значения переменных в нам нужно только один раз оценить все для одной группы, а затем объединить результаты. Это требует вычисления до членов, каждый из которых требует вычисления для комбинации. Нам даже не нужен двумерный массив для хранения , потому что при вычислении требуются только и .dr1,n+1O(n)f(r)nf(d)n,f(r)nf(1)n
Общее количество шагов на единицу меньше количества цифр в двоичном разложении (которое считает разбиения на равные группы в формуле ) плюс количество единиц в разложении (которое считает все разы нечетными встречается значение, требующее применения формулы ). Это все еще только шагов.d(a)(b)O(log(d))
На R
десятилетней рабочей станции работа была выполнена за 0,007 секунды. Код указан в конце этого поста. Он использует логарифмы вероятностей, а не сами вероятности, чтобы избежать возможных переполнений или накопления слишком больших потерь. Это позволяет удалить фактор в решении, чтобы мы могли вычислить значения, лежащие в основе вероятностей.d−n
Обратите внимание, что эта процедура приводит к одновременному вычислению всей последовательности вероятностей , что позволяет легко изучить, как шансы изменяются с .f0,f1,…,fnn
Приложения
Распределение в обобщенной задаче дня рождения вычисляется функцией tmultinom.full
. Единственная проблема заключается в поиске верхней границы для числа людей, которые должны присутствовать, прежде чем вероятность столкновения станет слишком большой. Следующий код делает это грубой силой, начиная с малого и удваивая его, пока он не станет достаточно большим. Таким образом, весь расчет занимает время где - решение. Вычисляется полное распределение вероятностей для числа людей до .m+1nO(n2log(n)log(d))nn
#
# 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)
Специальная версия этой проблемы рассматривается при распространении парадокса дня рождения более чем на 2 человека , что касается случая стороннего штампа, который бросается очень много раз.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