/* * Created on Jun 9, 2005 */ package org.seqcode.math.probability; import java.util.Vector; import java.io.*; /** * @author tdanford */ public class Hypergeometric { public static void main(String[] args) { int birthdays = Integer.parseInt(args[0]); double prob = 0.0; for(int i = 1; prob < 0.5 && i < birthdays; i++) { prob = birthday_prob(birthdays, i); System.out.println(i + ": " + prob); } } public static void old_main(String[] args) { int total = Integer.parseInt(args[0]); int theta = Integer.parseInt(args[1]); int sample = Integer.parseInt(args[2]); int x = Integer.parseInt(args[3]); Hypergeometric h = new Hypergeometric(); double log_prob = h.log_hypgeomPValue(total, theta, sample, x); double prob = Math.exp(log_prob); System.out.println("Prob: " + prob); } private Vector<Double> logFactorial; public Hypergeometric() { logFactorial = new Vector<Double>(); logFactorial.setSize(21); logFactorial.set(0, -Double.MAX_VALUE); double sum = 0.0; for(int i = 1; i <= 20; i++) { logFactorial.set(i, sum); sum += Math.log((double)(i + 1)); } } public static double birthday_prob(int birthdays, int people) { double log_first = 0.0; for(int i = birthdays; i > birthdays-people; i--) { log_first += Math.log((double)i); } double log_second = (double)people * Math.log((double)birthdays); double total = log_first - log_second; double prob = 1.0 - Math.exp(total); return prob; } private void extendLogFactorial(int max) { int currentMax = logFactorial.size() - 1; if(max <= currentMax) { return; } logFactorial.setSize(max+1); double sum = logFactorial.get(currentMax); sum += Math.log((double)(currentMax + 1)); for(int i = currentMax + 1; i <= max; i++) { logFactorial.set(i, sum); sum += Math.log((double)(i + 1)); } } public double log_add(double v1, double v2) { //if(v1 > v2) { return v1 + Math.log((double)1.0 + Math.exp(v2 - v1)); //} else { //return log_add(v2, v1); //} } public double log_factorial(int n) { extendLogFactorial(n); return logFactorial.get(n); } public double log_choose(int N, int x) { if(x < 0 || N < 0 || x > N) { throw new IllegalArgumentException("params: " + N + " " + x); } if(x == N || x == 0 || N == 0) { return 0.0; } extendLogFactorial(N); double numer = logFactorial.get(N); double denom = logFactorial.get(N - x) + logFactorial.get(x); return numer - denom; } public double log_hypgeom(int N, int theta, int n, int x) { /** * factors: * numer1: (theta choose x) * numer2: (N - theta choose n - x) * denom: (N choose n) */ double n1 = log_choose(theta, x); double n2 = log_choose(N-theta, n-x); double d = log_choose(N, n); return (n1 + n2) - d; } public double log_hypgeomPValue(int N, int theta, int n, int x) { try { int max = n; if(theta < max) { max = theta; } double log_sum = 0.0; for(int i = x; i <= max; i++) { if(i == x) { log_sum = log_hypgeom(N, theta, n, i); } else { log_sum = log_add(log_sum, log_hypgeom(N, theta, n, i)); } } return log_sum; } catch(IllegalArgumentException iae) { String error = "Error occurred with parameters: " + N + ", " + theta + ", " + n + ", " + x; throw new IllegalArgumentException(error); } } }