randvar.c

来自「General Hidden Markov Model Library 一个通用」· C语言 代码 · 共 942 行 · 第 1/2 页

C
942
字号
/*********************************************************************************       This file is part of the General Hidden Markov Model Library,*       GHMM version 0.8_beta1, see http://ghmm.org**       Filename: ghmm/ghmm/randvar.c*       Authors:  Bernhard Knab, Benjamin Rich, Janne Grunau**       Copyright (C) 1998-2004 Alexander Schliep*       Copyright (C) 1998-2001 ZAIK/ZPR, Universitaet zu Koeln*       Copyright (C) 2002-2004 Max-Planck-Institut fuer Molekulare Genetik,*                               Berlin**       Contact: schliep@ghmm.org**       This library is free software; you can redistribute it and/or*       modify it under the terms of the GNU Library General Public*       License as published by the Free Software Foundation; either*       version 2 of the License, or (at your option) any later version.**       This library 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*       Library General Public License for more details.**       You should have received a copy of the GNU Library General Public*       License along with this library; if not, write to the Free*       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA***       This file is version $Revision: 1650 $*                       from $Date: 2006-07-20 17:57:27 +0200 (Thu, 20 Jul 2006) $*             last change by $Author: grunau $.********************************************************************************/#ifdef WIN32#  include "win_config.h"#endif#ifdef HAVE_CONFIG_H#  include "../config.h"#endif#include <math.h>#include <float.h>#include <string.h>#ifdef HAVE_LIBPTHREAD# include <pthread.h>#endif /* HAVE_LIBPTHREAD */#include "ghmm.h"#include "mes.h"#include "mprintf.h"#include "randvar.h"#include "rng.h"#ifdef DO_WITH_GSL# include <gsl/gsl_math.h># include <gsl/gsl_sf_erf.h># include <gsl/gsl_randist.h>#endif /* DO_WITH_GSL */#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)#elsestatic double ighmm_erf (double x);static double ighmm_erfc (double x);#endif /* check for ISO C99 *//* A list of already calculated values of the density function of a    N(0,1)-distribution, with x in [0.00, 19.99] */#define PDFLEN 2000#define X_STEP_PDF 0.01         /* step size */#define X_FAKT_PDF 100          /* equivalent to step size */static double pdf_stdnormal[PDFLEN];static int pdf_stdnormal_exists = 0;/* A list of already calulated values PHI of the Gauss distribution is   read in, x in [-9.999, 0] */#define X_STEP_PHI 0.001        /* step size */#define X_FAKT_PHI 1000         /* equivalent to step size */static int PHI_len = 0;static double x_PHI_1 = -1.0;#ifndef M_SQRT1_2#define M_SQRT1_2  0.70710678118654752440084436210#endif/*============================================================================*//* needed by ighmm_gtail_pmue_interpol */double ighmm_rand_get_xfaktphi (){  return X_FAKT_PHI;}double ighmm_rand_get_xstepphi (){  return X_STEP_PHI;}double ighmm_rand_get_philen (){#ifdef DO_WITH_GSL  return PHI_len;#else  return ighmm_rand_get_xPHIless1 () / X_STEP_PHI;#endif}/*============================================================================*/double ighmm_rand_get_PHI (double x){#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)  return (erf (x * M_SQRT1_2) + 1.0) / 2.0;#else  return (ighmm_erf (x * M_SQRT1_2) + 1.0) / 2.0;#endif}                               /* randvar_get_PHI *//*============================================================================*//* When is PHI[x,0,1] == 1? */double ighmm_rand_get_xPHIless1 (){# define CUR_PROC "ighmm_rand_get_xPHIless1"  if (x_PHI_1 == -1) {    double low, up, half;    low = 0;    up = 100;    while (up - low > 0.001) {      half = (low + up) / 2.0;      if (ighmm_rand_get_PHI (half) < 1.0)        low = half;      else        up = half;    }    x_PHI_1 = low;  }  return (x_PHI_1);# undef CUR_PROC}/*============================================================================*/double ighmm_rand_get_1overa (double x, double mean, double u){  /* Calulates 1/a(x, mean, u), with a = the integral from x til \infty over     the Gauss density function */# define CUR_PROC "ighmm_rand_get_1overa"  double erfc_value;  if (u <= 0.0) {    GHMM_LOG(LCONVERTED, "u <= 0.0 not allowed\n");    goto STOP;  }#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)  erfc_value = erfc ((x - mean) / sqrt (u * 2));#else  erfc_value = ighmm_erfc ((x - mean) / sqrt (u * 2));#endif  if (erfc_value <= DBL_MIN) {    ighmm_mes (MES_WIN, "a ~= 0.0 critical! (mue = %.2f, u =%.2f)\n", mean, u);    return (erfc_value);  }  else    return (2.0 / erfc_value);STOP:  return (-1.0);# undef CUR_PROC}                               /* ighmm_rand_get_1overa *//*============================================================================*//* REMARK:   The calulation of this density function was testet, by calculating the    following integral sum for arbitrary mue and u:     for (x = 0, x < ..., x += step(=0.01/0.001/0.0001))        isum += step * ighmm_rand_normal_density_pos(x, mue, u);   In each case, the sum "converged" evidently towards 1!   (BK, 14.6.99)   CHANGE:   Truncate at -EPS_NDT (const.h), so that x = 0 doesn't lead to a problem.   (BK, 15.3.2000)*/double ighmm_rand_normal_density_pos (double x, double mean, double u){# define CUR_PROC "ighmm_rand_normal_density_pos"  return ighmm_rand_normal_density_trunc (x, mean, u, -GHMM_EPS_NDT);# undef CUR_PROC}                               /* double ighmm_rand_normal_density_pos *//*============================================================================*/double ighmm_rand_normal_density_trunc (double x, double mean, double u,                                     double a){# define CUR_PROC "ighmm_rand_normal_density_trunc"#ifndef DO_WITH_GSL  double c;#endif /* DO_WITH_GSL */  if (u <= 0.0) {    GHMM_LOG(LCONVERTED, "u <= 0.0 not allowed\n");    goto STOP;  }  if (x < a)    return (0.0);#ifdef DO_WITH_GSL  /* move mean to the right position */  /* double gsl_ran_gaussian_tail_pdf (double x, double a, double sigma) */  return gsl_ran_gaussian_tail_pdf (x - mean, a - mean, sqrt (u));#else  if ((c = ighmm_rand_get_1overa (a, mean, u)) == -1) {    GHMM_LOG_QUEUED(LCONVERTED);    goto STOP;  };  return (c * ighmm_rand_normal_density (x, mean, u));#endif /* DO_WITH_GSL */STOP:  return (-1.0);# undef CUR_PROC}                               /* double ighmm_rand_normal_density_trunc *//*============================================================================*/double ighmm_rand_normal_density (double x, double mean, double u){# define CUR_PROC "ighmm_rand_normal_density"#ifndef DO_WITH_GSL  double expo;#endif  if (u <= 0.0) {    GHMM_LOG(LCONVERTED, "u <= 0.0 not allowed\n");    goto STOP;  }  /* The denominator is possibly < EPS??? Check that ? */#ifdef DO_WITH_GSL  /* double gsl_ran_gaussian_pdf (double x, double sigma) */  return gsl_ran_gaussian_pdf (x - mean, sqrt (u));#else  expo = exp (-1 * m_sqr (mean - x) / (2 * u));  return (1 / (sqrt (2 * PI * u)) * expo);#endifSTOP:  return (-1.0);# undef CUR_PROC}                               /* double ighmm_rand_normal_density *//*============================================================================*/double ighmm_rand_uniform_density (double x, double max, double min){# define CUR_PROC "ighmm_rand_uniform_density"  double prob;  if (max <= min) {    GHMM_LOG(LCONVERTED, "max <= min not allowed \n");    goto STOP;  }  prob = 1.0/(max-min);  if ( (x <= max) && (x>=min) ){    return prob;  }else{    return 0.0;  }STOP:  return (-1.0);# undef CUR_PROC}                               /* double ighmm_rand_uniform_density *//*============================================================================*//* special ghmm_cmodel pdf need it: smo->density==normal_approx: *//* generates a table of of aequidistant samples of gaussian pdf */static int randvar_init_pdf_stdnormal (){# define CUR_PROC "randvar_init_pdf_stdnormal"  int i;  double x = 0.00;  for (i = 0; i < PDFLEN; i++) {    pdf_stdnormal[i] = 1 / (sqrt (2 * PI)) * exp (-1 * x * x / 2);    x += (double) X_STEP_PDF;  }  pdf_stdnormal_exists = 1;  /* printf("pdf_stdnormal_exists = %d\n", pdf_stdnormal_exists); */  return (0);# undef CUR_PROC}                               /* randvar_init_pdf_stdnormal */double ighmm_rand_normal_density_approx (double x, double mean, double u){# define CUR_PROC "ighmm_rand_normal_density_approx"#ifdef HAVE_LIBPTHREAD  static pthread_mutex_t lock;#endif /* HAVE_LIBPTHREAD */  int i;  double y, z, pdf_x;  if (u <= 0.0) {    GHMM_LOG(LCONVERTED, "u <= 0.0 not allowed\n");    goto STOP;  }  if (!pdf_stdnormal_exists) {#ifdef HAVE_LIBPTHREAD    pthread_mutex_lock (&lock); /* Put on a lock, because the clustering is parallel   */#endif /* HAVE_LIBPTHREAD */    randvar_init_pdf_stdnormal ();#ifdef HAVE_LIBPTHREAD    pthread_mutex_unlock (&lock);       /* Take the lock off */#endif /* HAVE_LIBPTHREAD */  }  y = 1 / sqrt (u);  z = fabs ((x - mean) * y);  i = (int) (z * X_FAKT_PDF);  /* linear interpolation: */  if (i >= PDFLEN - 1) {    i = PDFLEN - 1;    pdf_x = y * pdf_stdnormal[i];  }  else    pdf_x = y * (pdf_stdnormal[i] +                 (z - i * X_STEP_PDF) *                 (pdf_stdnormal[i + 1] - pdf_stdnormal[i]) / X_STEP_PDF);  return (pdf_x);STOP:  return (-1.0);# undef CUR_PROC}                               /* double ighmm_rand_normal_density_approx *//*============================================================================*/double ighmm_rand_std_normal (int seed){# define CUR_PROC "ighmm_rand_std_normal"  if (seed != 0) {    GHMM_RNG_SET (RNG, seed);    return (1.0);  }  else {#ifdef DO_WITH_GSL    return (gsl_ran_gaussian (RNG, 1.0));#else    /* Use the polar Box-Mueller transform */    /*       double x, y, r2;       do {       x = 2.0 * GHMM_RNG_UNIFORM(RNG) - 1.0;       y = 2.0 * GHMM_RNG_UNIFORM(RNG) - 1.0;       r2 = (x * x) + (y * y);       } while (r2 >= 1.0);       return x * sqrt((-2.0 * log(r2)) / r2);     */    double r2, theta;    r2 = -2.0 * log (GHMM_RNG_UNIFORM (RNG));   /* r2 ~ chi-square(2) */    theta = 2.0 * PI * GHMM_RNG_UNIFORM (RNG);  /* theta ~ uniform(0, 2 \pi) */    return sqrt (r2) * cos (theta);#endif  }# undef CUR_PROC}                               /* ighmm_rand_std_normal *//*============================================================================*/double ighmm_rand_normal (double mue, double u, int seed){# define CUR_PROC "ighmm_rand_normal"  if (seed != 0) {    GHMM_RNG_SET (RNG, seed);    return (1.0 * sqrt (u) + mue);  }  else {#ifdef DO_WITH_GSL    return (gsl_ran_gaussian (RNG, sqrt (u)) + mue);#else    double x;    x = sqrt (u) * ighmm_rand_std_normal (seed) + mue;    return (x);#endif  }# undef CUR_PROC}                               /* ighmm_rand_normal *//*============================================================================*/#ifndef DO_WITH_GSL# define C0 2.515517# define C1 0.802853# define C2 0.010328# define D1 1.432788# define D2 0.189269# define D3 0.001308#endifdouble ighmm_rand_normal_right (double a, double mue, double u, int seed){# define CUR_PROC "ighmm_rand_normal_right"  double x = -1;  double sigma;#ifdef DO_WITH_GSL  double s;#else  double U, Us, Us1, Feps, Feps1, t, T;#endif  if (u <= 0.0) {    GHMM_LOG(LCONVERTED, "u <= 0.0 not allowed\n");    goto STOP;  }  sigma = sqrt (u);  if (seed != 0) {    GHMM_RNG_SET (RNG, seed);    return (1.0);  }#ifdef DO_WITH_GSL  /* up to version 0.8 gsl_ran_gaussian_tail can not handle negative cutoff */#define GSL_RAN_GAUSSIAN_TAIL_BUG 1#ifdef GSL_RAN_GAUSSIAN_TAIL_BUG  s = (-mue) / sigma;  if (s < 1) {    do {      x = gsl_ran_gaussian (RNG, 1.0);    }    while (x < s);    return x * sigma + mue;  }#endif /* GSL_RAN_GAUSSIAN_TAIL_BUG */  /* move boundary to lower values in order to achieve maximum at mue     gsl_ran_gaussian_tail(generator, lower_boundary, sigma)   */  return gsl_ran_gaussian_tail (RNG, a - mue, sqrt (u)) + mue;#else /* DO_WITH_GSL */  /* Method: Generate Gauss-distributed random nunbers (with GSL-lib.),     until a positive one is found -> not very effective if mue << 0     while (x < 0.0) {     x = sigma * ighmm_rand_std_normal(seed) + mue;     } */  /* Inverse transformation with restricted sampling by Fishman */  U = GHMM_RNG_UNIFORM (RNG);  Feps = ighmm_rand_get_PHI (-(a + mue) / sigma);  Us = Feps + (1 - Feps) * U;  /* Numerically better: 1-Us = 1-Feps - (1-Feps)*U, therefore:      Feps1 = 1-Feps, Us1 = 1-Us */  Feps1 = ighmm_rand_get_PHI ((a + mue) / sigma);  Us1 = Feps1 - Feps1 * U;  t = m_min (Us, Us1);  t = sqrt (-log (t * t));  T =

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?