/* Copyright (C) 2001 Kyle Siegrist, Dawn Duehring This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package distributions; /** This class models the distribution of the sample size needed to get a specified number of distinct sample values when sampling with replacement from a finite population of a specified size*/ public class CouponDistribution extends Distribution{ int popSize, distinctValues, upperValue; double[][] prob; /**This general constructor: creates a new coupon distribution with specified population size and distinct sample size.*/ public CouponDistribution(int m, int k){ setParameters(m, k); } /**This general constructor creates a new coupon distribution with population size 10 and distinct sample size 10.*/ public CouponDistribution(){ this(10, 10); } /**This method sets the parameters: the population size and number of distinct values needed*/ public void setParameters(int m, int k){ int upperIndex, maxIndex; //Correct for invalid parameters if (m < 1) m = 1; if (k < 1) k = 1; else if (k > m) k = m; popSize = m; distinctValues = k; upperValue = (int)Math.ceil(getMean() + 4 * getSD()); super.setParameters(distinctValues, upperValue, 1, DISCRETE); prob = new double[upperValue + 1][popSize + 1]; prob[0][0] = 1; prob[1][1] = 1; for (int i = 1; i < upperValue; i++){ if (i < popSize) upperIndex = i + 1; else upperIndex = popSize; for (int n = 1; n <= upperIndex; n++){ prob[i + 1][n] = prob[i][n] * ((double)n / popSize) + prob[i][n - 1] * ((double)(popSize - n + 1) / popSize); } } } /**Density function*/ public double getDensity(double x){ int k = (int)(Math.rint(x)); if (k < distinctValues | k > upperValue) return 0; else return ((double)(popSize - distinctValues + 1) / popSize) * prob[k - 1][distinctValues - 1]; } /**Mean*/ public double getMean(){ double sum = 0; for (int i = 1; i <= distinctValues; i++) sum = sum + (double)popSize / (popSize - i + 1); return sum; } /**Variance*/ public double getVariance(){ double sum = 0; for (int i = 1; i <= distinctValues; i++) sum = sum + (double)(popSize * (i - 1)) / ((popSize - i + 1) * (popSize - i + 1)); return sum; } /**Get the population size*/ public double getPopSize(){ return popSize; } /**Set the population size*/ public void setPopSize(int m){ setParameters(m, distinctValues); } /**Get the number of distinct values*/ public double getDistinctValues(){ return distinctValues; } /**Set the number of distinct values*/ public void setDistinctValues(int k){ setParameters(popSize, k); } /**Simulate a value from the distribution*/ public double simulate(){ int[] cellCount = new int[(int)popSize]; double occupiedCells = 0; int ballCount = 0; while (occupiedCells <= distinctValues){ ballCount++; int ballIndex = (int)(popSize * Math.random()); if (cellCount[ballIndex] == 0) occupiedCells++; cellCount[ballIndex] = cellCount[ballIndex]++; } return ballCount; } }