JWS C Library
C language utility library
pmf.c
Go to the documentation of this file.
00001 /*
00002  * This work is licensed under a Creative Commons 
00003  * Attribution-Noncommercial-Share Alike 3.0 United States License.
00004  * 
00005  *    http://creativecommons.org/licenses/by-nc-sa/3.0/us/
00006  * 
00007  * You are free:
00008  * 
00009  *    to Share - to copy, distribute, display, and perform the work
00010  *    to Remix - to make derivative works
00011  * 
00012  * Under the following conditions:
00013  * 
00014  *    Attribution. You must attribute the work in the manner specified by the
00015  *    author or licensor (but not in any way that suggests that they endorse you
00016  *    or your use of the work).
00017  * 
00018  *    Noncommercial. You may not use this work for commercial purposes.
00019  * 
00020  *    Share Alike. If you alter, transform, or build upon this work, you may
00021  *    distribute the resulting work only under the same or similar license to
00022  *    this one.
00023  * 
00024  * For any reuse or distribution, you must make clear to others the license
00025  * terms of this work. The best way to do this is by including this header.
00026  * 
00027  * Any of the above conditions can be waived if you get permission from the
00028  * copyright holder.
00029  * 
00030  * Apart from the remix rights granted under this license, nothing in this
00031  * license impairs or restricts the author's moral rights.
00032  */
00033 
00034 
00046 #include <jwsc/config.h>
00047 
00048 #include <stdlib.h>
00049 #include <math.h>
00050 #include <assert.h>
00051 #include <inttypes.h>
00052 
00053 #include "jwsc/base/limits.h"
00054 #include "jwsc/prob/pdf.h"
00055 #include "jwsc/prob/pmf.h"
00056 
00057 
00059 #define  INV_E_SINGLE       0.3678794411714423f
00060 
00062 #define  INV_E_DOUBLE       0.36787944117144232159552377016146
00063 
00065 #define  ALMOST_ONE_SINGLE  0.9999999999999999
00066 
00068 #define  ALMOST_ONE_DOUBLE  0.99999999999999999999999999999999
00069 
00070 
00088 float poisson_pmf_f(float lambda, uint32_t n)
00089 {
00090     float p;
00091     int i;
00092 
00093     if (lambda <= 0 && lambda == n)
00094     {
00095         return 1;
00096     }
00097     else if (lambda <= 0)
00098     {
00099         return 0;
00100     }
00101 
00102     p = 1;
00103 
00104     if (lambda < n)
00105     {
00106         for (i = n; i > (n - lambda); i--)
00107         {
00108             p *= lambda * INV_E_SINGLE * (1 / (float)i);
00109         }
00110 
00111         for (; i > 0; i--)
00112         {
00113             p *= lambda * (1 / (float)i);
00114         }
00115     }
00116     else
00117     {
00118         for (i = n; i > 0; i--)
00119         {
00120             p *= lambda * INV_E_SINGLE * (1 / (float)i);
00121         }
00122         
00123         p *= exp(-(lambda - n));
00124     }
00125 
00126 #if defined(JWSC_HAVE_ISNAN) && defined(JWSC_HAVE_ISINF)
00127     if (isnan(p) || isinf(p))
00128     {
00129         return 0;
00130     }
00131 #endif
00132 
00133     return p;
00134 }
00135 
00146 double poisson_pmf_d(double lambda, uint32_t n)
00147 {
00148     double p;
00149     int i;
00150 
00151     if (lambda <= 0 && lambda == n)
00152     {
00153         return 1;
00154     }
00155     else if (lambda <= 0)
00156     {
00157         return 0;
00158     }
00159 
00160     p = 1;
00161 
00162     if (lambda < n)
00163     {
00164         for (i = n; i > (n - lambda); i--)
00165         {
00166             p *= lambda * INV_E_DOUBLE * (1 / (double)i);
00167         }
00168 
00169         for (; i > 0; i--)
00170         {
00171             p *= lambda * (1 / (double)i);
00172         }
00173     }
00174     else
00175     {
00176         for (i = n; i > 0; i--)
00177         {
00178             p *= lambda * INV_E_DOUBLE * (1 / (double)i);
00179         }
00180         
00181         p *= exp(-(lambda - n));
00182     }
00183 
00184 #if defined(JWSC_HAVE_ISNAN) && defined(JWSC_HAVE_ISINF)
00185     if (isnan(p) || isinf(p))
00186     {
00187         return 0;
00188     }
00189 #endif
00190 
00191     return p;
00192 }
00193 
00221 uint32_t sample_poisson_pmf_f
00222 (
00223     float lambda, 
00224     uint32_t a, 
00225     uint32_t b
00226 )
00227 {
00228     uint32_t s;
00229     uint32_t accept;
00230     float max_p, p, u;
00231 
00232     if (lambda <= 0 && ((lambda >= a) && (lambda <= b)))
00233     {
00234         return (int)lambda;
00235     }
00236     else if (lambda <= 0)
00237     {
00238         return (a - lambda) < (lambda - b) ? a : b;
00239     }
00240 
00241     max_p = poisson_pmf_f(lambda, floor(lambda + 0.5));
00242     accept = 0;
00243 
00244     while (!accept)
00245     {
00246         s = floor(sample_uniform_pdf_f((float)a, (float)b+1.0));
00247         if (s == b+1)
00248         {
00249             s = b;
00250         }
00251         p = poisson_pmf_f(lambda, s);
00252         u = sample_uniform_pdf_f(0, max_p);
00253 
00254         if (u <= p)
00255         {
00256             accept = 1;
00257         }
00258     }
00259 
00260     return s;
00261 }
00262 
00280 uint32_t sample_poisson_pmf_d
00281 (
00282     double lambda, 
00283     uint32_t a, 
00284     uint32_t b
00285 )
00286 {
00287     uint32_t s;
00288     uint32_t accept;
00289     double max_p, p, u;
00290 
00291     if (lambda <= 0 && ((lambda >= a) && (lambda <= b)))
00292     {
00293         return (int)lambda;
00294     }
00295     else if (lambda <= 0)
00296     {
00297         return (a - lambda) < (lambda - b) ? a : b;
00298     }
00299 
00300     max_p = poisson_pmf_d(lambda, floor(lambda + 0.5));
00301     accept = 0;
00302 
00303     while (!accept)
00304     {
00305         s = floor(sample_uniform_pdf_d((double)a, (double)b+1.0));
00306         if (s == b+1)
00307         {
00308             s = b;
00309         }
00310         p = poisson_pmf_d(lambda, s);
00311         u = sample_uniform_pdf_d(0, max_p);
00312 
00313         if (u <= p)
00314         {
00315             accept = 1;
00316         }
00317     }
00318 
00319     return s;
00320 }
00321 
00340 float bernoulli_pmf_f(float p, uint32_t n)
00341 {
00342     return n ? p : (1.0 - p);
00343 }
00344 
00353 double bernoulli_pmf_d(double p, uint32_t n)
00354 {
00355     return n ? p : (1.0 - p);
00356 }
00357 
00377 uint8_t sample_bernoulli_pmf_f(float p)
00378 {
00379     float u;
00380 
00381     assert(p >= 0.0 && p <= 1.0);
00382 
00383     u = sample_uniform_pdf_f(0.0, 1.0);
00384 
00385     if (u <= p)
00386     {
00387         return 1;
00388     }
00389 
00390     return 0;
00391 }
00392 
00402 uint8_t sample_bernoulli_pmf_d(double p)
00403 {
00404     double u;
00405 
00406     assert(p >= 0.0 && p <= 1.0);
00407 
00408     u = sample_uniform_pdf_d(0.0, 1.0);
00409 
00410     if (u <= p)
00411     {
00412         return 1;
00413     }
00414 
00415     return 0;
00416 }
00417 
00440 float geometric_pmf_f(float p, uint32_t n)
00441 {
00442     uint32_t i;
00443     float P;
00444 
00445     assert(p > 0 && p < 1);
00446 
00447     P = 1.0;
00448 
00449     for (i = 0; i < n; i++)
00450     {
00451         P *= (1.0 - p);
00452     }
00453 
00454     return P * p;
00455 }
00456 
00469 double geometric_pmf_d(double p, uint32_t n)
00470 {
00471     uint32_t i;
00472     double P;
00473 
00474     assert(p > 0 && p < 1);
00475 
00476     P = 1.0;
00477 
00478     for (i = 0; i < n; i++)
00479     {
00480         P *= (1.0 - p);
00481     }
00482 
00483     return P * p;
00484 }
00485 
00508 float log_geometric_pmf_f(float p, uint32_t n)
00509 {
00510     float q = 1 - p;
00511 
00512     assert(p > 0 && p < 1);
00513     if (p < JWSC_MIN_LOG_ARG)
00514     {
00515         p = JWSC_MIN_LOG_ARG;
00516     }
00517     else if (q < JWSC_MIN_LOG_ARG)
00518     {
00519         q = JWSC_MIN_LOG_ARG;
00520     }
00521 
00522     return log(p) + n*log(q);
00523 }
00524 
00537 double log_geometric_pmf_d(double p, uint32_t n)
00538 {
00539     double q = 1 - p;
00540 
00541     assert(p > 0 && p < 1);
00542     if (p < JWSC_MIN_LOG_ARG)
00543     {
00544         p = JWSC_MIN_LOG_ARG;
00545     }
00546     else if (q < JWSC_MIN_LOG_ARG)
00547     {
00548         q = JWSC_MIN_LOG_ARG;
00549     }
00550 
00551     return log(p) + n*log(q);
00552 }
00553 
00574 uint32_t sample_geometric_pmf_f(float p)
00575 {
00576     float u;
00577 
00578     assert(p > 0 && p < 1);
00579 
00580     u = sample_uniform_pdf_f(p, ALMOST_ONE_SINGLE);
00581 
00582     return (uint32_t)floor((log(1.0 - u) / log(1.0 - p)) - 1.0);
00583 }
00584 
00595 uint32_t sample_geometric_pmf_d(double p)
00596 {
00597     double u;
00598 
00599     assert(p > 0 && p < 1);
00600 
00601     u = sample_uniform_pdf_d(p, ALMOST_ONE_DOUBLE);
00602 
00603     return (uint32_t)floor((log(1.0 - u) / log(1.0 - p)) - 1.0);
00604 }
00605