Implement some more transformation functions using code from Jason
authorBen Pfaff <blp@gnu.org>
Wed, 9 Mar 2005 18:02:15 +0000 (18:02 +0000)
committerBen Pfaff <blp@gnu.org>
Wed, 9 Mar 2005 18:02:15 +0000 (18:02 +0000)
Stover.  Thanks Jason!

20 files changed:
configure.ac
lib/ChangeLog
lib/Makefile.am
lib/gsl-extras/Makefile.am [new file with mode: 0644]
lib/gsl-extras/betadistinv.c [new file with mode: 0644]
lib/gsl-extras/binomial.c [new file with mode: 0644]
lib/gsl-extras/geometric.c [new file with mode: 0644]
lib/gsl-extras/gsl-extras.h [new file with mode: 0644]
lib/gsl-extras/hypergeometric.c [new file with mode: 0644]
lib/gsl-extras/negbinom.c [new file with mode: 0644]
lib/gsl-extras/poisson.c [new file with mode: 0644]
po/en_GB.po
po/pspp.pot
src/ChangeLog
src/Makefile.am
src/expressions/helpers.c
src/expressions/helpers.h
src/expressions/operations.def
tests/expressions/randist/beta.out
tests/expressions/randist/f.out

index 69836f9599a09e14ae4b8645cf05f381cfd26f4e..542b453aa4a31b5e074e5c79f4c4a3a965870afd 100644 (file)
@@ -149,7 +149,7 @@ if test x"$enable_debug" = x"yes"  ; then
 fi
 
 AC_CONFIG_FILES([Makefile po/Makefile.in m4/Makefile 
 fi
 
 AC_CONFIG_FILES([Makefile po/Makefile.in m4/Makefile 
-                lib/Makefile lib/misc/Makefile 
+                lib/Makefile lib/misc/Makefile lib/gsl-extras/Makefile
                 doc/Makefile 
                 src/Makefile src/expressions/Makefile
                 config/Makefile
                 doc/Makefile 
                 src/Makefile src/expressions/Makefile
                 config/Makefile
index 505a5fb8e6fa471cdc1bf349ce1b636b2706933b..7406ab0b3186aeab95079110718bab0b44751f0d 100644 (file)
@@ -1,3 +1,9 @@
+Wed Mar  9 09:53:50 2005  Ben Pfaff  <blp@gnu.org>
+
+       * gsl-extras/: New directory.
+
+       * Makefile.am: (SUBDIRS) Add gsl-extras.
+
 Mon Feb 28 23:20:05 2005  Ben Pfaff  <blp@gnu.org>
 
        * julcal/: Removed directory.
 Mon Feb 28 23:20:05 2005  Ben Pfaff  <blp@gnu.org>
 
        * julcal/: Removed directory.
index bae615ac20a6c4c9f368896934517a04d84793ac..f50e789594de748b20fc66d15350949e7eaf7aae 100644 (file)
@@ -1,5 +1,5 @@
 ## Process this file with automake to produce Makefile.in  -*- makefile -*-
 
 ## Process this file with automake to produce Makefile.in  -*- makefile -*-
 
-SUBDIRS = misc 
+SUBDIRS = misc gsl-extras
 
 MAINTAINERCLEANFILES = Makefile.in
 
 MAINTAINERCLEANFILES = Makefile.in
diff --git a/lib/gsl-extras/Makefile.am b/lib/gsl-extras/Makefile.am
new file mode 100644 (file)
index 0000000..82b61ef
--- /dev/null
@@ -0,0 +1,16 @@
+## Process this file with automake to produce Makefile.in  -*- makefile -*-
+
+noinst_LIBRARIES = libgsl-extras.a
+
+AM_CPPFLAGS = -I$(top_srcdir)
+
+AM_CFLAGS=
+
+if cc_is_gcc
+AM_CFLAGS+=-Wall -W -Wwrite-strings -Wstrict-prototypes \
+-Wpointer-arith -Wno-sign-compare -Wmissing-prototypes \
+-ansi 
+endif
+
+libgsl_extras_a_SOURCES = betadistinv.c binomial.c geometric.c \
+hypergeometric.c negbinom.c poisson.c gsl-extras.h
diff --git a/lib/gsl-extras/betadistinv.c b/lib/gsl-extras/betadistinv.c
new file mode 100644 (file)
index 0000000..a0838d2
--- /dev/null
@@ -0,0 +1,659 @@
+/* cdf/betadistinv.c
+ *
+ * Copyright (C) 2004 Jason H. Stover.
+ *
+ * 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.
+ */
+
+/*
+ * Invert the Beta distribution. 
+ * 
+ * References:
+ *
+ * Roger W. Abernathy and Robert P. Smith. "Applying Series Expansion 
+ * to the Inverse Beta Distribution to Find Percentiles of the F-Distribution,"
+ * ACM Transactions on Mathematical Software, volume 19, number 4, December 1993,
+ * pages 474-480.
+ *
+ * G.W. Hill and A.W. Davis. "Generalized asymptotic expansions of a 
+ * Cornish-Fisher type," Annals of Mathematical Statistics, volume 39, number 8,
+ * August 1968, pages 1264-1273.
+ */
+#include <config.h>
+#include <math.h>
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_errno.h>
+#include <gsl/gsl_sf_gamma.h>
+#include <gsl/gsl_cdf.h>
+#include <gsl/gsl_randist.h>
+#include "gsl-extras.h"
+
+#define BETAINV_INIT_ERR .01
+#define BETADISTINV_N_TERMS 3
+#define BETADISTINV_MAXITER 20
+
+static double 
+s_bisect (double x, double y)
+{
+  double result = GSL_MIN(x,y) + fabs(x - y) / 2.0;
+  return result;
+}
+static double
+new_guess_P ( double old_guess, double x, double y, 
+             double prob, double a, double b)
+{
+  double result;
+  double p_hat;
+  double end_point;
+  
+  p_hat = gsl_cdf_beta_P(old_guess, a, b);
+  if (p_hat < prob)
+    {
+      end_point = GSL_MAX(x,y);
+    }
+  else if ( p_hat > prob )
+    {
+      end_point = GSL_MIN(x,y);
+    }
+  else
+    {
+      end_point = old_guess;
+    }
+  result = s_bisect(old_guess, end_point);
+  
+  return result;
+}
+
+static double
+new_guess_Q ( double old_guess, double x, double y, 
+             double prob, double a, double b)
+{
+  double result;
+  double q_hat;
+  double end_point;
+  
+  q_hat = gsl_cdf_beta_Q(old_guess, a, b);
+  if (q_hat >= prob)
+    {
+      end_point = GSL_MAX(x,y);
+    }
+  else if ( q_hat < prob )
+    {
+      end_point = GSL_MIN(x,y);
+    }
+  else
+    {
+      end_point = old_guess;
+    }
+  result = s_bisect(old_guess, end_point);
+  
+  return result;
+}
+
+/*
+ * The get_corn_fish_* functions below return the first
+ * three terms of the Cornish-Fisher expansion
+ * without recursion. The recursive functions
+ * make the code more legible when higher order coefficients
+ * are used, but terms beyond the cubic do not 
+ * improve accuracy.
+ */
+  /*
+   * Linear coefficient for the 
+   * Cornish-Fisher expansion.
+   */
+static double 
+get_corn_fish_lin (const double x, const double a, const double b)
+{
+  double result;
+  
+  result = gsl_ran_beta_pdf (x, a, b);
+  if(result > 0)
+    {
+      result = 1.0 / result;
+    }
+  else
+    {
+      result = GSL_DBL_MAX;
+    }
+
+  return result;
+}
+  /*
+   * Quadratic coefficient for the 
+   * Cornish-Fisher expansion.
+   */
+static double
+get_corn_fish_quad (const double x, const double a, const double b)
+{
+  double result;
+  double gam_ab;
+  double gam_a;
+  double gam_b;
+  double num;
+  double den;
+  
+  gam_ab =  gsl_sf_lngamma(a + b);
+  gam_a = gsl_sf_lngamma (a);
+  gam_b = gsl_sf_lngamma (b);
+  num = exp(2 * (gam_a + gam_b - gam_ab)) * (1 - a + x * (b + a - 2));
+  den = 2.0 * pow ( x, 2*a - 1 ) * pow ( 1 - x, 2 * b - 1 );
+  if ( fabs(den) > 0.0)
+    {
+      result = num / den;
+    }
+  else
+    {
+      result = 0.0;
+    }
+
+  return result;
+}
+/*
+ * The cubic term for the Cornish-Fisher expansion.
+ * Theoretically, use of this term should give a better approximation, 
+ * but in practice inclusion of the cubic term worsens the 
+ * iterative procedure in gsl_cdf_beta_Pinv and gsl_cdf_beta_Qinv
+ * for extreme values of p, a or b.
+ */                                
+#if 0
+static double 
+get_corn_fish_cube (const double x, const double a, const double b)
+{
+  double result;
+  double am1 = a - 1.0;
+  double am2 = a - 2.0;
+  double apbm2 = a+b-2.0;
+  double apbm3 = a+b-3.0;
+  double apbm4 = a+b-4.0;
+  double ab1ab2 = am1 * am2;
+  double tmp;
+  double num;
+  double den;
+
+  num =  (am1 - x * apbm2) * (am1 - x * apbm2);
+  tmp = ab1ab2 - x * (apbm2 * ( ab1ab2 * apbm4 + 1) + x * apbm2 * apbm3);
+  num += tmp;
+  tmp = gsl_ran_beta_pdf(x,a,b);
+  den = 2.0 * x * x * (1 - x) * (1 - x) * pow(tmp,3.0);
+  if ( fabs(den) > 0.0)
+    {
+      result = num / den;
+    }
+  else
+    {
+      result = 0.0;
+    }
+
+  return result;
+}
+#endif
+/*
+ * The Cornish-Fisher coefficients can be defined recursivley,
+ * starting with the nth derivative of s_psi = -f'(x)/f(x),
+ * where f is the beta density.
+ *
+ * The section below was commented out since 
+ * the recursive generation of the coeficients did
+ * not improve the accuracy of the directly coded 
+ * the first three coefficients.
+ */
+#if 0
+static double
+s_d_psi (double x, double a, double b, int n)
+{
+  double result;
+  double np1 = (double) n + 1;
+  double asgn;
+  double bsgn;
+  double bm1 = b - 1.0;
+  double am1 = a - 1.0;
+  double mx = 1.0 - x;
+  
+  asgn = (n % 2) ? 1.0:-1.0;
+  bsgn = (n % 2) ? -1.0:1.0;
+  result = gsl_sf_gamma(np1) * ((bsgn * bm1 / (pow(mx, np1)))
+                               + (asgn * am1 / (pow(x,np1))));
+  return result;
+}
+/*
+ * nth derivative of a coefficient with respect 
+ * to x.
+ */
+static double 
+get_d_coeff ( double x, double a, 
+             double b, double n, double k)
+{
+  double result;
+  double d_psi;
+  double k_fac;
+  double i_fac;
+  double kmi_fac;
+  double i;
+  
+  if (n == 2)
+    {
+      result = s_d_psi(x, a, b, k);
+    }
+  else
+    {
+      result = 0.0;
+      for (i = 0.0; i < (k+1); i++)
+       {
+         k_fac = gsl_sf_lngamma(k+1.0);
+         i_fac = gsl_sf_lngamma(i+1.0);
+         kmi_fac = gsl_sf_lngamma(k-i+1.0);
+         
+         result += exp(k_fac - i_fac - kmi_fac)
+           * get_d_coeff( x, a, b, 2.0, i) 
+           * get_d_coeff( x, a, b, (n - 1.0), (k - i));
+       }
+      result += get_d_coeff ( x, a, b, (n-1.0), (k+1.0));
+    }
+
+  return result;
+}
+/*
+ * Cornish-Fisher coefficient.
+ */
+static double
+get_corn_fish (double c, double x, 
+              double a, double b, double n)
+{
+  double result;
+  double dc;
+  double c_prev;
+  
+  if(n == 1.0)
+    {
+      result = 1;
+    }
+  else if (n==2.0)
+    {
+      result = s_d_psi(x, a, b, 0);
+    }
+  else
+    {
+      dc = get_d_coeff(x, a, b, (n-1.0), 1.0);
+      c_prev = get_corn_fish(c, x, a, b, (n-1.0));
+      result = (n-1) * s_d_psi(x,a,b,0) * c_prev + dc;
+    }
+  return result;
+}
+#endif
+
+double 
+gslextras_cdf_beta_Pinv ( const double p, const double a, const double b)
+{
+  double result;
+  double state;
+  double beta_result;
+  double lower = 0.0;
+  double upper = 1.0;
+  double c1;
+  double c2;
+#if 0
+  double c3;
+#endif
+  double frac1;
+  double frac2;
+  double frac3;
+  double frac4;
+  double p0;
+  double p1;
+  double p2;
+  double tmp;
+  double err;
+  double abserr;
+  double relerr;
+  double min_err;
+  int n_iter = 0;
+
+  if ( p < 0.0 )
+    {
+      GSLEXTRAS_CDF_ERROR("p < 0", GSL_EDOM);
+    }
+  if ( p > 1.0 )
+    {
+      GSLEXTRAS_CDF_ERROR("p > 1",GSL_EDOM);
+    }
+  if ( a < 0.0 )
+    {
+      GSLEXTRAS_CDF_ERROR ("a < 0", GSL_EDOM );
+    }
+  if ( b < 0.0 )
+    {
+      GSLEXTRAS_CDF_ERROR ( "b < 0", GSL_EDOM );
+    }
+  if ( p == 0.0 )
+    {
+      return 0.0;
+    }
+  if ( p == 1.0 )
+    {
+      return 1.0;
+    }
+
+  if (p > (1.0 - GSL_DBL_EPSILON))
+    {
+      /*
+       * When p is close to 1.0, the bisection
+       * works better with gsl_cdf_Q.
+       */
+      state = gslextras_cdf_beta_Qinv ( p, a, b);
+      result = 1.0 - state;
+      return result;
+    }
+  if (p < GSL_DBL_EPSILON )
+    {
+      /*
+       * Start at a small value and rise until
+       * we are above the correct result. This 
+       * avoids overflow. When p is very close to 
+       * 0, an initial state value of a/(a+b) will
+       * cause the interpolating polynomial
+       * to overflow.
+       */
+      upper = GSL_DBL_MIN;
+      beta_result = gsl_cdf_beta_P (upper, a, b);
+      while (beta_result < p)
+       {
+         lower = upper;
+         upper *= 4.0;
+         beta_result = gsl_cdf_beta_P (upper, a, b);
+       }
+      state = (lower + upper) / 2.0;
+    }
+  else
+    {
+      /*
+       * First guess is the expected value.
+       */
+      lower = 0.0;
+      upper = 1.0;
+      state = a/(a+b);
+      beta_result = gsl_cdf_beta_P (state, a, b);
+    }
+  err = beta_result - p;
+  abserr = fabs(err);
+  relerr = abserr / p;
+  while ( relerr > BETAINV_INIT_ERR && n_iter < 100)
+    {
+      tmp = new_guess_P ( state, lower, upper, 
+                         p, a, b);
+      lower = ( tmp < state ) ? lower:state;
+      upper = ( tmp < state ) ? state:upper;
+      state = tmp;
+      beta_result = gsl_cdf_beta_P (state, a, b);
+      err = p - beta_result;
+      abserr = fabs(err);
+      relerr = abserr / p;
+    }
+
+  result = state;
+  min_err = relerr;
+  /*
+   * Use a second order Lagrange interpolating
+   * polynomial to get closer before switching to
+   * the iterative method.
+   */
+  p0 = gsl_cdf_beta_P (lower, a, b);
+  p1 = gsl_cdf_beta_P (state, a, b);
+  p2 = gsl_cdf_beta_P (upper, a, b);
+  if( p0 < p1 && p1 < p2)
+    {
+      frac1 = (p - p2) / (p0 - p1);
+      frac2 = (p - p1) / (p0 - p2);
+      frac3 = (p - p0) / (p1 - p2);
+      frac4 = (p - p0) * (p - p1) / ((p2 - p0) * (p2 - p1));
+      state = frac1 * (frac2 * lower - frac3 * state)
+       + frac4 * upper;
+
+      beta_result = gsl_cdf_beta_P( state, a, b);
+      err = p - beta_result;
+      abserr = fabs(err);
+      relerr = abserr / p;
+      if (relerr < min_err)
+       {
+         result = state;
+         min_err = relerr;
+       }
+    }
+
+  n_iter = 0;
+
+  /*
+   * Newton-type iteration using the terms from the
+   * Cornish-Fisher expansion. If only the first term
+   * of the expansion is used, this is Newton's method.
+   */
+  while ( relerr > GSL_DBL_EPSILON && n_iter < BETADISTINV_MAXITER)
+    {
+      n_iter++;
+      c1 = get_corn_fish_lin (state, a, b);
+      c2 = get_corn_fish_quad (state, a, b);
+      /*
+       * The cubic term does not help, and can can
+       * harm the approximation for extreme values of
+       * p, a, or b.       
+       */      
+#if 0
+      c3 = get_corn_fish_cube (state, a, b);
+      state += err * (c1 + (err / 2.0 ) * (c2 + c3 * err / 3.0));
+#endif
+      state += err * (c1 + (c2 * err / 2.0 ));
+      /*
+       * The section below which is commented out uses
+       * a recursive function to get the coefficients. 
+       * The recursion makes coding higher-order terms
+       * easier, but did not improve the result beyond
+       * the use of three terms. Since explicitly coding
+       * those three terms in the get_corn_fish_* functions
+       * was not difficult, the recursion was abandoned.
+       */
+#if 0 
+      coeff = 1.0;
+      for(i = 1.0; i < BETADISTINV_N_TERMS; i += 1.0)
+       {
+         i_fac *= i;
+         coeff = get_corn_fish (coeff, prior_state, a, b, i);
+         state += coeff * pow(err, i) / 
+           (i_fac * pow (gsl_ran_beta_pdf(prior_state,a,b), i));
+       }
+#endif
+      beta_result = gsl_cdf_beta_P ( state, a, b );
+      err = p - beta_result;
+      abserr = fabs(err);
+      relerr = abserr / p;
+      if (relerr < min_err)
+       {
+         result = state;
+         min_err = relerr;
+       }
+    }
+
+  return result;
+}
+
+double
+gslextras_cdf_beta_Qinv (double q, double a, double b)
+{
+  double result;
+  double state;
+  double beta_result;
+  double lower = 0.0;
+  double upper = 1.0;
+  double c1;
+  double c2;
+#if 0
+  double c3;
+#endif
+  double p0;
+  double p1;
+  double p2;
+  double frac1;
+  double frac2;
+  double frac3;
+  double frac4;
+  double tmp;
+  double err;
+  double abserr;
+  double relerr;
+  double min_err;
+  int n_iter = 0;
+
+  if ( q < 0.0 )
+    {
+      GSLEXTRAS_CDF_ERROR("q < 0", GSL_EDOM);
+    }
+  if ( q > 1.0 )
+    {
+      GSLEXTRAS_CDF_ERROR("q > 1",GSL_EDOM);
+    }
+  if ( a < 0.0 )
+    {
+      GSLEXTRAS_CDF_ERROR ("a < 0", GSL_EDOM );
+    }
+  if ( b < 0.0 )
+    {
+      GSLEXTRAS_CDF_ERROR ( "b < 0", GSL_EDOM );
+    }
+  if ( q == 0.0 )
+    {
+      return 1.0;
+    }
+  if ( q == 1.0 )
+    {
+      return 0.0;
+    }
+
+  if ( q < GSL_DBL_EPSILON )
+    {
+      /*
+       * When q is close to 0, the bisection
+       * and interpolation done in the rest of
+       * this routine will not give the correct
+       * value within double precision, so 
+       * gsl_cdf_beta_Qinv is called instead.
+       */
+      state = gslextras_cdf_beta_Pinv ( q, a, b);
+      result = 1.0 - state;
+      return result;
+    }
+  if ( q > 1.0 - GSL_DBL_EPSILON )
+    {
+      /*
+       * Make the initial guess close to 0.0.
+       */
+      upper = GSL_DBL_MIN;
+      beta_result = gsl_cdf_beta_Q ( upper, a, b);
+      while (beta_result > q )
+       {
+         lower = upper;
+         upper *= 4.0;
+         beta_result = gsl_cdf_beta_Q ( upper, a, b);
+       }
+      state = (upper + lower) / 2.0;
+    }
+  else
+    {
+      /* Bisection to get an initial approximation.
+       * First guess is the expected value.
+       */
+      state = a/(a+b);
+      lower = 0.0;
+      upper = 1.0;
+    }
+  beta_result = gsl_cdf_beta_Q (state, a, b);
+  err = beta_result - q;
+  abserr = fabs(err);
+  relerr = abserr / q;
+  while ( relerr > BETAINV_INIT_ERR && n_iter < 100)
+    {
+      n_iter++;
+      tmp = new_guess_Q ( state, lower, upper, 
+                         q, a, b);
+      lower = ( tmp < state ) ? lower:state;
+      upper = ( tmp < state ) ? state:upper;
+      state = tmp;
+      beta_result = gsl_cdf_beta_Q (state, a, b);
+      err = q - beta_result;
+      abserr = fabs(err);
+      relerr = abserr / q;
+    }
+  result = state;
+  min_err = relerr;
+
+  /*
+   * Use a second order Lagrange interpolating
+   * polynomial to get closer before switching to
+   * the iterative method.
+   */
+  p0 = gsl_cdf_beta_Q (lower, a, b);
+  p1 = gsl_cdf_beta_Q (state, a, b);
+  p2 = gsl_cdf_beta_Q (upper, a, b);
+  if(p0 > p1 && p1 > p2)
+    {
+      frac1 = (q - p2) / (p0 - p1);
+      frac2 = (q - p1) / (p0 - p2);
+      frac3 = (q - p0) / (p1 - p2);
+      frac4 = (q - p0) * (q - p1) / ((p2 - p0) * (p2 - p1));
+      state = frac1 * (frac2 * lower - frac3 * state)
+       + frac4 * upper;
+      beta_result = gsl_cdf_beta_Q( state, a, b);
+      err = beta_result - q;
+      abserr = fabs(err);
+      relerr = abserr / q;
+      if (relerr < min_err)
+       {
+         result = state;
+         min_err = relerr;
+       }
+    }
+
+  /*
+   * Iteration using the terms from the
+   * Cornish-Fisher expansion. If only the first term
+   * of the expansion is used, this is Newton's method.
+   */
+
+  n_iter = 0;
+  while ( relerr > GSL_DBL_EPSILON && n_iter < BETADISTINV_MAXITER)
+    {
+      n_iter++;
+      c1 = get_corn_fish_lin (state, a, b);
+      c2 = get_corn_fish_quad (state, a, b);
+      /*
+       * The cubic term does not help, and can harm
+       * the approximation for extreme values of p, a and b.
+       */
+#if 0
+      c3 = get_corn_fish_cube (state, a, b);
+      state += err * (c1 + (err / 2.0 ) * (c2 + c3 * err / 3.0));
+#endif
+      state += err * (c1 + (c2 * err / 2.0 ));
+      beta_result = gsl_cdf_beta_Q ( state, a, b );
+      err = beta_result - q;
+      abserr = fabs(err);
+      relerr = abserr / q;
+      if (relerr < min_err)
+       {
+         result = state;
+         min_err = relerr;
+       }
+    }
+
+  return result;
+}
diff --git a/lib/gsl-extras/binomial.c b/lib/gsl-extras/binomial.c
new file mode 100644 (file)
index 0000000..a85f4a3
--- /dev/null
@@ -0,0 +1,98 @@
+/* cdf/binomial.c
+ *
+ * Copyright (C) 2004 Jason H. Stover.
+ *
+ * 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.
+ */
+
+/*
+ * Computes the cumulative distribution function for a binomial
+ * random variable. For a binomial random variable X with n trials
+ * and success probability p,
+ *
+ *          Pr( X <= k ) = Pr( Y >= p )
+ *
+ * where Y is a beta random variable with parameters k+1 and n-k.
+ *
+ * Reference: 
+ * 
+ * W. Feller, "An Introduction to Probability and Its
+ * Applications," volume 1. Wiley, 1968. Exercise 45, page 173,
+ * chapter 6.
+ */
+#include <config.h>
+#include <math.h>
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_errno.h>
+#include <gsl/gsl_cdf.h>
+#include "gsl-extras.h"
+
+double
+gslextras_cdf_binomial_P(const long k, const long n, const double p)
+{
+  double P;
+  double a;
+  double b;
+
+  if(p > 1.0 || p < 0.0)
+    {
+      GSLEXTRAS_CDF_ERROR("p < 0 or p > 1",GSL_EDOM);
+    }
+  if ( k >= n )
+    {
+      P = 1.0;
+    }
+  else if (k < 0)
+    {
+      P = 0.0;
+    }
+  else
+    {
+      a = (double) k+1;
+      b = (double) n - k;
+      P = gsl_cdf_beta_Q( p, a, b);
+    }
+  
+  return P;
+}
+double
+gslextras_cdf_binomial_Q(const long k, const long n, const double q)
+{
+  double P;
+  double a;
+  double b;
+
+  if(q > 1.0 || q < 0.0)
+    {
+      GSLEXTRAS_CDF_ERROR("p < 0 or p > 1",GSL_EDOM);
+    }
+  if( k >= n )
+    {
+      P = 0.0;
+    }
+  else if ( k < 0 )
+    {
+      P = 1.0;
+    }
+  else
+    {
+      a = (double) k+1;
+      b = (double) n - k;
+      P = gsl_cdf_beta_P(q, a, b);
+    }
+
+  return P;
+}
+
diff --git a/lib/gsl-extras/geometric.c b/lib/gsl-extras/geometric.c
new file mode 100644 (file)
index 0000000..4612fad
--- /dev/null
@@ -0,0 +1,105 @@
+/* cdf/geometric.c
+ *
+ * Copyright (C) 2004 Jason H. Stover.
+ *
+ * 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.
+ */
+
+/*
+ * Pr(X <= n) for a negative binomial random variable X, i.e.,
+ * the probability of n or fewer failuers before success k.
+ */
+
+#include <config.h>
+#include <math.h>
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_errno.h>
+#include <gsl/gsl_sf.h>
+#include <gsl/gsl_cdf.h>
+#include "gsl-extras.h"
+
+/*
+ * Pr (X <= n), i.e., the probability of n or fewer
+ * failures until the first success.
+ */
+double
+gslextras_cdf_geometric_P (const long n, const double p)
+{
+  double P;
+  double a;
+  int i;
+  int m;
+  double sign = 1.0;
+  double term;
+  double q;
+
+  if(p > 1.0 || p < 0.0)
+    {
+      GSLEXTRAS_CDF_ERROR("p < 0 or p > 1",GSL_EDOM);
+    }
+  if ( n < 0 )
+    {
+      return 0.0;
+    }
+  q = 1.0 - p;
+  a = (double) n+1;
+  if( p < GSL_DBL_EPSILON )
+    {
+      /*
+       * 1.0 - pow(q,a) will overflow, so use
+       * a Taylor series.
+       */
+      i = 2;
+      m = n+1;
+      term = exp(log(a) + log(p));
+      P = term;
+      while ( term > GSL_DBL_MIN && i < m)
+       {
+         term = exp (sign * gsl_sf_lnchoose(m,i) + i * log(p));
+         P += term;
+         i++;
+         sign = -sign;
+       }
+    }
+  else
+    {
+      P = 1.0 - pow ( q, a);
+    }
+  return P;
+}
+double
+gslextras_cdf_geometric_Q ( const long n, const double p)
+{
+  double P;
+  double q;
+  double a;
+
+  if(p > 1.0 || p < 0.0)
+    {
+      GSLEXTRAS_CDF_ERROR("p < 0 or p > 1",GSL_EDOM);
+    }
+  if ( n < 0 )
+    {
+      P = 1.0;
+    }
+  else
+    {
+      a = (double) n+1;
+      q = 1.0 - p;
+      P = pow(q, a);
+    }
+
+  return P;
+}
diff --git a/lib/gsl-extras/gsl-extras.h b/lib/gsl-extras/gsl-extras.h
new file mode 100644 (file)
index 0000000..5d2f6d8
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef GSL_EXTRAS_H
+#define GSL_EXTRAS_H
+
+/* GSLEXTRAS_CDF_ERROR: call the error handler, and return a NAN. */
+#define GSLEXTRAS_CDF_ERROR(reason, gsl_errno) \
+       do { \
+       gsl_error (reason, __FILE__, __LINE__, gsl_errno) ; \
+       return GSL_NAN ; \
+       } while (0)
+
+double gslextras_cdf_beta_Pinv (const double p, const double a,
+                                const double b);
+double gslextras_cdf_beta_Qinv (double q, double a, double b);
+double gslextras_cdf_binomial_P(const long k, const long n, const double p);
+double gslextras_cdf_binomial_Q(const long k, const long n, const double q);
+double gslextras_cdf_geometric_P (const long n, const double p);
+double gslextras_cdf_geometric_Q ( const long n, const double p);
+double gslextras_cdf_hypergeometric_P (const unsigned int k, 
+                                       const unsigned int n0,
+                                       const unsigned int n1,
+                                       const unsigned int t);
+double gslextras_cdf_hypergeometric_Q (const unsigned int k, 
+                                       const unsigned int n0,
+                                       const unsigned int n1,
+                                       const unsigned int t);
+double gslextras_cdf_negative_binomial_P(const long n,
+                                         const long k, const double p);
+double gslextras_cdf_negative_binomial_Q(const long n, const long k,
+                                         const double p);
+double gslextras_cdf_poisson_P (const long k, const double lambda);
+double gslextras_cdf_poisson_Q (const long k, const double lambda);
+
+#endif /* gsl-extras.h */
diff --git a/lib/gsl-extras/hypergeometric.c b/lib/gsl-extras/hypergeometric.c
new file mode 100644 (file)
index 0000000..5e4d181
--- /dev/null
@@ -0,0 +1,195 @@
+/* cdf/hypergeometric.c
+ *
+ * Copyright (C) 2004 Jason H. Stover.
+ *
+ * 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.
+ */
+
+/*
+ * Computes the cumulative distribution function for a hypergeometric
+ * random variable. A hypergeometric random variable X is the number
+ * of elements of type 0 in a sample of size t, drawn from a population
+ * of size n1 + n0, in which n1 are of type 1 and n0 are of type 0.
+ *
+ * This algorithm computes Pr( X <= k ) by summing the terms from
+ * the mass function, Pr( X = k ).
+ *
+ * References:
+ *
+ * T. Wu. An accurate computation of the hypergeometric distribution 
+ * function. ACM Transactions on Mathematical Software. Volume 19, number 1,
+ * March 1993.
+ *  This algorithm is not used, since it requires factoring the
+ *  numerator and denominator, then cancelling. It is more accurate
+ *  than the algorithm used here, but the cancellation requires more
+ *  time than the algorithm used here.
+ *
+ * W. Feller. An Introduction to Probability Theory and Its Applications,
+ * third edition. 1968. Chapter 2, section 6. 
+ */
+#include <config.h>
+#include <math.h>
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_errno.h>
+#include <gsl/gsl_cdf.h>
+#include <gsl/gsl_randist.h>
+#include "gsl-extras.h"
+
+/*
+ * Pr (X <= k)
+ */
+double
+gslextras_cdf_hypergeometric_P (const unsigned int k, 
+                                const unsigned int n0,
+                                const unsigned int n1,
+                                const unsigned int t)
+{
+  unsigned int i;
+  unsigned int mode;
+  double P;
+  double tmp;
+  double relerr;
+
+  if( t > (n0+n1))
+    {
+      GSLEXTRAS_CDF_ERROR("t larger than population size",GSL_EDOM);
+    }
+  else if( k >= n0 || k >= t)
+    {
+      P = 1.0;
+    }
+  else if (k < 0.0)
+    {
+      P = 0.0;
+    }
+  else
+    {
+      P = 0.0;
+      mode = (int) t*n0 / (n0+n1);
+      relerr = 1.0;
+      if( k < mode )
+       {
+         i = k;
+         relerr = 1.0;
+         while(i != UINT_MAX && relerr > GSL_DBL_EPSILON && P < 1.0)
+           {
+             tmp = gsl_ran_hypergeometric_pdf(i, n0, n1, t);
+             P += tmp;
+             relerr = tmp / P;
+             i--;
+           }
+       }
+      else
+       {
+         i = mode;
+         relerr = 1.0;
+         while(i <= k && relerr > GSL_DBL_EPSILON && P < 1.0)
+           {
+             tmp = gsl_ran_hypergeometric_pdf(i, n0, n1, t);
+             P += tmp;
+             relerr = tmp / P;
+             i++;
+           }
+         i = mode - 1;
+         relerr = 1.0;
+         while( i != UINT_MAX && relerr > GSL_DBL_EPSILON && P < 1.0)
+           {
+             tmp = gsl_ran_hypergeometric_pdf(i, n0, n1, t);
+             P += tmp;
+             relerr = tmp / P;
+             i--;
+           }
+       }
+      /*
+       * Hack to get rid of a pesky error when the sum
+       * gets slightly above 1.0.
+       */
+      P = GSL_MIN_DBL (P, 1.0);
+    }
+  return P;
+}
+
+/*
+ * Pr (X > k)
+ */
+double
+gslextras_cdf_hypergeometric_Q (const unsigned int k, 
+                                const unsigned int n0,
+                                const unsigned int n1,
+                                const unsigned int t)
+{
+  unsigned int i;
+  unsigned int mode;
+  double P;
+  double relerr;
+  double tmp;
+
+  if( t > (n0+n1))
+    {
+      GSLEXTRAS_CDF_ERROR("t larger than population size",GSL_EDOM);
+    }
+  else if( k >= n0 || k >= t)
+    {
+      P = 0.0;
+    }
+  else if (k < 0.0)
+    {
+      P = 1.0;
+    }
+  else
+    {
+      P = 0.0;
+      mode = (int) t*n0 / (n0+n1);
+      relerr = 1.0;
+      
+      if(k < mode)
+       {
+         i = mode;
+         while( i <= t && relerr > GSL_DBL_EPSILON && P < 1.0)
+           {
+             tmp = gsl_ran_hypergeometric_pdf(i, n0, n1, t);
+             P += tmp;
+             relerr = tmp / P;
+             i++;
+           }
+         i = mode - 1;
+         relerr = 1.0;
+         while ( i > k && relerr > GSL_DBL_EPSILON && P < 1.0)
+           {
+             tmp = gsl_ran_hypergeometric_pdf(i, n0, n1, t);
+             P += tmp;
+             relerr = tmp / P;
+             i--;
+           }
+       }
+      else
+       {
+         i = k+1;
+         while(i <= t && relerr > GSL_DBL_EPSILON && P < 1.0)
+           {
+             tmp = gsl_ran_hypergeometric_pdf(i, n0, n1, t);
+             P += tmp;
+             relerr = tmp / P;
+             i++;
+           }
+       }
+      /*
+       * Hack to get rid of a pesky error when the sum
+       * gets slightly above 1.0.
+       */
+      P = GSL_MIN_DBL(P, 1.0);
+    }
+  return P;
+}
diff --git a/lib/gsl-extras/negbinom.c b/lib/gsl-extras/negbinom.c
new file mode 100644 (file)
index 0000000..0fc4689
--- /dev/null
@@ -0,0 +1,91 @@
+/* cdf/negbinom.c
+ *
+ * Copyright (C) 2004 Jason H. Stover.
+ *
+ * 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.
+ */
+
+
+#include <config.h>
+#include <math.h>
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_errno.h>
+#include <gsl/gsl_cdf.h>
+#include "gsl-extras.h"
+
+/*
+ * Pr(X <= n) for a negative binomial random variable X, i.e.,
+ * the probability of n or fewer failuers before success k.
+ */
+double
+gslextras_cdf_negative_binomial_P(const long n, const long k, const double p)
+{
+  double P;
+  double a;
+  double b;
+
+  if(p > 1.0 || p < 0.0)
+    {
+      GSLEXTRAS_CDF_ERROR("p < 0 or p > 1",GSL_EDOM);
+    }
+  if ( k < 0 )
+    {
+      GSLEXTRAS_CDF_ERROR ("k < 0",GSL_EDOM);
+    }
+  if ( n < 0 )
+    {
+      P = 0.0;
+    }
+  else
+    {
+      a = (double) k;
+      b = (double) n+1;
+      P = gsl_cdf_beta_P(p, a, b);
+    }
+
+  return P;
+}
+/*
+ * Pr ( X > n ).
+ */
+double
+gslextras_cdf_negative_binomial_Q(const long n, const long k, const double p)
+{
+  double P;
+  double a;
+  double b;
+
+  if(p > 1.0 || p < 0.0)
+    {
+      GSLEXTRAS_CDF_ERROR("p < 0 or p > 1",GSL_EDOM);
+    }
+  if ( k < 0 )
+    {
+      GSLEXTRAS_CDF_ERROR ("k < 0",GSL_EDOM);
+    }
+  if ( n < 0 )
+    {
+      P = 1.0;
+    }
+  else
+    {
+      a = (double) k;
+      b = (double) n+1;
+      P = gsl_cdf_beta_Q(p, a, b);
+    }
+
+  return P;
+}
+
diff --git a/lib/gsl-extras/poisson.c b/lib/gsl-extras/poisson.c
new file mode 100644 (file)
index 0000000..fffa993
--- /dev/null
@@ -0,0 +1,91 @@
+/* cdf/poisson.c
+ *
+ * Copyright (C) 2004 Jason H. Stover.
+ *
+ * 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.
+ */
+/*
+ * Computes the cumulative distribution function for a Poisson
+ * random variable. For a Poisson random variable X with parameter
+ * lambda,
+ *
+ *          Pr( X <= k ) = Pr( Y >= p )
+ *
+ * where Y is a gamma random variable with parameters k+1 and 1.
+ *
+ * Reference: 
+ * 
+ * W. Feller, "An Introduction to Probability and Its
+ * Applications," volume 1. Wiley, 1968. Exercise 46, page 173,
+ * chapter 6.
+ */
+#include <config.h>
+#include <math.h>
+#include <gsl/gsl_math.h>
+#include <gsl/gsl_errno.h>
+#include <gsl/gsl_cdf.h>
+#include "gsl-extras.h"
+#include "gsl-extras.h"
+
+/*
+ * Pr (X <= k) for a Poisson random variable X.
+ */
+double
+gslextras_cdf_poisson_P (const long k, const double lambda)
+{
+  double P;
+  double a;
+  
+  if ( lambda <= 0.0 )
+    {
+      GSLEXTRAS_CDF_ERROR ("lambda <= 0", GSL_EDOM);
+    }
+  if ( k < 0 )
+    {
+      P = 0.0;
+    }
+  else
+    {
+      a = (double) k+1;
+      P = gsl_cdf_gamma_Q ( lambda, a, 1.0);
+    }
+  return P;
+}
+
+/*
+ * Pr ( X > k ) for a Possion random variable X.
+ */
+double
+gslextras_cdf_poisson_Q (const long k, const double lambda)
+{
+  double P;
+  double a;
+  
+  if ( lambda <= 0.0 )
+    {
+      GSLEXTRAS_CDF_ERROR ("lambda <= 0", GSL_EDOM);
+    }
+  if ( k < 0 )
+    {
+      P = 1.0;
+    }
+  else
+    {
+      a = (double) k+1;
+      P = gsl_cdf_gamma_P ( lambda, a, 1.0);
+    }
+  return P;
+}
+
index 3e2113465d720c729d6dc27763aa216b1ba88142..7ac7cab5f7c1251be08ac0fb5aa469b26cc36aac 100644 (file)
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PSPP 0.3.1\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
 msgstr ""
 "Project-Id-Version: PSPP 0.3.1\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2005-03-08 12:50+0800\n"
+"POT-Creation-Date: 2005-03-09 09:46-0800\n"
 "PO-Revision-Date: 2004-01-23 13:04+0800\n"
 "Last-Translator: John Darrington <john@darrington.wattle.id.au>\n"
 "Language-Team: John Darrington <john@darrington.wattle.id.au>\n"
 "PO-Revision-Date: 2004-01-23 13:04+0800\n"
 "Last-Translator: John Darrington <john@darrington.wattle.id.au>\n"
 "Language-Team: John Darrington <john@darrington.wattle.id.au>\n"
@@ -1209,25 +1209,6 @@ msgstr ""
 msgid "installation error"
 msgstr ""
 
 msgid "installation error"
 msgstr ""
 
-#: src/filename.c:221
-#, c-format
-msgid "Searching for `%s'..."
-msgstr ""
-
-#: src/filename.c:229 src/filename.c:261
-msgid "Search unsuccessful!"
-msgstr ""
-
-#: src/filename.c:254
-#, c-format
-msgid "Found `%s'."
-msgstr ""
-
-#: src/filename.c:686
-#, c-format
-msgid "Not opening pipe file `%s' because SAFER option set."
-msgstr ""
-
 #: src/file-type.c:129
 msgid "MIXED, GROUPED, or NESTED expected."
 msgstr ""
 #: src/file-type.c:129
 msgid "MIXED, GROUPED, or NESTED expected."
 msgstr ""
@@ -1366,6 +1347,25 @@ msgstr ""
 msgid "Unknown record type %g."
 msgstr ""
 
 msgid "Unknown record type %g."
 msgstr ""
 
+#: src/filename.c:221
+#, c-format
+msgid "Searching for `%s'..."
+msgstr ""
+
+#: src/filename.c:229 src/filename.c:261
+msgid "Search unsuccessful!"
+msgstr ""
+
+#: src/filename.c:254
+#, c-format
+msgid "Found `%s'."
+msgstr ""
+
+#: src/filename.c:686
+#, c-format
+msgid "Not opening pipe file `%s' because SAFER option set."
+msgstr ""
+
 #: src/flip.c:81
 msgid ""
 "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
 #: src/flip.c:81
 msgid ""
 "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
index c67a0aa8e68e074c11f503526e29603318f31db8..cc19a3dca3268cc8c810b455e85b0ec29ef058d6 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2005-03-08 12:50+0800\n"
+"POT-Creation-Date: 2005-03-09 09:46-0800\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -1210,25 +1210,6 @@ msgstr ""
 msgid "installation error"
 msgstr ""
 
 msgid "installation error"
 msgstr ""
 
-#: src/filename.c:221
-#, c-format
-msgid "Searching for `%s'..."
-msgstr ""
-
-#: src/filename.c:229 src/filename.c:261
-msgid "Search unsuccessful!"
-msgstr ""
-
-#: src/filename.c:254
-#, c-format
-msgid "Found `%s'."
-msgstr ""
-
-#: src/filename.c:686
-#, c-format
-msgid "Not opening pipe file `%s' because SAFER option set."
-msgstr ""
-
 #: src/file-type.c:129
 msgid "MIXED, GROUPED, or NESTED expected."
 msgstr ""
 #: src/file-type.c:129
 msgid "MIXED, GROUPED, or NESTED expected."
 msgstr ""
@@ -1367,6 +1348,25 @@ msgstr ""
 msgid "Unknown record type %g."
 msgstr ""
 
 msgid "Unknown record type %g."
 msgstr ""
 
+#: src/filename.c:221
+#, c-format
+msgid "Searching for `%s'..."
+msgstr ""
+
+#: src/filename.c:229 src/filename.c:261
+msgid "Search unsuccessful!"
+msgstr ""
+
+#: src/filename.c:254
+#, c-format
+msgid "Found `%s'."
+msgstr ""
+
+#: src/filename.c:686
+#, c-format
+msgid "Not opening pipe file `%s' because SAFER option set."
+msgstr ""
+
 #: src/flip.c:81
 msgid ""
 "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
 #: src/flip.c:81
 msgid ""
 "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
index 4cdd2acb109484c647f563e1904e107f96159905..a0eb80bb225945e4551faeb92d41f366c79a9033 100644 (file)
@@ -1,3 +1,17 @@
+Wed Mar  9 09:54:27 2005  Ben Pfaff  <blp@gnu.org>
+
+       * Makefile.am: (pspp_LDADD) Add libgsl-extras.a.
+
+       * expressions/helpers.c: (struct func_params) Removed.
+       (generalized_idf) Removed.
+       (cdf_beta) Removed.
+       (idf_beta) Removed.
+       (idf_fdist) Use gslextras_cdf_beta_Pinv() instead of idf_beta().
+
+       * expressions/operations.def: Implement IDF.BETA, CDF.BINOM,
+       CDF.GEOM, CDF.HYPER, CDF.NEGBIN, CDF.POISSON using gsl-extras.
+       Implement SIG.F, which I had overlooked previously.
+
 Tue Mar  8 12:47:53 WST 2005 John Darrington <john@darrington.wattle.id.au>
 
        * command.c command.def glob.[ch] cmdline.c: Made DEBUG cmds
 Tue Mar  8 12:47:53 WST 2005 John Darrington <john@darrington.wattle.id.au>
 
        * command.c command.def glob.[ch] cmdline.c: Made DEBUG cmds
@@ -64,22 +78,23 @@ Sun Mar  6 17:07:20 2005  Ben Pfaff  <blp@gnu.org>
 
 Sun Mar  6 22:09:20 2005  Ben Pfaff  <blp@gnu.org>
 
 
 Sun Mar  6 22:09:20 2005  Ben Pfaff  <blp@gnu.org>
 
-       * operations.def: (NUMBER) Use DI_IMPLIED_DECIMALS.
+       * expressions/operations.def: (NUMBER) Use DI_IMPLIED_DECIMALS.
 
 Sun Mar  6 19:33:24 2005  Ben Pfaff  <blp@gnu.org>
 
 
 Sun Mar  6 19:33:24 2005  Ben Pfaff  <blp@gnu.org>
 
-       * operations.def: (VEC_ELEM_NUM) Treat user-missing values as
-       system-missing.
+       * expressions/operations.def: (VEC_ELEM_NUM) Treat user-missing
+       values as system-missing.
 
 
-       * parse.c: (parse_vector_element) Fix order of arguments in call
-       to expr_allocate_binary().
+       * expressions/parse.c: (parse_vector_element) Fix order of
+       arguments in call to expr_allocate_binary().
 
 Sun Mar  6 17:51:05 2005  Ben Pfaff  <blp@gnu.org>
 
 
 Sun Mar  6 17:51:05 2005  Ben Pfaff  <blp@gnu.org>
 
-       * optimize.c: (optimize_tree) Fix optimization bug for x**2.
+       * expressions/optimize.c: (optimize_tree) Fix optimization bug for
+       x**2.
 
 
-       * parse.c: (type_coercion_core) Set *node to NULL on failure, as
-       indicated by function comment.
+       * expressions/parse.c: (type_coercion_core) Set *node to NULL on
+       failure, as indicated by function comment.
        (parse_binary_operators) Always return NULL on type_coercion()
        failure.  Should have been doing this anyway, but bug in
        type_coercion_core() filtered through.
        (parse_binary_operators) Always return NULL on type_coercion()
        failure.  Should have been doing this anyway, but bug in
        type_coercion_core() filtered through.
@@ -88,29 +103,31 @@ Sun Mar  6 17:51:05 2005  Ben Pfaff  <blp@gnu.org>
 
 Sun Mar  6 10:47:13 2005  Ben Pfaff  <blp@gnu.org>
 
 
 Sun Mar  6 10:47:13 2005  Ben Pfaff  <blp@gnu.org>
 
-       * operations.def: Add VALUE function.
+       * expressions/operations.def: Add VALUE function.
 
 
-       * parse.c: (parse_function) Need an unary composite node for
-       variables in A TO B, not a variable node.  Use
+       * expressions/parse.c: (parse_function) Need an unary composite
+       node for variables in A TO B, not a variable node.  Use
        allocate_unary_variable().
        (parse_primary) Use allocate_unary_variable().
        (allocate_unary_variable) New function.
 
 Thu Mar  3 23:53:32 2005  Ben Pfaff  <blp@gnu.org>
 
        allocate_unary_variable().
        (parse_primary) Use allocate_unary_variable().
        (allocate_unary_variable) New function.
 
 Thu Mar  3 23:53:32 2005  Ben Pfaff  <blp@gnu.org>
 
-       * PSPP_expressions.pm: Renamed it back to generate.pl but fixed
-       the real problem that was preventing the build from a separate
-       directory.  I liked it my way better ;-)
+       * expressions/PSPP_expressions.pm: Renamed it back to generate.pl
+       but fixed the real problem that was preventing the build from a
+       separate directory.  I liked it my way better ;-)
        
 Thu Mar  3 23:17:51 2005  Ben Pfaff  <blp@gnu.org>
 
        
 Thu Mar  3 23:17:51 2005  Ben Pfaff  <blp@gnu.org>
 
-       * parse.c: (expr_parse) Fix parameter type.  Thanks to John
-       Darrington <john@darrington.wattle.id.au> for reporting this bug.
+       * expressions/parse.c: (expr_parse) Fix parameter type.  Thanks to
+       John Darrington <john@darrington.wattle.id.au> for reporting this
+       bug.
 
 Thu Mar  3 22:10:25 WST 2005 John Darrington <john@darrington.wattle.id.au>
 
 
 Thu Mar  3 22:10:25 WST 2005 John Darrington <john@darrington.wattle.id.au>
 
-       * Makefile.am evaluate.h.pl evaluate.inc.pl operations.h.pl
-         optimize.inc.pl parse.inc.p:  
+       * expressions/Makefile.am expressions/evaluate.h.pl
+         expressions/evaluate.inc.pl expressions/operations.h.pl
+         expressions/optimize.inc.pl expressions/parse.inc.p:
 
          Renamed generate.pl to PSPP_expressions.pm and adjusted *.pl
          to suit. 
 
          Renamed generate.pl to PSPP_expressions.pm and adjusted *.pl
          to suit. 
index 1dac4987485ca6f1c91cddf8a6d1f0948f8c9f1d..6f03ed9115be0292c2ee2c65c6becc857a86a3bc 100644 (file)
@@ -76,6 +76,7 @@ vfm.c vfm.h vfmP.h weight.c
 pspp_LDADD = \
        ../lib/misc/libmisc.a                   \
        expressions/libexpressions.a            \
 pspp_LDADD = \
        ../lib/misc/libmisc.a                   \
        expressions/libexpressions.a            \
+       ../lib/gsl-extras/libgsl-extras.a       \
        -lplot \
        @LIBINTL@
 
        -lplot \
        @LIBINTL@
 
index 879b95f493035755e40163752190158814ad12db..58c4a0361be81529b60d8b7a14ef4e3cba2ab581 100644 (file)
@@ -165,84 +165,6 @@ copy_string (struct expression *e, const char *old, size_t length)
   return s;
 }
 
   return s;
 }
 
