src/math.c

Go to the documentation of this file.
00001 /*
00002    libit - Library for basic source and channel coding functions
00003    Copyright (C) 2005-2005 Vivien Chappelier, Herve Jegou
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public
00016    License along with this library; if not, write to the Free
00017    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 */
00019 
00020 /*
00021   Functions
00022   Copyright (C) 2005 Vivien Chappelier, Hervé Jégou
00023 */
00024 
00025 #include <it/types.h>
00026 #include <it/math.h>
00027 #include <it/vec.h>
00028 #include <it/io.h>
00029 
00030 /*----------------------------------------------------------------------------*/
00031 /* the differentiation operator */
00032 it_function (itf_differentiate)
00033 {
00034   volatile double round;
00035   double epsilon;
00036   double fmin, fmax;
00037   it_function_t f = it_this->function;
00038   it_args_t args = it_this->args;
00039 
00040   /* some small constant (~1/3 of double precision) */
00041   epsilon = 1e-6 * ((x > 0) ? (x) : (-x));
00042   if (epsilon < 1e-6)
00043     epsilon = 1e-6;
00044 
00045   /* round off to appropriate binary representation */
00046   round = x + epsilon;
00047   epsilon = round - x;
00048 
00049   /* add some precision */
00050   fmax = f (x + epsilon, args);
00051   fmin = f (x - epsilon, args);
00052 
00053   return ((fmax - fmin) / (2.0 * epsilon));
00054 }
00055 
00056 
00057 /*----------------------------------------------------------------------------*/
00058 /* the 2nd-order differentiation operator */
00059 it_function (itf_diff2)
00060 {
00061   volatile double round;
00062   double epsilon;
00063   double fmin, fmid, fmax;
00064   it_function_t f = it_this->function;
00065   it_args_t args = it_this->args;
00066 
00067   /* some small constant (~1/6 of double precision) */
00068   epsilon = 1e-3 * ((x > 0) ? (x) : (-x));
00069   if (epsilon < 1e-3)
00070     epsilon = 1e-3;
00071 
00072   /* round off to appropriate binary representation */
00073   round = x + epsilon;
00074   epsilon = round - x;
00075 
00076   /* add some precision */
00077   fmax = f (x + epsilon, args);
00078   fmin = f (x - epsilon, args);
00079   fmid = f (x, args);
00080 
00081   return ((fmax - 2 * fmid + fmin) / (epsilon * epsilon));
00082 }
00083 
00084 
00085 /*----------------------------------------------------------------------------*/
00086 /* integration using the trapezoid method */
00087 it_function (itf_integrate_trapezoid)
00088 {
00089   double b = x;
00090   double a = it_this->a;
00091   int  N = it_this->N;
00092   it_function_t f = it_this->function;
00093   it_args_t args = it_this->args;
00094   double step;
00095   double sum;
00096   int  i;
00097 
00098   step = (b - a) / N;
00099 
00100   sum = f (a, args) / 2;
00101   x = a + step;
00102 
00103   for (i = 1; i <= N - 1; i++) {
00104     sum += f (x, args);
00105     x += step;
00106   }
00107 
00108   sum += f (b, args) / 2;
00109   sum *= step;
00110 
00111   return (sum);
00112 }
00113 
00114 
00115 /*----------------------------------------------------------------------------*/
00116 /* integration using the Romberg method (Richardson + trapezoid) */
00117 it_function (itf_integrate_romberg)
00118 {
00119   double b = x;
00120   double a = it_this->a;
00121   int  N = it_this->N;
00122   int  p = it_this->p;
00123   it_function_t f = it_this->function;
00124   it_args_t args = it_this->args;
00125   double step;
00126   double r;
00127   int  i, n;
00128   vec  S;
00129 
00130   step = (b - a) / N;
00131 
00132   S = vec_new (p);
00133 
00134   /* compute the first trapezoid integral */
00135   S[0] = f (a, args) / 2;
00136   x = a + step;
00137 
00138   for (i = 1; i <= N - 1; i++) {
00139     S[0] += f (x, args);
00140     x += step;
00141   }
00142 
00143   S[0] += f (b, args) / 2;
00144   S[0] *= step;
00145 
00146   /* compute p trapezoid integrals with step/2^p recursively */
00147   for (n = 1; n < p; n++) {
00148 
00149     step /= 2;
00150     N *= 2;
00151     x = a + step;
00152     S[n] = 0;
00153 
00154     for (i = 1; i <= N - 1; i += 2) {
00155       S[n] += f (x, args);
00156       x += 2 * step;
00157     }
00158     S[n] *= step;
00159     S[n] += S[n - 1] / 2;
00160   }
00161 
00162   /* use the Richardson method to improve the approximation order */
00163   for (n = p - 1; n >= 0; n--) {
00164     r = (1 << 2 * (p - n)); /* 4^j */
00165     for (i = 0; i < n; i++)
00166       S[i] = (r * S[i + 1] - S[i]) / (r - 1);
00167   }
00168 
00169   r = S[0];
00170 
00171   vec_delete (S);
00172 
00173   return (r);
00174 }
00175 
00176 
00177 /*----------------------------------------------------------------------------*/
00178 /* default integral (romberg with fixed precision) */
00179 it_function (itf_integrate)
00180 {
00181   it_function_args (itf_integrate_romberg) integrate_romberg_args;
00182   double b = x;
00183   double a = it_this->a;
00184   int  N;
00185   int  p;
00186 
00187   /* compute N so that step < 0.5 */
00188   N = (int) (2 * (b - a) + 1);
00189   p = 10;     /* sane default */
00190 
00191   integrate_romberg_args.a = a;
00192   integrate_romberg_args.N = N;
00193   integrate_romberg_args.p = p;
00194   integrate_romberg_args.function = it_this->function;
00195   integrate_romberg_args.args = it_this->args;
00196 
00197   return (itf_integrate_romberg (x, &integrate_romberg_args));
00198 }
00199 
00200 
00201 /*----------------------------------------------------------------------------*/
00202 /* compute the expectation (first moment of the function) */
00203 it_function (itf_expectation)
00204 {
00205   it_function_args (itf_mul) mul_args;
00206   it_function_args (itf_integrate) integrate_args;
00207 
00208   /* for integrating x * f(x) */
00209   mul_args.f = itf_identity;
00210   mul_args.f_args = NULL;
00211   mul_args.g = it_this->function;
00212   mul_args.g_args = it_this->args;
00213   integrate_args.function = itf_mul;
00214   integrate_args.args = &mul_args;
00215   integrate_args.a = it_this->a;
00216 
00217   return (itf_integrate (x, &integrate_args));
00218 }
00219 
00220 
00221 /*----------------------------------------------------------------------------*/
00222 /* function composition, returns f(g(x)) */
00223 it_function (itf_compose)
00224 {
00225   it_function_t f = it_this->f;
00226   it_function_t g = it_this->g;
00227   it_args_t f_args = it_this->f_args;
00228   it_args_t g_args = it_this->g_args;
00229 
00230   return (f (g (x, g_args), f_args));
00231 }
00232 
00233 
00234 /*----------------------------------------------------------------------------*/
00235 /* function sum, returns f(x) + g(x) */
00236 it_function (itf_sum)
00237 {
00238   it_function_t f = it_this->f;
00239   it_function_t g = it_this->g;
00240   it_args_t f_args = it_this->f_args;
00241   it_args_t g_args = it_this->g_args;
00242 
00243   return (f (x, f_args) + g (x, g_args));
00244 }
00245 
00246 
00247 /*----------------------------------------------------------------------------*/
00248 /* function product, returns f(x) * g(x) */
00249 it_function (itf_mul)
00250 {
00251   it_function_t f = it_this->f;
00252   it_function_t g = it_this->g;
00253   it_args_t f_args = it_this->f_args;
00254   it_args_t g_args = it_this->g_args;
00255 
00256   return (f (x, f_args) * g (x, g_args));
00257 }
00258 
00259 
00260 /*----------------------------------------------------------------------------*/
00261 /* identity */
00262 it_function (itf_identity)
00263 {
00264   return (x);
00265 }
00266 
00267 
00268 /*----------------------------------------------------------------------------*/
00269 /* Gaussian distribution */
00270 it_function (itf_gaussian)
00271 {
00272   double sigma = it_this->sigma;
00273 
00274   return (1. / (sqrt (2. * M_PI) * sigma) *
00275     exp (-x * x / (2. * sigma * sigma)));
00276 }
00277 
00278 
00279 /*----------------------------------------------------------------------------*/
00280 /* Laplacian distribution */
00281 it_function (itf_laplacian)
00282 {
00283   double lambda = it_this->lambda;  /* variance is 2*lambda^2 */
00284 
00285   return (1. / (2. * lambda) * exp (-fabs (x) / lambda));
00286 }
00287 
00288 
00289 /*----------------------------------------------------------------------------*/
00290 /* Generalized Gaussian distribution */
00291 #ifdef WIN32
00292 it_function (itf_generalized_gaussian)
00293 {
00294   it_fprintf (stderr, "undefined function lgamma()\n");
00295   return (NAN);
00296 }
00297 #else
00298 it_function (itf_generalized_gaussian)
00299 {
00300   double alpha = it_this->alpha;
00301   double beta = it_this->beta;
00302 
00303   assert (alpha > 0);
00304   assert (beta > 0);
00305 
00306   return (beta / (2.0 * alpha) *
00307     exp (-lgamma (1.0 / beta) - pow (fabs (x) / alpha, beta)));
00308 }
00309 #endif
00310 
00311 /*----------------------------------------------------------------------------*/
00312 #define erfinv_a3 -0.140543331
00313 #define erfinv_a2 0.914624893
00314 #define erfinv_a1 -1.645349621
00315 #define erfinv_a0 0.886226899
00316 
00317 #define erfinv_b4 0.012229801
00318 #define erfinv_b3 -0.329097515
00319 #define erfinv_b2 1.442710462
00320 #define erfinv_b1 -2.118377725
00321 #define erfinv_b0 1
00322 
00323 #define erfinv_c3 1.641345311
00324 #define erfinv_c2 3.429567803
00325 #define erfinv_c1 -1.62490649
00326 #define erfinv_c0 -1.970840454
00327 
00328 #define erfinv_d2 1.637067800
00329 #define erfinv_d1 3.543889200
00330 #define erfinv_d0 1
00331 
00332 #ifdef WIN32
00333 double erfinv (double x)
00334 {
00335   it_fprintf (stderr, "undefined function erf()\n");
00336   return (NAN);
00337 }
00338 #else
00339 double erfinv (double x)
00340 {
00341   double x2, r, y;
00342   int  sign_x;
00343 
00344   if (x < -1 || x > 1)
00345     return NAN;
00346 
00347   if (x == 0)
00348     return 0;
00349 
00350   if (x > 0)
00351     sign_x = 1;
00352   else {
00353     sign_x = -1;
00354     x = -x;
00355   }
00356 
00357   if (x <= 0.7) {
00358 
00359     x2 = x * x;
00360     r =
00361       x * (((erfinv_a3 * x2 + erfinv_a2) * x2 + erfinv_a1) * x2 + erfinv_a0);
00362     r /= (((erfinv_b4 * x2 + erfinv_b3) * x2 + erfinv_b2) * x2 +
00363     erfinv_b1) * x2 + erfinv_b0;
00364   }
00365   else {
00366     y = sqrt (-log ((1 - x) / 2));
00367     r = (((erfinv_c3 * y + erfinv_c2) * y + erfinv_c1) * y + erfinv_c0);
00368     r /= ((erfinv_d2 * y + erfinv_d1) * y + erfinv_d0);
00369   }
00370 
00371   r = r * sign_x;
00372   x = x * sign_x;
00373 
00374   r -= (erf (r) - x) / (2 / sqrt (M_PI) * exp (-r * r));
00375   r -= (erf (r) - x) / (2 / sqrt (M_PI) * exp (-r * r));
00376 
00377   return r;
00378 }
00379 #endif
00380 
00381 #undef erfinv_a3
00382 #undef erfinv_a2
00383 #undef erfinv_a1
00384 #undef erfinv_a0
00385 
00386 #undef erfinv_b4
00387 #undef erfinv_b3
00388 #undef erfinv_b2
00389 #undef erfinv_b1
00390 #undef erfinv_b0
00391 
00392 #undef erfinv_c3
00393 #undef erfinv_c2
00394 #undef erfinv_c1
00395 #undef erfinv_c0
00396 
00397 #undef erfinv_d2
00398 #undef erfinv_d1
00399 #undef erfinv_d0
00400 
00401 
00402 /*----------------------------------------------------------------------------*/
00403 static int nchoosek_tmp (int n, int k)
00404 {
00405   if (k == 0)
00406     return 1;
00407 
00408   return (n * nchoosek_tmp (n - 1, k - 1)) / k;
00409 }
00410 
00411 
00412 int nchoosek (int n, int k)
00413 {
00414   if (k > n || k < 0)
00415     return 0;
00416 
00417   if (k > n / 2)
00418     k = n - k;
00419 
00420   return nchoosek_tmp (n, k);
00421 }
00422 
00423 
00424 /*----------------------------------------------------------------------------*/
00425 double lognchoosek (int n, int k)
00426 {
00427   int  i;
00428   double r = 0;
00429   if (k > n || k < 0)
00430     return 0;
00431 
00432   if (k > n / 2)
00433     k = n - k;
00434 
00435   for (i = 1; i <= k; i++)
00436     r -= log (i);
00437 
00438   for (i = n - k + 1; i <= n; i++)
00439     r += log (i);
00440 
00441   return r;
00442 }
00443 
00444 /*----------------------------------------------------------------------------*/
00445 double it_integrate (it_function_t function, it_args_t args, double a,
00446          double b)
00447 {
00448   it_function_args (itf_integrate) integrate_args;
00449 
00450   integrate_args.function = function;
00451   integrate_args.args = args;
00452   integrate_args.a = a;
00453   return (itf_integrate (b, &integrate_args));
00454 }
00455 
00456 double it_differentiate (it_function_t function, it_args_t args, double a)
00457 {
00458   it_function_args (itf_differentiate) differentiate_args;
00459 
00460   differentiate_args.function = function;
00461   differentiate_args.args = args;
00462   return (itf_differentiate (a, &differentiate_args));
00463 }
00464 
00465 
00466 
00467 /*----------------------------------------------------------------------------*/
00468 double log_sum(double log_a, double log_b)
00469 {
00470   if (log_a < log_b)
00471     return log_b + log (1 + exp(log_a - log_b));
00472   else
00473     return log_a + log (1 + exp(log_b - log_a));
00474 }
00475 
00476 
00477 /* Compute the logarithm of the Gamma function */
00478 double log_gamma (double x)
00479 {
00480   double z=1/(x*x);
00481 
00482     x=x+6;
00483     z=(((-0.000595238095238*z+0.000793650793651)
00484   *z-0.002777777777778)*z+0.083333333333333)/x;
00485     z=(x-0.5)*log(x)-x+0.918938533204673+z-log(x-1)-
00486   log(x-2)-log(x-3)-log(x-4)-log(x-5)-log(x-6);
00487     return z;
00488 }
00489 
00490 
00491 /* Sigmoid and functions: 1 / (1 + exp(-lambda * x)) */
00492 double sigmoid (double x, double lambda)
00493 {
00494   return 1 / (1 + exp (-lambda * x));
00495 }
00496 
00497 
00498 double invsigmoid (double x, double lambda)
00499 {
00500   return - log(1 / x - 1) / lambda;
00501 }

Hosted by
Copyright (C) 2005-2006 Hervé Jégou
Vivien Chappelier
Francois Cayre
libit logo courtesy of Jonathan Delhumeau