Blame randist/exppow.c

Packit 67cb25
/* randist/exppow.c
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2006, 2007 James Theiler, Brian Gough
Packit 67cb25
 * Copyright (C) 2006 Giulio Bottazzi
Packit 67cb25
 * 
Packit 67cb25
 * This program is free software; you can redistribute it and/or modify
Packit 67cb25
 * it under the terms of the GNU General Public License as published by
Packit 67cb25
 * the Free Software Foundation; either version 3 of the License, or (at
Packit 67cb25
 * your option) any later version.
Packit 67cb25
 * 
Packit 67cb25
 * This program is distributed in the hope that it will be useful, but
Packit 67cb25
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 67cb25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 67cb25
 * General Public License for more details.
Packit 67cb25
 * 
Packit 67cb25
 * You should have received a copy of the GNU General Public License
Packit 67cb25
 * along with this program; if not, write to the Free Software
Packit 67cb25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
#include <config.h>
Packit 67cb25
#include <math.h>
Packit 67cb25
#include <gsl/gsl_math.h>
Packit 67cb25
#include <gsl/gsl_sf_gamma.h>
Packit 67cb25
#include <gsl/gsl_rng.h>
Packit 67cb25
#include <gsl/gsl_randist.h>
Packit 67cb25
Packit 67cb25
/* The exponential power probability distribution is  
Packit 67cb25
Packit 67cb25
   p(x) dx = (1/(2 a Gamma(1+1/b))) * exp(-|x/a|^b) dx
Packit 67cb25
Packit 67cb25
   for -infty < x < infty. For b = 1 it reduces to the Laplace
Packit 67cb25
   distribution. 
Packit 67cb25
Packit 67cb25
   The exponential power distribution is related to the gamma
Packit 67cb25
   distribution by E = a * pow(G(1/b),1/b), where E is an exponential
Packit 67cb25
   power variate and G is a gamma variate.
Packit 67cb25
Packit 67cb25
   We use this relation for b < 1. For b >=1 we use rejection methods
Packit 67cb25
   based on the laplace and gaussian distributions which should be
Packit 67cb25
   faster.  For b>4 we revert to the gamma method.
Packit 67cb25
Packit 67cb25
   See P. R. Tadikamalla, "Random Sampling from the Exponential Power
Packit 67cb25
   Distribution", Journal of the American Statistical Association,
Packit 67cb25
   September 1980, Volume 75, Number 371, pages 683-686.
Packit 67cb25
   
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
double
Packit 67cb25
gsl_ran_exppow (const gsl_rng * r, const double a, const double b)
Packit 67cb25
{
Packit 67cb25
  if (b < 1 || b > 4)
Packit 67cb25
    {
Packit 67cb25
      double u = gsl_rng_uniform (r);
Packit 67cb25
      double v = gsl_ran_gamma (r, 1 / b, 1.0);
Packit 67cb25
      double z = a * pow (v, 1 / b);
Packit 67cb25
Packit 67cb25
      if (u > 0.5)
Packit 67cb25
        {
Packit 67cb25
          return z;
Packit 67cb25
        }
Packit 67cb25
      else
Packit 67cb25
        {
Packit 67cb25
          return -z;
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
  else if (b == 1)
Packit 67cb25
    {
Packit 67cb25
      /* Laplace distribution */
Packit 67cb25
      return gsl_ran_laplace (r, a);
Packit 67cb25
    }
Packit 67cb25
  else if (b < 2)
Packit 67cb25
    {
Packit 67cb25
      /* Use laplace distribution for rejection method, from Tadikamalla */
Packit 67cb25
Packit 67cb25
      double x, h, u;
Packit 67cb25
Packit 67cb25
      double B = pow (1 / b, 1 / b);
Packit 67cb25
Packit 67cb25
      do
Packit 67cb25
        {
Packit 67cb25
          x = gsl_ran_laplace (r, B);
Packit 67cb25
          u = gsl_rng_uniform_pos (r);
Packit 67cb25
          h = -pow (fabs (x), b) + fabs (x) / B - 1 + (1 / b);
Packit 67cb25
        }
Packit 67cb25
      while (log (u) > h);
Packit 67cb25
Packit 67cb25
      return a * x;
Packit 67cb25
    }
Packit 67cb25
  else if (b == 2)
Packit 67cb25
    {
Packit 67cb25
      /* Gaussian distribution */
Packit 67cb25
      return gsl_ran_gaussian (r, a / sqrt (2.0));
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      /* Use gaussian for rejection method, from Tadikamalla */
Packit 67cb25
Packit 67cb25
      double x, h, u;
Packit 67cb25
Packit 67cb25
      double B = pow (1 / b, 1 / b);
Packit 67cb25
Packit 67cb25
      do
Packit 67cb25
        {
Packit 67cb25
          x = gsl_ran_gaussian (r, B);
Packit 67cb25
          u = gsl_rng_uniform_pos (r);
Packit 67cb25
          h = -pow (fabs (x), b) + (x * x) / (2 * B * B) + (1 / b) - 0.5;
Packit 67cb25
        }
Packit 67cb25
      while (log (u) > h);
Packit 67cb25
Packit 67cb25
      return a * x;
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
double
Packit 67cb25
gsl_ran_exppow_pdf (const double x, const double a, const double b)
Packit 67cb25
{
Packit 67cb25
  double p;
Packit 67cb25
  double lngamma = gsl_sf_lngamma (1 + 1 / b);
Packit 67cb25
  p = (1 / (2 * a)) * exp (-pow (fabs (x / a), b) - lngamma);
Packit 67cb25
  return p;
Packit 67cb25
}