-struct func_params 
-  {
-    double Ptarget;
-    double a;
-    double b;
-  };
-
-static double
-generalized_idf (double P, double a, double b, double (*cdf) (double, void *)) 
-{
-  struct func_params params;
-  gsl_function f;
-  gsl_root_fsolver *fsolver;
-  int iter;
-  int status;
-  double root;
-
-  if (P < 0 || P > 1)
-    return SYSMIS;
-
-  params.Ptarget = P;
-  params.a = a;
-  params.b = b;
-  
-  f.function = cdf;
-  f.params = &params;
-
-  fsolver = gsl_root_fsolver_alloc (gsl_root_fsolver_brent);
-  gsl_root_fsolver_set (fsolver, &f, 0, 1);
-
-  iter = 0;
-  do 
-    {
-      double x_lower, x_upper;
-      
-      status = gsl_root_fsolver_iterate (fsolver);
-      if (status != 0)
-        return SYSMIS;
-
-      x_lower = gsl_root_fsolver_x_lower (fsolver);
-      x_upper = gsl_root_fsolver_x_upper (fsolver);
-      status = gsl_root_test_interval (x_lower, x_upper, 0, 2 * DBL_EPSILON);
-    }
-  while (status == GSL_CONTINUE && ++iter < 100);
-
-  root = gsl_root_fsolver_root (fsolver);
-  gsl_root_fsolver_free (fsolver);
-  return root;
-}
-
-static double
-cdf_beta (double x, void *params_) 
-{
-  struct func_params *params = params_;
-
-  return gsl_cdf_beta_P (x, params->a, params->b) - params->Ptarget;
-}
-
-double
-idf_beta (double P, double a, double b) 
-{
-#if 1
-  return generalized_idf (P, a, b, cdf_beta);
-#else
-  double x = a / (a + b);
-  double dx = 1.;
-  while (fabs (dx) > 2 * DBL_EPSILON) 
-    {
-      dx = (gsl_sf_beta_inc (a, b, x) - P) / gsl_ran_beta_pdf (x, a, b);
-      x -= dx;
-      if (x < 0)
-        x += (dx - x) / 2;
-    }
-
-  return x;
-#endif
-}
-
 /* Returns the noncentral beta cumulative distribution function
    value for the given arguments.
 
 /* Returns the noncentral beta cumulative distribution function
    value for the given arguments.
 
@@ -390,7 +312,7 @@ cdf_bvnor (double x0, double x1, double r)
 double
 idf_fdist (double P, double df1, double df2) 
 {
 double
 idf_fdist (double P, double df1, double df2) 
 {
-  double temp = idf_beta (P, df1 / 2, df2 / 2);
+  double temp = gslextras_cdf_beta_Pinv (P, df1 / 2, df2 / 2);
   return temp * df2 / ((1. - temp) * df1);
 }
 
   return temp * df2 / ((1. - temp) * df1);
 }
 
index 32e01dd3a3aa75d04a8d9c5801b0f2861b4e299a..6e51fdf4aefaf98ffb09e989034169eccad8bdb3 100644 (file)
@@ -14,6 +14,7 @@
 #include "dictionary.h"
 #include "error.h"
 #include "calendar.h"
 #include "dictionary.h"
 #include "error.h"
 #include "calendar.h"
+#include "gsl-extras/gsl-extras.h"
 #include "misc.h"
 #include "moments.h"
 #include "settings.h"
 #include "misc.h"
 #include "moments.h"
 #include "settings.h"
index e1998266154f263b4c96032f60c78485d14f359d..0d21c16a65e10bf06229fb115fc794f2d3d03118 100644 (file)
@@ -617,7 +617,8 @@ operator BOOLEAN_TO_NUM (boolean x) = x;
 function PDF.BETA (x >= 0 && x <= 1, a > 0, b > 0)
      = gsl_ran_beta_pdf (x, a, b);
 function CDF.BETA (x >= 0 && x <= 1, a > 0, b > 0) = gsl_cdf_beta_P (x, a, b);
 function PDF.BETA (x >= 0 && x <= 1, a > 0, b > 0)
      = gsl_ran_beta_pdf (x, a, b);
 function CDF.BETA (x >= 0 && x <= 1, a > 0, b > 0) = gsl_cdf_beta_P (x, a, b);
-function IDF.BETA (P >= 0 && P <= 1, a > 0, b > 0) = idf_beta (P, a, b);
+function IDF.BETA (P >= 0 && P <= 1, a > 0, b > 0)
+     = gslextras_cdf_beta_Pinv (P, a, b);
 no_opt function RV.BETA (a > 0, b > 0) = gsl_ran_beta (get_rng (), a, b);
 function NCDF.BETA (x >= 0, a > 0, b > 0, lambda > 0)
      = ncdf_beta (x, a, b, lambda);
 no_opt function RV.BETA (a > 0, b > 0) = gsl_ran_beta (get_rng (), a, b);
 function NCDF.BETA (x >= 0, a > 0, b > 0, lambda > 0)
      = ncdf_beta (x, a, b, lambda);
@@ -665,7 +666,7 @@ function PDF.F (x >= 0, df1 > 0, df2 > 0) = gsl_ran_fdist_pdf (x, df1, df2);
 no_opt function RV.F (df1 > 0, df2 > 0) = gsl_ran_fdist (get_rng (), df1, df2);
 function NCDF.F (x >= 0, df1 > 0, df2 > 0, lambda >= 0) = unimplemented;
 function NPDF.F (x >= 0, df1 > 0, df2 > 0, lmabda >= 0) = unimplemented;
 no_opt function RV.F (df1 > 0, df2 > 0) = gsl_ran_fdist (get_rng (), df1, df2);
 function NCDF.F (x >= 0, df1 > 0, df2 > 0, lambda >= 0) = unimplemented;
 function NPDF.F (x >= 0, df1 > 0, df2 > 0, lmabda >= 0) = unimplemented;
-function SIG.F (x >= 0, df1 > 0, df2 > 0) = unimplemented;
+function SIG.F (x >= 0, df1 > 0, df2 > 0) = gsl_cdf_fdist_Q (x, df1, df2);
 
 // Gamma distribution.
 function CDF.GAMMA (x >= 0, a > 0, b > 0) = gsl_cdf_gamma_P (x, a, 1. / b);
 
 // Gamma distribution.
 function CDF.GAMMA (x >= 0, a > 0, b > 0) = gsl_cdf_gamma_P (x, a, 1. / b);
@@ -820,7 +821,7 @@ no_opt function RV.BERNOULLI (p >= 0 && p <= 1)
 
 // Binomial distribution.
 function CDF.BINOM (k, n > 0 && n == floor (n), p >= 0 && p <= 1)
 
 // Binomial distribution.
 function CDF.BINOM (k, n > 0 && n == floor (n), p >= 0 && p <= 1)
-     = unimplemented;
+     = gslextras_cdf_binomial_P (k, p, n);
 function PDF.BINOM (k >= 0 && k == floor (k) && k <= n,
                     n > 0 && n == floor (n),
                     p >= 0 && p <= 1)
 function PDF.BINOM (k >= 0 && k == floor (k) && k <= n,
                     n > 0 && n == floor (n),
                     p >= 0 && p <= 1)
@@ -829,7 +830,8 @@ no_opt function RV.BINOM (p > 0 && p == floor (p), n >= 0 && n <= 1)
      = gsl_ran_binomial (get_rng (), p, n);
 
 // Geometric distribution.
      = gsl_ran_binomial (get_rng (), p, n);
 
 // Geometric distribution.
-function CDF.GEOM (k >= 1 && k == floor (k), p >= 0 && p <= 1) = unimplemented;
+function CDF.GEOM (k >= 1 && k == floor (k), p >= 0 && p <= 1)
+     = gslextras_cdf_geometric_P (k, p);
 function PDF.GEOM (k >= 1 && k == floor (k),
                    p >= 0 && p <= 1)
      = gsl_ran_geometric_pdf (k, p);
 function PDF.GEOM (k >= 1 && k == floor (k),
                    p >= 0 && p <= 1)
      = gsl_ran_geometric_pdf (k, p);
@@ -840,7 +842,7 @@ function CDF.HYPER (k >= 0 && k == floor (k) && k <= c,
                     a > 0 && a == floor (a),
                     b > 0 && b == floor (b) && b <= a,
                     c > 0 && c == floor (c) && c <= a)
                     a > 0 && a == floor (a),
                     b > 0 && b == floor (b) && b <= a,
                     c > 0 && c == floor (c) && c <= a)
-     = unimplemented;
+     = gslextras_cdf_hypergeometric_P (k, c, a - c, b);
 function PDF.HYPER (k >= 0 && k == floor (k) && k <= c,
                     a > 0 && a == floor (a),
                     b > 0 && b == floor (b) && b <= a,
 function PDF.HYPER (k >= 0 && k == floor (k) && k <= c,
                     a > 0 && a == floor (a),
                     b > 0 && b == floor (b) && b <= a,
@@ -858,14 +860,16 @@ no_opt extension function RV.LOG (p > 0 && p <= 1)
      = gsl_ran_logarithmic (get_rng (), p);
 
 // Negative binomial distribution.
      = gsl_ran_logarithmic (get_rng (), p);
 
 // Negative binomial distribution.
-function CDF.NEGBIN (k >= 1, n == floor (n), p > 0 && p <= 1) = unimplemented;
+function CDF.NEGBIN (k >= 1, n == floor (n), p > 0 && p <= 1)
+     = gslextras_cdf_negative_binomial_P (k, p, n);
 function PDF.NEGBIN (k >= 1, n == floor (n), p > 0 && p <= 1)
      = gsl_ran_negative_binomial_pdf (k, p, n);
 no_opt function RV.NEGBIN (n == floor (n), p > 0 && p <= 1) 
      = gsl_ran_negative_binomial (get_rng (), p, n);
 
 // Poisson distribution.
 function PDF.NEGBIN (k >= 1, n == floor (n), p > 0 && p <= 1)
      = gsl_ran_negative_binomial_pdf (k, p, n);
 no_opt function RV.NEGBIN (n == floor (n), p > 0 && p <= 1) 
      = gsl_ran_negative_binomial (get_rng (), p, n);
 
 // Poisson distribution.
-function CDF.POISSON (k >= 0 && k == floor (k), mu > 0) = unimplemented;
+function CDF.POISSON (k >= 0 && k == floor (k), mu > 0)
+     = gslextras_cdf_poisson_P (k, mu);
 function PDF.POISSON (k >= 0 && k == floor (k), mu > 0)
      = gsl_ran_poisson_pdf (k, mu);
 no_opt function RV.POISSON (mu > 0) = gsl_ran_poisson (get_rng (), mu);
 function PDF.POISSON (k >= 0 && k == floor (k), mu > 0)
      = gsl_ran_poisson_pdf (k, mu);
 no_opt function RV.POISSON (mu > 0) = gsl_ran_poisson (get_rng (), mu);
index ea138295dc13ad851790931594efd91229b18b7b..e19d5f1ec61bd68ad63b6853bc29ce34642d4a69 100644 (file)
      .90     1.50     2.00      .76      .90      .79 
      .90     1.50     2.50      .68      .90      .75 
      .90     1.50     3.00      .62      .90      .74 
      .90     1.50     2.00      .76      .90      .79 
      .90     1.50     2.50      .68      .90      .75 
      .90     1.50     3.00      .62      .90      .74 
-     .99      .75      .25     1.00      .99 164255.7 
+     .99      .75      .25     1.00      .98 20860.76 
      .99      .75      .50     1.00      .99    34.83 
      .99      .75     1.00      .99      .99      .75 
      .99      .75     1.50      .94      .99      .26 
      .99      .75     2.00      .88      .99      .17 
      .99      .75     2.50      .81      .99      .13 
      .99      .75     3.00      .75      .99      .12 
      .99      .75      .50     1.00      .99    34.83 
      .99      .75     1.00      .99      .99      .75 
      .99      .75     1.50      .94      .99      .26 
      .99      .75     2.00      .88      .99      .17 
      .99      .75     2.50      .81      .99      .13 
      .99      .75     3.00      .75      .99      .12 
-     .99     1.00      .25     1.00      .99 250000.
+     .99     1.00      .25     1.00      .98 46067.0
      .99     1.00      .50     1.00      .99    50.00 
      .99     1.00     1.00      .99      .99     1.00 
      .99     1.00     1.50      .95      .99      .32 
      .99     1.00     2.00      .90      .99      .20 
      .99     1.00     2.50      .84      .99      .16 
      .99     1.00     3.00      .78      .99      .14 
      .99     1.00      .50     1.00      .99    50.00 
      .99     1.00     1.00      .99      .99     1.00 
      .99     1.00     1.50      .95      .99      .32 
      .99     1.00     2.00      .90      .99      .20 
      .99     1.00     2.50      .84      .99      .16 
      .99     1.00     3.00      .78      .99      .14 
-     .99     1.50      .25     1.00      .99 428406.6 
+     .99     1.50      .25     1.00      .98 67836.74 
      .99     1.50      .50     1.00      .99    81.05 
      .99     1.50     1.00      .99      .99     1.49 
      .99     1.50     1.50      .97      .99      .45 
      .99     1.50      .50     1.00      .99    81.05 
      .99     1.50     1.00      .99      .99     1.49 
      .99     1.50     1.50      .97      .99      .45 
index ab76a257c36074c1f2848242d714a159733a4681..2e014815dced6e2736b27bc2f437d8f9680bf0a9 100644 (file)
      .99     5.00     1.00  5763.65      .99      .00 
      .99     5.00     2.00    99.30      .99      .00 
      .99     5.00     5.00    10.97      .99      .00 
      .99     5.00     1.00  5763.65      .99      .00 
      .99     5.00     2.00    99.30      .99      .00 
      .99     5.00     5.00    10.97      .99      .00 
-     .99     5.00    10.00     5.64      .99      .01 
+     .99     5.00    10.00    10.00     1.00      .00 
      .99    10.00     1.00  6055.85      .99      .00 
      .99    10.00     2.00    99.40      .99      .00 
      .99    10.00     5.00    10.05      .99      .00 
      .99    10.00     1.00  6055.85      .99      .00 
      .99    10.00     2.00    99.40      .99      .00 
      .99    10.00     5.00    10.05      .99      .00