Added script front-end for primer-design code
[htsworkflow.git] / htswanalysis / MACS / lib / gsl / gsl-1.11 / randist / multinomial.c
1 /* randist/multinomial.c
2  * 
3  * Copyright (C) 2002 Gavin E. Crooks <gec@compbio.berkeley.edu>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or (at
8  * your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #include <config.h>
21 #include <math.h>
22 #include <gsl/gsl_rng.h>
23 #include <gsl/gsl_randist.h>
24 #include <gsl/gsl_sf_gamma.h>
25
26 /* The multinomial distribution has the form
27
28                                       N!           n_1  n_2      n_K
29    prob(n_1, n_2, ... n_K) = -------------------- p_1  p_2  ... p_K
30                              (n_1! n_2! ... n_K!) 
31
32    where n_1, n_2, ... n_K are nonnegative integers, sum_{k=1,K} n_k = N,
33    and p = (p_1, p_2, ..., p_K) is a probability distribution. 
34
35    Random variates are generated using the conditional binomial method.
36    This scales well with N and does not require a setup step.
37
38    Ref: 
39    C.S. David, The computer generation of multinomial random variates,
40    Comp. Stat. Data Anal. 16 (1993) 205-217
41 */
42
43 void
44 gsl_ran_multinomial (const gsl_rng * r, const size_t K,
45                      const unsigned int N, const double p[], unsigned int n[])
46 {
47   size_t k;
48   double norm = 0.0;
49   double sum_p = 0.0;
50
51   unsigned int sum_n = 0;
52
53   /* p[k] may contain non-negative weights that do not sum to 1.0.
54    * Even a probability distribution will not exactly sum to 1.0
55    * due to rounding errors. 
56    */
57
58   for (k = 0; k < K; k++)
59     {
60       norm += p[k];
61     }
62
63   for (k = 0; k < K; k++)
64     {
65       if (p[k] > 0.0)
66         {
67           n[k] = gsl_ran_binomial (r, p[k] / (norm - sum_p), N - sum_n);
68         }
69       else
70         {
71           n[k] = 0;
72         }
73
74       sum_p += p[k];
75       sum_n += n[k];
76     }
77
78 }
79
80
81 double
82 gsl_ran_multinomial_pdf (const size_t K,
83                          const double p[], const unsigned int n[])
84 {
85   return exp (gsl_ran_multinomial_lnpdf (K, p, n));
86 }
87
88
89 double
90 gsl_ran_multinomial_lnpdf (const size_t K,
91                            const double p[], const unsigned int n[])
92 {
93   size_t k;
94   unsigned int N = 0;
95   double log_pdf = 0.0;
96   double norm = 0.0;
97
98   for (k = 0; k < K; k++)
99     {
100       N += n[k];
101     }
102
103   for (k = 0; k < K; k++)
104     {
105       norm += p[k];
106     }
107
108   log_pdf = gsl_sf_lnfact (N);
109
110   for (k = 0; k < K; k++)
111     {
112       /* Handle case where n[k]==0 and p[k]==0 */
113
114       if (n[k] > 0) 
115         {
116           log_pdf += log (p[k] / norm) * n[k] - gsl_sf_lnfact (n[k]);
117         }
118     }
119
120   return log_pdf;
121 }