/* 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 Fisher F distribution with a spcified number of degrees of freedom in the numerator and denominator*/ public class FisherDistribution extends Distribution{ private int nDegrees, dDegrees; private double c; /**This general constructor creates a new Fisher distribution with a specified number of degrees of freedom in the numerator and denominator*/ public FisherDistribution(int n, int d){ setParameters(n, d); } /**This default constructor creates a new Fisher distribution with 5 degrees of freedom in numerator and denominator*/ public FisherDistribution(){ this(5, 5); } /**This method sets the parameters, the degrees of freedom in the numerator and denominator. Additionally, the normalizing constant and default interval are computed*/ public void setParameters(int n, int d){ double upper, width; //Correct invalid parameters if (n < 1) n = 1; if (d < 1) d = 1; nDegrees = n; dDegrees = d; //Compute normalizing constant c = logGamma(0.5 * (nDegrees + dDegrees)) - logGamma(0.5 * nDegrees) - logGamma(0.5 * dDegrees) + 0.5 * nDegrees * (Math.log(nDegrees) - Math.log(dDegrees)); //Compute interval if (dDegrees <= 4) upper = 20; else upper = getMean() + 4 * getSD(); width = 0.01 * upper; super.setParameters(0, upper, width, CONTINUOUS); } /**This method computes the denisty function*/ public double getDensity(double x){ if (x < 0) return 0; else if (x == 0 & nDegrees == 1) return Double.POSITIVE_INFINITY; else return Math.exp(c + (0.5 * nDegrees - 1) * Math.log(x) - 0.5 * (nDegrees + dDegrees) * Math.log(1 + nDegrees * x / dDegrees)); } /**This method computes the maximum value of the getDensity function*/ public double getMaxDensity(){ double mode; if (nDegrees == 1) mode = getDomain().getLowerValue(); else mode = (double)((nDegrees - 2) * dDegrees) / (nDegrees * (dDegrees + 2)); return getDensity(mode); } /**This method returns the mean*/ public double getMean(){ if (dDegrees <= 2) return Double.POSITIVE_INFINITY; else return (double)dDegrees / (dDegrees - 2); } /**This method returns the variance*/ public double getVariance(){ if (dDegrees <= 2) return Double.NaN; else if (dDegrees <= 4) return Double.POSITIVE_INFINITY; else return 2.0 * (dDegrees / (dDegrees - 2)) * (dDegrees / (dDegrees - 2)) * (dDegrees + nDegrees - 2) / (nDegrees * (dDegrees - 4)); } /**This method computes the cumulative distribution function in terms of the beta CDF*/ public double getCDF(double x){ double u = dDegrees / (dDegrees + nDegrees * x); if (x < 0) return 0; else return 1 - betaCDF(u, 0.5 * dDegrees, 0.5 * nDegrees); } /**This method returns the numerator degrees of freedom*/ public double getNDegrees(){ return nDegrees; } /**This method sets the numerator degrees of freedom*/ public void setNDegrees(int n){ setParameters(n, dDegrees); } /**This method gets the denominator degrees of freedom*/ public double getDDegrees(){ return dDegrees; } /**This method sets the denominator degrees of freedom*/ public void setDDegrees(int d){ setParameters(nDegrees, d); } /**This method simulates a value from the distribution*/ public double simulate(){ double U, V, Z, r, theta; U = 0; for (int i = 1; i <= dDegrees; i++){ r = Math.sqrt(-2 * Math.log(Math.random())); theta = 2 * Math.PI * Math.random(); Z = r * Math.cos(theta); U = U + Z * Z; } V = 0; for (int j = 1; j <= dDegrees; j++){ r = Math.sqrt(-2 * Math.log(Math.random())); theta = 2 * Math.PI * Math.random(); Z = r * Math.cos(theta); V = V + Z * Z; } return (U / nDegrees) / (V / dDegrees); } }