3 Copyright (C) 2005-2017 Mario Rodriguez Riotorto
5 This program is free software; you can redistribute
6 it and/or modify it under the terms of the
7 GNU General Public License as published by
8 the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it
12 will be useful, but WITHOUT ANY WARRANTY;
13 without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details at
16 http://www.gnu.org/copyleft/gpl.html
18 For comments, suggestions and the like, feel free to contact the author at
21 batch("rtest_distrib.mac", test) ;
23 riotorto AT yahoo DOT com
30 This is a set of Maxima functions for univariate probability distributions,
31 both continuous and discrete.
33 Continuous distributions: Discrete distributions:
34 Normal (*normal) Binomial (*binomial)
35 Student (*student_t) Poisson (*poisson)
36 Chi^2 (*chi2) Bernoulli (*bernoulli)
37 F (*f) Geometric (*geometric)
38 Exponential (*exp) Discrete uniform (*discrete_uniform)
39 Lognormal (*lognormal) Hypergeometric (*hypergeometric)
40 Gamma (*gamma) Negative binomial (*negative_binomial)
41 Beta (*beta) Finite discrete (*general_finite_discrete)
42 Continuous uniform (*continuous_uniform)
50 Noncentral Chi^2 (*noncentral_chi2)
51 Noncentral Student (*noncentral_student_t)
54 Density function (pdf_*)
55 Distribution function (cdf_*)
59 Standard deviation (std_*)
60 Skewness coefficient (skewness_*)
61 Kurtosis coefficient (kurtosis_*)
62 Random variate (random_*)
65 pdf_student_t(x,n) is the density function of the Student distribution
66 with n degrees of freedom
67 std_pareto(a,b) is the standard deviation of the Pareto distribution
68 with parameters a and b
69 kurtosis_poisson(m) is the kurtosis coefficient of the Poisson distribution
72 Note: the Cauchy model has no moments, in this case only the density and
73 the distribution functions, 'pdf_cauchy' and 'cdf_cauchy', are defined.
75 For questions, suggestions, bugs and the like, feel free
78 riotorto @@@ yahoo DOT com
81 put('distrib, 2, 'version) $
83 /* Sets the random state according to the computer clock time */
84 set_random_state(make_random_state(true))$
87 /* Loads numerical routines */
88 load("numdistrib.lisp")$
92 /* NORMAL (OR GAUSSIAN) DISTRIBUTION */
95 if maybe(s > 0) = false
96 then error("pdf_normal: standard deviation must be greater than zero")
97 else exp(-(x-m)^2/(2*s^2))/(sqrt(2*%pi)*s)$
100 if maybe(s > 0) = false
101 then error("cdf_normal: standard deviation must be greater than zero")
102 else 1/2+erf((x-m)/(s*sqrt(2)))/2 $
104 /* R: qnorm(q,m,s) */
105 quantile_normal(q,m,s) :=
106 if maybe(s > 0 and q >= 0 and q <= 1) = false
107 then error("quantile_normal: illegal parameters")
108 else if sign(q) = 'zero
110 elseif sign(q-1) = 'zero
112 else m + sqrt(2)*s*inverse_erf(2*q-1) $
115 if maybe(s > 0) = false
116 then error("mean_normal: standard deviation must be greater than zero")
120 if maybe(s > 0) = false
121 then error("var_normal: standard deviation must be greater than zero")
125 if maybe(s > 0) = false
126 then error("std_normal: standard deviation must be greater than zero")
129 skewness_normal(m,s) :=
130 if maybe(s > 0) = false
131 then error("skewness_normal: standard deviation must be greater than zero")
134 kurtosis_normal(m,s) :=
135 if maybe(s > 0) = false
136 then error("kurtosis_normal: standard deviation must be greater than zero")
139 random_normal(m,s,[num]) :=
140 if maybe(s > 0) = false
141 then error("random_normal: standard deviation must be greater than zero")
143 if length(num) = 0 then no: 0 else no: num[1],
144 if integerp(no) and no >= 0
145 then m + s * ?rndnormal(no)
146 else error("random_normal: check sample size")) $
150 /* STUDENT DISTRIBUTION */
152 pdf_student_t(x,n) :=
153 if maybe(n > 0) = false
154 then error("pdf_student: number of degrees must be greater than zero")
155 else gamma((n+1)/2) * (1+x*x/n)^(-(n+1)/2) / (sqrt(n*%pi) * gamma(n/2)) $
158 cdf_student_t(x,n) :=
159 if maybe(n > 0) = false
160 then error("cdf_student_t: number of degrees must be greater than zero")
161 else (1+signum(x))/2 - signum(x) * beta_incomplete_regularized(n/2,1/2,n/(n+x^2)) / 2 $
164 quantile_student_t(q,n) :=
165 if maybe(n > 0 and q >= 0 and q <= 1) = false
166 then error("quantile_student_t: illegal parameters")
167 else /* need numerical approximation */
168 block([fq: float(q), fn: float(n), aux, sgn],
169 if numberp(fq) and numberp(fn)
170 then (if fq = 0.0 then return('minf),
171 if fq = 1.0 then return('inf),
172 if fq = 0.5 then return(0),
178 sgn*sqrt(n*(1 / ?iibeta(aux,float(n/2),0.5)-1)))
179 else error("quantile_student: need numeric arguments for approximate procedure")) $
182 if maybe(n > 0) = false
183 then error("mean_student_t:: degrees of freedom must be greater than zero")
187 if maybe(n > 2) = false
188 then error("var_student_t: degrees of freedom must be greater than 2")
192 if maybe(n > 2) = false
193 then error("std_student_t: degrees of freedom must be greater than 2")
194 else sqrt(n / (n-2)) $
196 skewness_student_t(n) :=
197 if maybe(n > 3) = false
198 then error("skewness_student_t: degrees of freedom must be greater than 3")
201 kurtosis_student_t(n) :=
202 if maybe(n > 4) = false
203 then error("kurtosis_student_t: degrees of freedom must be greater than 4")
206 random_student_t(n,[num]) :=
207 if maybe(n > 0) = false
208 then error("random_student_t: degrees of freedom must be greater than zero")
209 else block([no, fn: float(n)],
211 then error("random_student_t: need numeric arguments for approximate procedure"),
212 if length(num) = 0 then no: 0 else no: num[1],
213 if integerp(no) and no >= 0
214 then ?rndstudent(fn,no)
215 else error("random_student_t: check sample size") ) $
219 /* NONCENTRAL STUDENT DISTRIBUTION */
221 /* According to documentation on hgfred, sometimes it might be useful to load */
222 /* package orthopoly. In R, dt(x,n,ncp) */
223 pdf_noncentral_student_t(x,n,ncp) :=
224 if maybe(n > 0) = false
225 then error("pdf_noncentral_student_t: degrees of freedom must be greater than 0")
226 elseif sign(ncp) = 'zero
227 then pdf_student_t(x,n)
228 else n^(n/2) * factorial(n) * exp(-ncp^2/2) /
229 (2^n * (n+x^2)^(n/2) * gamma(n/2)) *
230 (sqrt(2)*ncp*x*hgfred([n/2+1],[3/2],ncp^2*x^2/(2*(n+x^2))) / ((n+x^2) * gamma((n+1)/2)) +
231 hgfred([(n+1)/2],[1/2],ncp^2*x^2/(2*(n+x^2))) / (sqrt(n+x^2) * gamma(n/2+1))) $
234 cdf_noncentral_student_t(x,n,ncp) :=
235 if maybe(n > 0) = false
236 then error("cdf_noncentral_student_t: degrees of freedom must be greater than 0")
237 elseif sign(ncp) = 'zero
238 then cdf_student_t(x,n)
239 else /* numerical approximation */
240 block([fx: float(x), fn: float(n), fncp: float(ncp)],
241 if numberp(fx) and numberp(fn) and numberp(fncp)
242 then ?cdfnt(fx,fn,fncp)
243 else error("cdf_noncentral_student_t: need numeric arguments for approximate procedure")) $
246 quantile_noncentral_student_t(q,n,ncp) :=
247 if maybe(n > 0 and q >= 0 and q <= 1) = false
248 then error("quantile_noncentral_student_t: illegal parameters")
249 else /* numerical approximation */
250 block([fq: float(q), fn: float(n), fncp: float(ncp)],
251 if numberp(fq) and numberp(fn)
252 then (if fq = 0.0 then return('minf),
253 if fq = 1.0 then return('inf),
256 then return(quantile_student_t(fq,fn))
257 else ?qnct(fq, fn, fncp)
258 else error("quantile_noncentral_student_t: need numeric arguments for approximate procedure")) ) $
260 mean_noncentral_student_t(n,ncp) :=
261 if maybe(n > 1) = false
262 then error("mean_noncentral_student_t: degrees of freedom must be greater than 1")
263 else ncp * sqrt(n/2) * gamma((n-1)/2) / gamma(n/2) $
265 var_noncentral_student_t(n,ncp) :=
266 if maybe(n > 2) = false
267 then error("var_noncentral_student_t: degrees of freedom must be greater than 2")
268 else n*(1+ncp^2)/(n-2) - ncp^2*n/2 * (gamma((n-1)/2) / gamma(n/2))^2 $
270 std_noncentral_student_t(n,ncp) := sqrt(var_noncentral_student_t(n,ncp)) $
272 skewness_noncentral_student_t(n,ncp) :=
273 if maybe(n > 3) = false
274 then error("skewness_noncentral_student_t: degrees of freedom must be greater than 3")
275 else block([m: mean_noncentral_student_t(n,ncp), v: var_noncentral_student_t(n,ncp)],
276 m / v^(3/2) * (n*(2*n-3+ncp^2)/((n-2)*(n-3)) - 2*v) ) $
278 kurtosis_noncentral_student_t(n,ncp) :=
279 if maybe(n > 4) = false
280 then error("kurtosis_noncentral_student_t: degrees of freedom must be greater than 4")
281 else block([m: mean_noncentral_student_t(n,ncp), v: var_noncentral_student_t(n,ncp)],
282 (n^2*(3+6*ncp^2+ncp^4)/((n-2)*(n-4)) - m^2 * (n*((n+1)*ncp^2+3*(3*n-5))/((n-2)*(n-3)) - 3*v))/v^2 - 3) $
284 random_noncentral_student_t(n,ncp,[num]) :=
285 if maybe(n > 0) = false
286 then error("random_noncentral_student_t: degrees of freedom must be greater than zero")
287 else block([no, fn: float(n), fncp: float(ncp)],
288 if numberp(fn) and numberp(fncp)
289 then (if length(num) = 0 then no: 0 else no: num[1],
290 if integerp(no) and no >= 0
291 then ?rndncstudent(fn,fncp,no)
292 else error("random_noncentral_student_t: check sample size"))
293 else error("random_noncentral_student_t: need numeric arguments for approximate procedure") ) $
297 /* CHI-SQUARE (OR PEARSON'S) DISTRIBUTION */
298 /* chi2(n) is equivalent to gamma(n/2,2) */
300 pdf_chi2(x,n) := pdf_gamma(x,n/2,2)$
302 cdf_chi2(x,n) := cdf_gamma(x,n/2,2)$
304 quantile_chi2(q,n) := quantile_gamma(q,n/2,2)$
306 mean_chi2(n) := mean_gamma(n/2,2)$
308 var_chi2(n) := var_gamma(n/2,2)$
310 std_chi2(n) := std_gamma(n/2,2)$
312 skewness_chi2(n) := skewness_gamma(n/2,2)$
314 kurtosis_chi2(n) := kurtosis_gamma(n/2,2)$
316 random_chi2(n,[num]) :=
317 if maybe(n > 0) = false
318 then error("random_chi2: degrees of freedom must be greater than zero")
319 else block([no, fn: float(n)],
321 then error("random_chi2: need numeric arguments for approximate procedure"),
322 if length(num) = 0 then no: 0 else no: num[1],
323 if integerp(no) and no >= 0
325 else error("random_chi2: check sample size")) $
329 /* NONCENTRAL CHI-SQUARE DISTRIBUTION */
331 /* R: dchisq(x,n,ncp) */
332 pdf_noncentral_chi2(x,n,ncp) :=
333 if maybe(n > 0) = false
334 then error("pdf_noncentral_chi2: degrees of freedom must be greater than 0")
335 elseif sign(ncp) = 'zero
337 else 1/2 * exp(-(x+ncp)/2) * (x/ncp)^(n/4-1/2) * bessel_i(n/2-1, sqrt(x*ncp)) * unit_step(x) $
339 /* R: pchisq(x,n,ncp) */
340 cdf_noncentral_chi2(x,n,ncp) :=
341 if maybe(n > 0) = false
342 then error("cdf_noncentral_chi2: degrees of freedom must be greater than 0")
343 elseif float(ncp)=0.0
345 elseif maybe(x >= 0) = false
347 else /* need numerical approximation */
348 block([fx: float(x), fn: float(n), fncp: float(ncp)],
349 if numberp(fx) and numberp(fn) and numberp(fncp)
350 then ?cdfnchi2(fx, fn, fncp,
351 1e-12, /* maximum error */
352 1.4210854715202e-14, /* 8*DBL_EPSILON */
353 1000000.0) /* number of iterations */
354 else error("cdf_noncentral_chi2: need numeric arguments for approximate procedure") ) $
356 /* R: qchisq(q,n,ncp) */
357 quantile_noncentral_chi2(q,n,ncp) :=
358 if maybe(n > 0 and q >= 0 and q <= 1) = false
359 then error("quantile_noncentral_chi2: degrees of freedom must be greater than 0")
360 else /* numerical approximation */
361 block([fq: float(q), fn: float(n), fncp: float(ncp)],
362 if numberp(fq) and numberp(fn) and numberp(fncp)
363 then (if fq = 0.0 then return(0),
364 if fq = 1.0 then return('inf),
365 if fncp=0.0 then return(quantile_chi2(q,n)),
366 ?qnchi2(fq, fn, fncp))
367 else error("quantile_noncentral_chi2: need numeric arguments for approximate procedure")) $
369 mean_noncentral_chi2(n,ncp) :=
370 if maybe(n > 0) = false
371 then error("mean_noncentral_chi2: degrees of freedom must be greater than 0")
374 var_noncentral_chi2(n,ncp) :=
375 if maybe(n > 0) = false
376 then error("var_noncentral_chi2: degrees of freedom must be greater than 0")
379 std_noncentral_chi2(n,ncp) := sqrt(var_noncentral_chi2(n,ncp)) $
381 skewness_noncentral_chi2(n,ncp) :=
382 if maybe(n > 0) = false
383 then error("skewness_noncentral_chi2: degrees of freedom must be greater than 0")
384 else 2^(3/2) * (n+3*ncp) /(n+2*ncp)^(3/2) $
386 kurtosis_noncentral_chi2(n,ncp) :=
387 if maybe(n > 0) = false
388 then error("kurtosis_noncentral_chi2: degrees of freedom must be greater than 0")
389 else 12 * (n+4*ncp) /(n+2*ncp)^2 $
391 random_noncentral_chi2(n,ncp,[num]) :=
392 if maybe(n > 0) = false
393 then error("random_noncentral_chi2: degrees of freedom must be greater than 0")
394 else block([no, fn: float(n), fncp: float(ncp)],
395 if not numberp(fn) or not numberp(fncp)
396 then error("random_noncentral_chi2: need numeric arguments for approximate procedure"),
397 if length(num) = 0 then no: 0 else no: num[1],
398 if integerp(no) and no >= 0
399 then ?rndnchi2(fn,fncp,no)
400 else error("random_noncentral_chi2: check sample size")) $
407 if maybe(n > 0 and m > 0) = false
408 then error("pdf_f: degrees of freedom must be greater than 0")
409 else gamma((m+n)/2)*(m/n)^(m/2)*x^(m/2-1)*(1+m*x/n)^(-(m+n)/2) / (gamma(m/2)*gamma(n/2)) * unit_step(x) $
413 if maybe(n > 0 and m > 0) = false
414 then error("cdf_f: degrees of freedom must be greater than 0")
415 else (1 - beta_incomplete_regularized(n/2, m/2, n/(n+m*x))) * unit_step(x) $
419 if maybe(n > 0 and m > 0 and q >= 0 and q <= 1) = false
420 then error("quantile_f: check input parameters")
421 else block([fq: float(q), fn: float(n), fm: float(m)],
422 if numberp(fq) and numberp(fn) and numberp(fm)
423 then(if fq = 0.0 then return(0),
424 if fq = 1.0 then return('inf),
425 fn * (1 / ?iibeta(1-fq, fn/2, fm/2) - 1) / fm)
426 else error("quantile_f: need numeric arguments for approximate procedure")) $
429 if maybe(n > 2 and m > 0) = false
430 then error("mean_f: degrees of freedom must be m>0 and n>2")
434 if maybe(n > 4 and m > 0) = false
435 then error("var_f: degrees of freedom must be m>0 and n>4")
436 else 2*n*n*(m+n-2)/(m*(n-2)*(n-2)*(n-4)) $
438 std_f(m,n) := sqrt(var_f(m,n)) $
441 if maybe(n > 6 and m > 0) = false
442 then error("skewness_f: degrees of freedom must be m>0 and n>6")
443 else (2*m+n-2)*sqrt(8*(n-4))/(sqrt(m*(m+n-2))*(n-6)) $
446 if maybe(n > 8 and m > 0) = false
447 then error("kurtosis_f: degrees of freedom must be m>0 and n>8")
448 else 12*((n-2)*(n-2)*(n-4)+m*(m+n-2)*(5*n-22)) / (m*(n-6)*(n-8)*(m+n-2)) $
450 random_f(m,n,[num]) :=
451 if maybe(n > 0 and m > 0) = false
452 then error("pdf_f: degrees of freedom must be greater than 0")
453 else block([no, fm: float(m), fn: float(n)],
454 if not numberp(fn) or not numberp(fm)
455 then error("random_f: need numeric arguments for approximate procedure"),
456 if length(num) = 0 then no: 0 else no: num[1],
457 if integerp(no) and no >= 0
459 else error("random_f: check sample size")) $
463 /* EXPONENTIAL DISTRIBUTION */
464 /* exp(m) equivalent to Weibull(1,1/m) */
466 pdf_exp(x,m) := pdf_weibull(x,1,1/m)$
468 cdf_exp(x,m) := cdf_weibull(x,1,1/m)$
470 quantile_exp(q,m) := quantile_weibull(q,1,1/m)$
472 mean_exp(m) := mean_weibull(1,1/m)$
474 var_exp(m) := var_weibull(1,1/m)$
476 std_exp(m) := std_weibull(1,1/m)$
478 skewness_exp(m) := skewness_weibull(1,1/m)$
480 kurtosis_exp(m) := kurtosis_weibull(1,1/m)$
482 random_exp(m,[num]) :=
483 if maybe(m > 0) = false
484 then error("random_exp: rate must be greater than 0")
485 else block([no, fm: float(m)],
487 then error("random_exp: need numeric arguments for approximate procedure"),
488 if length(num) = 0 then no: 0 else no: num[1],
489 if integerp(no) and no >= 0
491 else error("random_exp: check sample size") ) $
495 /* LOGNORMAL DISTRIBUTION */
497 pdf_lognormal(x,m,s) :=
498 if maybe(s > 0) = false
499 then error("pdf_lognormal: parameter s must be greater than 0")
500 else exp(-(log(x)-m)^2/(2*s^2))/(sqrt(2*%pi)*s*x) * unit_step(x) $
502 cdf_lognormal(x,m,s) :=
503 if maybe(s > 0) = false
504 then error("cdf_lognormal: parameter s must be greater than 0")
505 else 1/2+erf((log(x)-m)/(s*sqrt(2)))/2 * unit_step(x) $
507 /* R: qlnorm(p,m,s)*/
508 quantile_lognormal(q,m,s) :=
509 if maybe(s > 0 and q >= 0 and q <= 1) = false
510 then error("quantile_lognormal: check input parameters")
513 elseif sign(q-1)='zero
515 else exp(m + sqrt(2)*s*inverse_erf(2*q-1)) $
517 mean_lognormal(m,s) :=
518 if maybe(s > 0) = false
519 then error("mean_lognormal: parameter s must be greater than 0")
522 var_lognormal(m,s) :=
523 if maybe(s > 0) = false
524 then error("var_lognormal: parameter s must be greater than 0")
525 else exp(2*m+s^2)*(exp(s^2)-1) $
527 std_lognormal(m,s) := sqrt(var_lognormal(m,s)) $
529 skewness_lognormal(m,s) :=
530 if maybe(s > 0) = false
531 then error("skewness_lognormal: parameter s must be greater than 0")
532 else (exp(s^2)+2)*sqrt(exp(s^2)-1) $
534 kurtosis_lognormal(m,s) :=
535 if maybe(s > 0) = false
536 then error("kurtosis_lognormal: parameter s must be greater than 0")
537 else exp(4*s^2)+2*exp(3*s^2)+3*exp(2*s^2)-3 $
539 random_lognormal(m,s,[num]) :=
540 if maybe(s > 0) = false
541 then error("random_lognormal: parameter s must be greater than 0")
543 if length(num) = 0 then no: 0 else no: num[1],
544 if integerp(no) and no >= 0
545 then exp(m + s * ?rndnormal(no))
546 else error("random_lognormal: check sample size") ) $
550 /* GAMMA DISTRIBUTION */
552 /* R: dgamma(x,a,1/b) */
554 if maybe(a > 0 and b > 0) = false
555 then error("pdf_gamma: parameters a and b must be greater than 0")
556 else x^(a-1)*exp(-x/b)/(b^a*gamma(a)) * unit_step(x) $
558 /* R: pgamma(x,a,1/b) */
560 if maybe(a > 0 and b > 0) = false
561 then error("cdf_gamma: parameters a and b must be greater than 0")
562 else (1 - gamma_incomplete_regularized(a,x/b)) * unit_step(x) $
564 /* R: qgamma(q,a,1/b) */
565 quantile_gamma(q,a,b) :=
566 if maybe(a > 0 and b >0 and q >= 0 and q <= 1) = false
567 then error("quantile_gamma: check input parameters")
570 elseif sign(q-1)='zero
572 else /* approximate procedure */
573 block([fq: float(q), fa: float(a)],
574 if numberp(fq) and numberp(fa)
575 then(if fq = 0.0 then return(0),
576 if fq = 1.0 then return('inf),
577 b * ?iigamma(fq, fa))
578 else error("quantile_gamma: need numeric arguments for approximate procedure")) $
581 if maybe(a > 0 and b > 0) = false
582 then error("mean_gamma: parameters a and b must be greater than 0")
586 if maybe(a > 0 and b > 0) = false
587 then error("var_gamma: parameters a and b must be greater than 0")
590 std_gamma(a,b) := sqrt(var_gamma(a,b)) $
592 skewness_gamma(a,b) :=
593 if maybe(a > 0 and b > 0) = false
594 then error("skewness_gamma: parameters a and b must be greater than 0")
597 kurtosis_gamma(a,b) :=
598 if maybe(a > 0 and b > 0) = false
599 then error("kurtosis_gamma: parameters a and b must be greater than 0")
602 random_gamma(a,b,[num]) :=
603 if maybe(a > 0 and b > 0) = false
604 then error("random_gamma: parameters a and b must be greater than 0")
605 else block([no, fa:float(a), fb:float(b)],
606 if not numberp(fa) or not numberp(fb)
607 then error("random_gamma: need numeric arguments for approximate procedure"),
608 if length(num) = 0 then no: 0 else no: num[1],
609 if integerp(no) and no >= 0
610 then ?rndgamma(fa,fb,no)
611 else error("random_gamma: check sample size") ) $
615 /* BETA DISTRIBUTION */
618 if maybe(a > 0 and b > 0) = false
619 then error("pdf_beta: parameters a and b must be greater than 0")
620 else x^(a-1)*(1-x)^(b-1)/beta(a,b)*(unit_step(x)-unit_step(x-1)) $
622 /* R: pbeta(x,a,b) */
624 if maybe(a > 0 and b > 0) = false
625 then error("cdf_beta: parameters a and b must be greater than 0")
626 else beta_incomplete_regularized(a,b,x) * (unit_step(x)-unit_step(x-1)) + unit_step(x-1)$
628 /* R: qbeta(q,a,b) */
629 quantile_beta(q,a,b) :=
630 if maybe(a > 0 and b >0 and q >= 0 and q <= 1) = false
631 then error("quantile_beta: check input parameters")
634 elseif sign(q-1)='zero
636 else block([fq: float(q), fa: float(a), fb: float(b)],
637 if numberp(fq) and numberp(fa) and numberp(fb)
638 then(if fq = 0.0 then return(0),
639 if fq = 1.0 then return(1),
641 else error("quantile_beta: need numeric arguments for approximate procedure")) $
644 if maybe(a > 0 and b > 0) = false
645 then error("mean_beta: parameters a and b must be greater than 0")
649 if maybe(a > 0 and b > 0) = false
650 then error("var_beta: parameters a and b must be greater than 0")
651 else a*b/((a+b)^2*(a+b+1)) $
653 std_beta(a,b) := sqrt(var_beta(a,b)) $
655 skewness_beta(a,b) :=
656 if maybe(a > 0 and b > 0) = false
657 then error("skewness_beta: parameters a and b must be greater than 0")
658 else 2*(b-a)*sqrt(a+b+1)/(sqrt(a*b)*(a+b+2)) $
660 kurtosis_beta(a,b) :=
661 if maybe(a > 0 and b > 0) = false
662 then error("kurtosis_beta: parameters a and b must be greater than 0")
663 else 3*(a+b+1)*(2*(a+b)^2+a*b*(a+b-6)) / (a*b*(a+b+2)*(a+b+3)) - 3 $
665 random_beta(a,b,[num]) :=
666 if maybe(a > 0 and b > 0) = false
667 then error("random_beta: parameters a and b must be greater than 0")
668 else block([no, fa:float(a), fb:float(b)],
669 if not numberp(fa) or not numberp(fb)
670 then error("random_beta: need numeric arguments for approximate procedure"),
671 if length(num) = 0 then no: 0 else no: num[1],
672 if integerp(no) and no >= 0
673 then ?rndbeta(fa,fb,no)
674 else error("random_beta: check sample size") ) $
678 /* CONTINUOUS UNIFORM DISTRIBUTION */
680 pdf_continuous_uniform(x,a,b) :=
681 if maybe(b - a > 0) = false
682 then error("pdf_continuous_uniform: parameter b must be greater than a")
683 else (unit_step(x-a)-unit_step(x-b))/(b-a) $
685 cdf_continuous_uniform(x,a,b) :=
686 if maybe(b - a > 0) = false
687 then error("cdf_continuous_uniform: parameter b must be greater than a")
688 else (x-a)/(b-a)*(unit_step(x-a)-unit_step(x-b)) + unit_step(x-b) $
690 quantile_continuous_uniform(q,a,b) :=
691 if maybe(b - a > 0 and q >= 0 and q <= 1) = false
692 then error("quantile_continuous_uniform: check input parameters")
695 elseif sign(q-1)='zero
699 mean_continuous_uniform(a,b) :=
700 if maybe(b - a > 0) = false
701 then error("mean_continuous_uniform: parameter b must be greater than a")
704 var_continuous_uniform(a,b) :=
705 if maybe(b - a > 0) = false
706 then error("var_continuous_uniform: parameter b must be greater than a")
709 std_continuous_uniform(a,b) := sqrt(var_continuous_uniform(a,b))$
711 skewness_continuous_uniform(a,b) :=
712 if maybe(b - a > 0) = false
713 then error("skewness_continuous_uniform: parameter b must be greater than a")
716 kurtosis_continuous_uniform(a,b) :=
717 if maybe(b - a > 0) = false
718 then error("kurtosis_continuous_uniform: parameter b must be greater than a")
721 /* This is a direct application of the maxima */
722 /* random function. Make describe(random) for details */
723 random_continuous_uniform(a,b,[num]) :=
724 if maybe(b - a > 0) = false
725 then error("random_continuous_uniform: parameter b must be greater than a")
726 else block([no, f:float(b-a), listarith:true],
728 then error("random_continuous_uniform: need numeric arguments for approximate procedure"),
729 if length(num) = 0 then no: 0 else no: num[1],
733 else a + makelist(random(f),k,no)
734 else error("random_continuous_uniform: check sample size") ) $
738 /* LOGISTIC DISTRIBUTION */
740 pdf_logistic(x,a,b) :=
741 if maybe(b > 0) = false
742 then error("pdf_logistic: parameter b must be greater than 0")
743 else block([y: exp((a-x)/b)], y/(b*(1+y)^2)) $
745 cdf_logistic(x,a,b) :=
746 if maybe(b > 0) = false
747 then error("cdf_logistic: parameter b must be greater than 0")
748 else 1/(1+exp((a-x)/b)) $
750 quantile_logistic(q,a,b) :=
751 if maybe(b > 0 and q >= 0 and q <= 1) = false
752 then error("quantile_logistic: check input parameters")
755 elseif sign(q-1)='zero
757 else a - b * log(1/q-1) $
759 mean_logistic(a,b) :=
760 if maybe(b > 0) = false
761 then error("mean_logistic: parameter b must be greater than 0")
765 if maybe(b > 0) = false
766 then error("var_logistic: parameter b must be greater than 0")
769 std_logistic(a,b) := sqrt(var_logistic(a,b)) $
771 skewness_logistic(a,b) :=
772 if maybe(b > 0) = false
773 then error("skewness_logistic: parameter b must be greater than 0")
776 kurtosis_logistic(a,b) :=
777 if maybe(b > 0) = false
778 then error("kurtosis_logistic: parameter b must be greater than 0")
782 random_logistic(a,b,[num]) :=
783 if maybe(b > 0) = false
784 then error("random_logistic: parameter b must be greater than 0")
785 else block([no, fa:float(a), fb:float(b)],
786 if not numberp(fa) or not numberp(fb)
787 then error("random_logistic: need numeric arguments for approximate procedure"),
788 if length(num) = 0 then no: 0 else no: num[1],
791 then a - b * log(1/random(1.0) - 1.0)
792 else a - b * map('log,1/makelist(random(1.0),k,no) - 1.0)
793 else error("random_logistic: check sample size")) $
797 /* PARETO DISTRIBUTION */
800 if maybe(a > 0 and b > 0) = false
801 then error("pdf_pareto: parameters a and b must be greater than 0")
802 else a*b^a*x^(-a-1) * unit_step(x-b) $
805 if maybe(a > 0 and b > 0) = false
806 then error("pdf_pareto: parameters a and b must be greater than 0")
807 else (1-(b/x)^a) * unit_step(x-b) $
809 quantile_pareto(q,a,b) :=
810 if maybe(a > 0 and b > 0 and q >= 0 and q <= 1) = false
811 then error("quantile_pareto: check input parameters")
814 elseif sign(q-1)='zero
816 else b / (1-q)^(1/a) $
819 if maybe(a > 1) = false
820 then error("mean_pareto: parameter a must be greater than 1")
821 elseif maybe(b > 0) = false
822 then error("mean_pareto: parameter b must be greater than 0")
826 if maybe(a > 2) = false
827 then error("var_pareto: parameter a must be greater than 2")
828 elseif maybe(b > 0) = false
829 then error("var_pareto: parameter b must be greater than 0")
830 else a*b*b/((a-2)*(a-1)^2) $
833 if maybe(a > 2) = false
834 then error("std_pareto: parameter a must be greater than 2")
835 elseif maybe(b > 0) = false
836 then error("std_pareto: parameter b must be greater than 0")
837 else b*sqrt(a/(a-2))/(a-1) $
839 skewness_pareto(a,b) :=
840 if maybe(a > 3) = false
841 then error("skewness_pareto: parameter a must be greater than 3")
842 elseif maybe(b > 0) = false
843 then error("skewness_pareto: parameter b must be greater than 0")
844 else 2*(a+1)*sqrt(a-2)/((a-3)*sqrt(a)) $
846 kurtosis_pareto(a,b) :=
847 if maybe(a > 4) = false
848 then error("kurtosis_pareto: parameter a must be greater than 4")
849 elseif maybe(b > 0) = false
850 then error("kurtosis_pareto: parameter b must be greater than 0")
851 else (6*(a^3+a^2-6*a-2)) / (a*(a^2-7*a+12)) - 3 $
854 random_pareto(a,b,[num]) :=
855 if maybe(a > 0 and b > 0) = false
856 then error("random_pareto: parameters a and b must be greater than 0")
857 else block([no, fa:float(a), fb:float(b)],
858 if not numberp(fa) or not numberp(fb)
859 then error("random_pareto: need numeric arguments for approximate procedure"),
860 if length(num) = 0 then no: 0 else no: num[1],
863 then b / (1-random(1.0))^(1.0/a)
864 else b / (1-makelist(random(1.0),k,1,no))^(1.0/a)
865 else error("random_pareto: check sample size")) $
869 /* WEIBULL DISTRIBUTION */
871 pdf_weibull(x,a,b) :=
872 if maybe(a > 0 and b > 0) = false
873 then error("pdf_weibull: parameters a and b must be greater than 0")
874 else a/b*(x/b)^(a-1)*exp(-(x/b)^a) * unit_step(x) $
876 cdf_weibull(x,a,b) :=
877 if maybe(a > 0 and b > 0) = false
878 then error("cdf_weibull: parameters a and b must be greater than 0")
879 else (1-exp(-(x/b)^a)) * unit_step(x) $
881 /* R: qweibull(q,a,b) */
882 quantile_weibull(q,a,b) :=
883 if maybe(a > 0 and b > 0 and q >= 0 and q <= 1) = false
884 then error("quantile_weibull: check input parameters")
887 elseif sign(q-1)='zero
889 else b * (-log(1-q))^(1/a) $
892 if maybe(a > 0 and b > 0) = false
893 then error("mean_weibull: parameters a and b must be greater than 0")
894 else gamma(1/a+1)*b $
897 if maybe(a > 0 and b > 0) = false
898 then error("var_weibull: parameters a and b must be greater than 0")
899 else (gamma(2/a+1)-gamma(1/a+1)^2)*b^2 $
902 if maybe(a > 0 and b > 0) = false
903 then error("std_weibull: parameters a and b must be greater than 0")
904 else sqrt((gamma(2/a+1)-gamma(1/a+1)^2))*b $
906 skewness_weibull(a,b) :=
907 if maybe(a > 0 and b > 0) = false
908 then error("skewness_weibull: parameters a and b must be greater than 0")
909 else (gamma(3/a+1)-3*gamma(1/a+1)*gamma(2/a+1)+2*gamma(1/a+1)^3) /
910 (gamma(2/a+1)-gamma(1/a+1)^2)^(3/2) $
912 kurtosis_weibull(a,b) :=
913 if maybe(a > 0 and b > 0) = false
914 then error("kurtosis_weibull: parameters a and b must be greater than 0")
915 else (gamma(4/a+1)-4*gamma(1/a+1)*gamma(3/a+1)+
916 6*gamma(1/a+1)^2*gamma(2/a+1)-3*gamma(1/a+1)^4) /
917 (gamma(2/a+1)-gamma(1/a+1)^2)^2 - 3 $
920 random_weibull(a,b,[num]) :=
921 if maybe(a > 0 and b > 0) = false
922 then error("random_weibull: parameters a and b must be greater than 0")
923 else block([no, fa:float(a), fb:float(b)],
924 if not numberp(fa) or not numberp(fb)
925 then error("random_weibull: need numeric arguments for approximate procedure"),
926 if length(num) = 0 then no: 0 else no: num[1],
929 then b * (-log(random(1.0)))^(1.0/a)
930 else b * (-map('log,makelist(random(1.0),k,1,no)))^(1.0/a)
931 else error("random_weibull: check sample size")) $
935 /* RAYLEIGH DISTRIBUTION */
936 /* Rayleigh(b) is equivalent to Weibull(2,1/b) */
938 pdf_rayleigh(x,b):=pdf_weibull(x,2,1/b)$
940 cdf_rayleigh(x,b):=cdf_weibull(x,2,1/b)$
942 quantile_rayleigh(q,b):=quantile_weibull(q,2,1/b)$
944 mean_rayleigh(b):=mean_weibull(2,1/b)$
946 var_rayleigh(b):=var_weibull(2,1/b)$
948 std_rayleigh(b):=std_weibull(2,1/b)$
950 skewness_rayleigh(b):=skewness_weibull(2,1/b)$
952 kurtosis_rayleigh(b):=kurtosis_weibull(2,1/b)$
955 random_rayleigh(b,[num]) :=
956 if maybe(b > 0) = false
957 then error("random_rayleigh: parameter b must be greater than 0")
958 else block([no, fb:float(b)],
960 then error("random_rayleigh: need numeric argument for approximate procedure"),
961 if length(num) = 0 then no: 0 else no: num[1],
964 then sqrt(-log(random(1.0))) / b
965 else sqrt(-map('log,makelist(random(1.0),k,1,no))) / b
966 else error("random_rayleigh: check sample size")) $
970 /* LAPLACE DISTRIBUTION */
972 pdf_laplace(x,a,b) :=
973 if maybe(b > 0) = false
974 then error("pdf_laplace: parameter b must be greater than 0")
975 else exp(-abs(x-a)/b)/(2*b) $
977 cdf_laplace(x,a,b) :=
978 if maybe(b > 0) = false
979 then error("pdf_laplace: parameter b must be greater than 0")
980 else (1+signum(x-a)-signum(x-a)*exp(-abs(x-a)/b)) / 2 $
982 quantile_laplace(q,a,b) :=
983 if maybe(b > 0 and q >= 0 and q <= 1) = false
984 then error("quantile_laplace: check input parameters")
987 elseif sign(q-1)='zero
989 else a - b * signum(2*q-1) * log(1 - signum(2*q-1) * (2*q-1))$
992 if maybe(b > 0) = false
993 then error("mean_laplace: parameter b must be greater than 0")
997 if maybe(b > 0) = false
998 then error("var_laplace: parameter b must be greater than 0")
1002 if maybe(b > 0) = false
1003 then error("std_laplace: parameter b must be greater than 0")
1006 skewness_laplace(a,b) :=
1007 if maybe(b > 0) = false
1008 then error("skewness_laplace: parameter b must be greater than 0")
1011 kurtosis_laplace(a,b) :=
1012 if maybe(b > 0) = false
1013 then error("kurtosis_laplace: parameter b must be greater than 0")
1016 /* inverse method */
1017 random_laplace(a,b,[num]) :=
1018 if maybe(b > 0) = false
1019 then error("random_laplace: parameter b must be greater than 0")
1020 else block([no, fa:float(a), fb:float(b)],
1021 if not numberp(fa) or not numberp(fb)
1022 then error("random_laplace: need numeric arguments for approximate procedure"),
1023 if length(num) = 0 then no: 0 else no: num[1],
1026 then quantile_laplace(random(1.0),a,b)
1027 else makelist(quantile_laplace(random(1.0),a,b),k,1,no)
1028 else error("random_laplace: check sample size")) $
1032 /* CAUCHY (OR LORENTZ) DISTRIBUTION */
1034 pdf_cauchy(x,a,b) :=
1035 if maybe(b > 0) = false
1036 then error("pdf_cauchy: parameter b must be greater than 0")
1037 else b/(%pi*((x-a)^2+b^2)) $
1039 cdf_cauchy(x,a,b) :=
1040 if maybe(b > 0) = false
1041 then error("pdf_cauchy: parameter b must be greater than 0")
1042 else 1/2+atan((x-a)/b)/%pi $
1044 quantile_cauchy(q,a,b) :=
1045 if maybe(b > 0 and q >= 0 and q <= 1) = false
1046 then error("quantile_cauchy: check input parameters")
1047 elseif sign(q)='zero
1049 elseif sign(q-1)='zero
1051 else a + b * tan(%pi * (q - 1/2)) $
1053 /* Note: integrals for Cauchy moments are divergent */
1055 /* inverse method */
1056 random_cauchy(a,b,[num]) :=
1057 if maybe(b > 0) = false
1058 then error("random_cauchy: parameter b must be greater than 0")
1059 else block([no, fa:float(a), fb:float(b)],
1060 if not numberp(fa) or not numberp(fb)
1061 then error("random_cauchy: need numeric arguments for approximate procedure"),
1062 if length(num) = 0 then no: 0 else no: num[1],
1065 then tan (float(%pi) * (random(1.0)-0.5))*fb+fa
1066 else fa + fb * map('tan, 3.141592653589793 * (makelist(random(1.0),k,1,no)-0.5))
1067 else error("random_cauchy: check sample size")) $
1071 /* GUMBEL (OR EXTREME VALUE) DISTRIBUTION */
1073 pdf_gumbel(x,a,b) :=
1074 if maybe(b > 0) = false
1075 then error("pdf_gumbel: parameter b must be greater than 0")
1076 else exp((a-x)/b-exp((a-x)/b))/b $
1078 cdf_gumbel(x,a,b) :=
1079 if maybe(b > 0) = false
1080 then error("cdf_gumbel: parameter b must be greater than 0")
1081 else exp(-exp((a-x)/b)) $
1083 quantile_gumbel(q,a,b) :=
1084 if maybe(b > 0 and q >= 0 and q <= 1) = false
1085 then error("quantile_gumbel: check input parameters")
1086 elseif sign(q)='zero
1088 elseif sign(q-1)='zero
1090 else a - b * log(-log(q)) $
1093 if maybe(b > 0) = false
1094 then error("mean_gumbel: parameter b must be greater than 0")
1095 else /* %gamma=Euler-Mascheroni constant */
1099 if maybe(b > 0) = false
1100 then error("var_gumbel: parameter b must be greater than 0")
1101 else b*b*%pi*%pi/6 $
1104 if maybe(b > 0) = false
1105 then error("std_gumbel: parameter b must be greater than 0")
1106 else b*%pi/sqrt(6) $
1108 skewness_gumbel(a,b) :=
1109 if maybe(b > 0) = false
1110 then error("std_gumbel: parameter b must be greater than 0")
1111 else 12*sqrt(6)*zeta(3)/%pi^3 $
1113 kurtosis_gumbel(a,b) :=
1114 if maybe(b > 0) = false
1115 then error("kurtosis_gumbel: parameter b must be greater than 0")
1118 /* inverse method */
1119 random_gumbel(a,b,[num]) :=
1120 if maybe(b > 0) = false
1121 then error("random_gumbel: parameter b must be greater than 0")
1122 else block([no, fa:float(a), fb:float(b)],
1123 if not numberp(fa) or not numberp(fb)
1124 then error("random_gumbel: need numeric arguments for approximate procedure"),
1125 if length(num) = 0 then no: 0 else no: num[1],
1128 then a - b * log(-log(random(1.0)))
1129 else a - b * map('log,-map('log,makelist(random(1.0),k,1,no)))
1130 else error("random_gumbel: check sample size")) $
1134 /* BINOMIAL DISTRIBUTION */
1136 /* R: dbinom(x,n,p) */
1137 pdf_binomial(x,n,p) :=
1138 if maybe(p >= 0 and p <= 1) = false
1139 then error("pdf_binomial: p must be a probability")
1140 /* when n is not an integer, R returns NaN, we throw an error */
1141 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1142 then error("pdf_binomial: n must be a positive integer")
1143 elseif sign(x) = 'neg or sign(n-x) = 'neg or numberp(x) and x-floor(x) > 0
1145 elseif sign(p) = 'zero
1146 then kron_delta(x,0)
1147 elseif sign(1-p) = 'zero
1148 then kron_delta(x,n)
1149 else binomial(n,x)*p^x*(1-p)^(n-x) $
1151 /* R: pbinom(x,n,p) */
1152 cdf_binomial(x,n,p):=
1153 if maybe(p >= 0 and p <= 1) = false
1154 then error("cdf_binomial: p must be a probability")
1155 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1156 then error("cdf_binomial: n must be a positive integer")
1157 elseif sign(x) = 'neg
1159 elseif member(sign(x-n),['pos,'pz,'zero])
1161 else beta_incomplete_regularized(n-floor(x),floor(x)+1,1-p) $
1163 /* R: qbinom(q,n,p) */
1164 quantile_binomial(q,n,p):=
1165 if maybe(p >= 0 and p <= 1) = false
1166 then error("quantile_binomial: p must be a probability")
1167 elseif maybe(q >= 0 and q <= 1) = false
1168 then error("quantile_binomial: q must be a probability")
1169 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1170 then error("quantile_binomial: n must be a positive integer")
1171 elseif sign(q) = 'zero
1173 elseif sign(1-q) = 'zero
1175 elseif float(q) <= float((1-p)^n)
1177 elseif numberp(float(q)) and numberp(float(n)) and numberp(float(p))
1178 then /* partition method */
1179 block([a:0, b:n, m],
1182 if cdf_binomial(m,n,p) < q
1186 else error("quantile_binomial: need numeric arguments for approximate procedure") $
1188 mean_binomial(n,p) :=
1189 if maybe(p >= 0 and p <= 1) = false
1190 then error("mean_binomial: p must be a probability")
1191 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1192 then error("mean_binomial: n must be a positive integer")
1195 var_binomial(n,p) :=
1196 if maybe(p >= 0 and p <= 1) = false
1197 then error("var_binomial: p must be a probability")
1198 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1199 then error("var_binomial: n must be a positive integer")
1202 std_binomial(n,p) :=
1203 if maybe(p >= 0 and p <= 1) = false
1204 then error("std_binomial: p must be a probability")
1205 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1206 then error("std_binomial: n must be a positive integer")
1207 else sqrt(n*p*(1-p)) $
1209 skewness_binomial(n,p) :=
1210 if maybe(p >= 0 and p <= 1) = false
1211 then error("std_binomial: p must be a probability")
1212 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1213 then error("std_binomial: n must be a positive integer")
1214 else (1-2*p)/sqrt(n*p*(1-p)) $
1216 kurtosis_binomial(n,p) :=
1217 if maybe(p >= 0 and p <= 1) = false
1218 then error("kurtosis_binomial: p must be a probability")
1219 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1220 then error("kurtosis_binomial: n must be a positive integer")
1221 else (1-6*p*(1-p))/(n*p*(1-p)) $
1223 random_binomial(n,p,[num]) :=
1224 if maybe(p >= 0 and p <= 1) = false
1225 then error("random_binomial: p must be a probability")
1226 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1227 then error("random_binomial: n must be a positive integer")
1228 else block([no, fn:float(n), fp:float(p)],
1229 if not numberp(fn) or not numberp(fp)
1230 then error("random_binomial: need numeric arguments for approximate procedure"),
1231 if length(num) = 0 then no: 0 else no: num[1],
1233 then ?rndbinomial(n,fp,no)
1234 else error("random_binomial: check sample size")) $
1238 /* POISSON DISTRIBUTION */
1242 if maybe(m >= 0) = false
1243 then error("pdf_poisson: m must be positive")
1244 elseif sign(m) = 'zero
1245 then kron_delta(0,x)
1246 elseif sign(x) = 'neg or numberp(x) and x-floor(x) > 0
1248 else exp(-m)*m^x/x! $
1252 if maybe(m >= 0) = false
1253 then error("cdf_poisson: m must be positive")
1254 elseif sign(x) = 'neg
1256 else gamma_incomplete_regularized(floor(x)+1, m) $
1259 quantile_poisson(q,m):=
1260 if maybe(m >= 0) = false
1261 then error("quantile_poisson: m must be positive")
1262 elseif maybe(q >= 0 and q <= 1) = false
1263 then error("quantile_poisson: q must be a probability")
1264 elseif sign(m)='zero
1266 elseif member(sign(q-exp(-m)),['nz,'neg,'zero])
1268 elseif sign(1-q)='zero
1270 elseif numberp(float(q)) and numberp(float(m))
1271 then /* partition method */
1272 block([a, b:1.0,mm],
1273 while (cdf_poisson(b,m) < q) do b : 2.0*b,
1277 if cdf_poisson(mm,m) < q
1281 else error("quantile_poisson: need numeric arguments for approximate procedure") $
1284 if maybe(m >= 0) = false
1285 then error("mean_poisson: m must be positive")
1289 if maybe(m >= 0) = false
1290 then error("var_poisson: m must be positive")
1294 if maybe(m >= 0) = false
1295 then error("std_poisson: m must be positive")
1298 skewness_poisson(m):=
1299 if maybe(m >= 0) = false
1300 then error("skewness_poisson: m must be positive")
1303 kurtosis_poisson(m):=
1304 if maybe(m >= 0) = false
1305 then error("kurtosis_poisson: m must be positive")
1308 random_poisson(m,[num]) :=
1309 if maybe(m >= 0) = false
1310 then error("random_poisson: m must be positive")
1311 else block([no, fm:float(m)],
1313 then error("random_poisson: need numeric argument for approximate procedure"),
1314 if length(num) = 0 then no: 0 else no: num[1],
1316 then ?rndpoisson(fm,no)
1317 else error("random_poisson: check sample size")) $
1321 /* BERNOULLI DISTRIBUTION */
1322 /* Bernoulli(p) is equivalent to binomial(1,p) */
1324 pdf_bernoulli(x,p) :=
1325 if maybe(p >= 0 and p <= 1) = false
1326 then error("pdf_bernoulli: p must be a probability")
1327 elseif sign(x) = 'neg or sign(1-x) = 'neg or numberp(x) and x-floor(x) > 0
1329 elseif sign(p) = 'zero
1330 then kron_delta(x,0)
1331 elseif sign(1-p) = 'zero
1332 then kron_delta(x,1)
1333 else p^x*(1-p)^(1-x) $
1335 cdf_bernoulli(x,p):= cdf_binomial(x,1,p)$
1337 quantile_bernoulli(q,p):= quantile_binomial(q,1,p)$
1339 mean_bernoulli(p):=mean_binomial(1,p)$
1341 var_bernoulli(p):=var_binomial(1,p)$
1343 std_bernoulli(p):=std_binomial(1,p)$
1345 skewness_bernoulli(p):=skewness_binomial(1,p)$
1347 kurtosis_bernoulli(p):=kurtosis_binomial(1,p)$
1349 /* This is a direct application of the maxima
1350 random function. Make describe(random) for details */
1351 random_bernoulli(p,[num]) :=
1352 if maybe(p >= 0 and p <= 1) = false
1353 then error("random_bernoulli: p must be a probability")
1354 else block([no, fp:float(p)],
1356 then error("random_bernoulli: need numeric argument for approximate procedure"),
1357 if length(num) = 0 then no: 0 else no: num[1],
1360 then if random(1.0)<=fp then 1 else 0
1361 else makelist(if random(1.0)<=fp then 1 else 0,k,1,no)
1362 else error("random_bernoulli: check sample size")) $
1366 /* GEOMETRIC (OR PASCAL) DISTRIBUTION */
1369 pdf_geometric(x,p) :=
1370 if maybe(p > 0 and p <= 1) = false
1371 then error("pdf_geometric: p must be a non zero probability")
1372 elseif sign(p-1) = 'zero
1373 then if sign(x) = 'zero then 1 else 0
1374 elseif sign(x) = 'neg or numberp(x) and x-floor(x) > 0
1379 cdf_geometric(x,p) :=
1380 if maybe(p > 0 and p <= 1) = false
1381 then error("cdf_geometric: p must be a non zero probability")
1382 elseif sign(p-1) = 'zero
1383 then if member(sign(x), ['zero, 'pos, 'pz]) then 1 else 0
1384 elseif sign(x) = 'neg
1386 else 1-(1-p)^(floor(x)+1) $
1389 quantile_geometric(q,p) :=
1390 if maybe(p > 0 and p <= 1) = false
1391 then error("quantile_geometric: p must be a non zero probability")
1392 elseif maybe(q >= 0 and q <= 1) = false
1393 then error("quantile_geometric: q must be a probability")
1394 elseif sign(q-1) = 'zero
1396 elseif sign(q) = 'zero
1398 elseif sign(p-1) = 'zero
1400 else ceiling(log(1-q)/log(1-p)-1) $
1402 mean_geometric(p) :=
1403 if maybe(p > 0 and p <= 1) = false
1404 then error("mean_geometric: p must be a non zero probability")
1408 if maybe(p > 0 and p <= 1) = false
1409 then error("var_geometric: p must be a non zero probability")
1413 if maybe(p > 0 and p <= 1) = false
1414 then error("std_geometric: p must be a non zero probability")
1417 skewness_geometric(p) :=
1418 if maybe(p > 0 and p <= 1) = false
1419 then error("skewness_geometric: p must be a non zero probability")
1420 else (2-p)/sqrt(1-p) $
1422 kurtosis_geometric(p) :=
1423 if maybe(p > 0 and p <= 1) = false
1424 then error("kurtosis_geometric: p must be a non zero probability")
1425 else (p^2+6-6*p)/(1-p) $
1427 random_geometric(p,[num]) :=
1428 if maybe(p > 0 and p <= 1) = false
1429 then error("random_geometric: p must be a non zero probability")
1430 else block([no, fp:float(p)],
1432 then error("random_geometric: need numeric argument for approximate procedure"),
1433 if length(num) = 0 then no: 0 else no: num[1],
1436 else error("random_geometric: check sample size")) $
1440 /* DISCRETE UNIFORM DISTRIBUTION */
1442 pdf_discrete_uniform(x,n) :=
1443 if maybe(n > 0) = false or numberp(n) and n-floor(n) > 0
1444 then error("pdf_discrete_uniform: n must be a positive integer")
1445 elseif sign(x-1) = 'neg or sign(n-x) = 'neg or numberp(x) and x-floor(x) > 0
1449 cdf_discrete_uniform(x,n) :=
1450 if maybe(n > 0) = false or numberp(n) and n-floor(n) > 0
1451 then error("cdf_discrete_uniform: n must be a positive integer")
1452 elseif sign(x-1) = 'neg
1454 elseif member(sign(x-n), ['pos,'zero, 'pz])
1458 quantile_discrete_uniform(q,n) :=
1459 if maybe(n > 0) = false or numberp(n) and n-floor(n) > 0
1460 then error("cdf_discrete_uniform: n must be a positive integer")
1461 elseif maybe(q >= 0 and q <= 1) = false
1462 then error("quantile_discrete_uniform: q must be a probability")
1463 elseif sign(q-1) = 'zero
1465 elseif sign(q) = 'zero
1469 mean_discrete_uniform(n) :=
1470 if maybe(n > 0) = false or numberp(n) and n-floor(n) > 0
1471 then error("mean_discrete_uniform: n must be a positive integer")
1474 var_discrete_uniform(n) :=
1475 if maybe(n > 0) = false or numberp(n) and n-floor(n) > 0
1476 then error("var_discrete_uniform: n must be a positive integer")
1479 std_discrete_uniform(n) :=
1480 if maybe(n > 0) = false or numberp(n) and n-floor(n) > 0
1481 then error("std_discrete_uniform: n must be a positive integer")
1482 else sqrt((n^2-1)/12) $
1484 skewness_discrete_uniform(n) :=
1485 if maybe(n > 0) = false or numberp(n) and n-floor(n) > 0
1486 then error("skewness_discrete_uniform: n must be a positive integer")
1489 kurtosis_discrete_uniform(n) :=
1490 if maybe(n > 0) = false or numberp(n) and n-floor(n) > 0
1491 then error("kurtosis_discrete_uniform: n must be a positive integer")
1492 else -6/5-12/(5*(n^2-1)) $
1494 /* This is a direct application of the maxima
1495 random function. Make describe(random) for details */
1496 random_discrete_uniform(n,[num]) :=
1497 if maybe(n > 0) = false or numberp(n) and n-floor(n) > 0
1498 then error("random_discrete_uniform: n must be a positive integer")
1499 else block([no, fn:float(n)],
1501 then error("random_discrete_uniform: need numeric argument for approximate procedure"),
1502 if length(num) = 0 then no: 0 else no: num[1],
1506 else 1+makelist(random(n),k,1,no)
1507 else error("random_discrete_uniform: check sample size")) $
1511 /* HYPERGEOMETRIC DISTRIBUTION */
1513 /* R: dhyper(x, n1, n2, n) */
1514 pdf_hypergeometric(x,n1,n2,n) :=
1515 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1516 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1517 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1518 then error("pdf_hypergeometric: n1, n2, n must be a positive integers")
1519 elseif maybe (n <= n1 +n2) = false
1520 then error("pdf_hypergeometric: n must be less or equal than n1 + n2")
1521 elseif sign(x-max(0,n-n2))='neg or sign(min(n1,n)-x)='neg or numberp(x) and x-floor(x) > 0
1523 else binomial(n1,x)*binomial(n2,n-x)/binomial(n1+n2,n) $
1525 /* R: phyper(x, n1, n2, n) */
1526 cdf_hypergeometric(x,n1,n2,n) :=
1527 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1528 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1529 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1530 then error("pdf_hypergeometric: n1, n2, n must be a positive integers")
1531 elseif maybe (n <= n1 +n2) = false
1532 then error("cdf_hypergeometric: n must be less or equal than n1 + n2")
1533 elseif sign(x-max(0,n-n2))='neg
1535 elseif member(sign(min(n1,n)-x),['neg,'zero,'nz])
1537 else sum(binomial(n1,k)*binomial(n2,n-k) / binomial(n1+n2,n),k,0,floor(x)) $
1539 quantile_hypergeometric(q, n1, n2, n) :=
1540 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1541 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1542 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1543 then error("quantile_hypergeometric: n1, n2, n must be a positive integers")
1544 elseif maybe (n <= n1 +n2) = false
1545 then error("quantile_hypergeometric: n must be less or equal than n1 + n2")
1546 elseif maybe(q >= 0 and q <= 1) = false
1547 then error("quantile_hypergeometric: q must be a probability")
1548 elseif sign(q-1) = 'zero
1550 elseif member(sign(q - pdf_hypergeometric(max(0, n-n2),n1,n2,n)), ['neg,'zero, 'nz])
1552 elseif numberp(float(q)) and numberp(float(n1)) and numberp(float(n2)) and numberp(float(n))
1553 then /* partition method */
1554 block([a: max(0, n-n2), b: min(n1,n),m],
1556 m: floor(0.5*(a+b)),
1557 if cdf_hypergeometric(m,n1,n2,n) < q
1561 else error("quantile_hypergeometric: need numeric arguments for approximate procedure") $
1563 mean_hypergeometric(n1,n2,n) :=
1564 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1565 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1566 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1567 then error("mean_hypergeometric: n1, n2, n must be a positive integers")
1568 elseif maybe (n <= n1 +n2) = false
1569 then error("mean_hypergeometric: n must be less or equal than n1 + n2")
1572 var_hypergeometric(n1,n2,n) :=
1573 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1574 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1575 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1576 then error("var_hypergeometric: n1, n2, n must be a positive integers")
1577 elseif maybe (n <= n1 +n2) = false
1578 then error("var_hypergeometric: n must be less or equal than n1 + n2")
1579 else block([t:n1+n2], n*n1*n2*(t-n)/(t*t*(t-1))) $
1581 std_hypergeometric(n1,n2,n) :=
1582 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1583 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1584 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1585 then error("std_hypergeometric: n1, n2, n must be a positive integers")
1586 elseif maybe (n <= n1 +n2) = false
1587 then error("std_hypergeometric: n must be less or equal than n1 + n2")
1588 else block([t:n1+n2], sqrt(n*n1*n2*(t-n)/(t-1))/t) $
1590 skewness_hypergeometric(n1,n2,n) :=
1591 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1592 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1593 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1594 then error("skewness_hypergeometric: n1, n2, n must be a positive integers")
1595 elseif maybe (n <= n1 +n2) = false
1596 then error("skewness_hypergeometric: n must be less or equal than n1 + n2")
1597 else block([t:n1+n2], (n2-n1)*(t-2*n)*sqrt((t-1)/(n*n1*n2*(t-n)))/(t-2)) $
1599 kurtosis_hypergeometric(n1,n2,n) :=
1600 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1601 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1602 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1603 then error("kurtosis_hypergeometric: n1, n2, n must be a positive integers")
1604 elseif maybe (n <= n1 +n2) = false
1605 then error("kurtosis_hypergeometric: n must be less or equal than n1 + n2")
1606 else block([t:n1+n2],
1607 t*t*(t-1)/((t-2)*(t-3)*n*n1*n2*(t-n)) *
1608 (t*(t+1)-6*n*(t-n)+3*n1*n2*(t*t*(n-2)-t*n*n+6*n*(t-n))/t^2) - 3) $
1610 random_hypergeometric(n1,n2,n,[num]) :=
1611 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1612 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1613 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1614 then error("random_hypergeometric: n1, n2, n must be positive integers")
1615 elseif maybe (n <= n1 +n2) = false
1616 then error("random_hypergeometric: n must be less or equal than n1 + n2")
1618 if not integerp(n1) or not integerp(n2) or not integerp(n)
1619 then error("random_hypergeometric: need numeric argument for approximate procedure"),
1620 if length(num) = 0 then no: 0 else no: num[1],
1622 then ?rndhypergeo(n1,n2,n,no)
1623 else error("random_hypergeometric: check sample size")) $
1627 /* NEGATIVE BINOMIAL DISTRIBUTION */
1629 /* R: dnbinom(x, n, p) */
1630 pdf_negative_binomial(x,n,p) :=
1631 if maybe(p > 0 and p <= 1) = false
1632 then error("pdf_negative_binomial: p must be a positive probability")
1633 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1634 then error("pdf_negative_binomial: n must be a positive integer")
1635 elseif sign(p-1) = 'zero or sign(x) = 'neg or numberp(x) and x-floor(x) > 0
1637 else gamma(n+x)*p^n*(1-p)^x/(x!*gamma(n)) $
1639 /* R: pnbinom(x, n, p) */
1640 cdf_negative_binomial(x,n,p) :=
1641 if maybe(p > 0 and p <= 1) = false
1642 then error("cdf_negative_binomial: p must be a positive probability")
1643 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1644 then error("cdf_negative_binomial: n must be a positive integer")
1645 elseif sign(x) = 'neg
1647 else beta_incomplete_regularized(n,floor(x)+1,p) $
1649 /* R: qnbinom(q,n,p) */
1650 quantile_negative_binomial(q,n,p) :=
1651 if maybe(p > 0 and p <= 1) = false
1652 then error("quantile_negative_binomial: p must be a positive probability")
1653 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1654 then error("quantile_negative_binomial: n must be a positive integer")
1655 elseif maybe(q >= 0 and q <= 1) = false
1656 then error("quantile_negative_binomial: q must be a probability")
1657 elseif member(sign(q-p^n), ['zero, 'neg, 'nz])
1659 elseif sign(1-q) = 'zero
1661 elseif numberp(float(q)) and numberp(float(n)) and numberp(float(p))
1662 then /* partition method */
1663 block([a, b: 1.0, m, fq: float(q)],
1664 while (float(beta_incomplete_regularized(n,floor(b)+1,p)) < fq) do b: b*2,
1667 m: floor(0.5*(a+b)),
1668 if float(beta_incomplete_regularized(n,m+1,p)) < fq
1672 else error("quantile_negative_binomial: need numeric arguments for approximate procedure") $
1674 mean_negative_binomial(n,p) :=
1675 if maybe(p > 0 and p <= 1) = false
1676 then error("mean_negative_binomial: p must be a positive probability")
1677 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1678 then error("mean_negative_binomial: n must be a positive integer")
1681 var_negative_binomial(n,p) :=
1682 if maybe(p > 0 and p <= 1) = false
1683 then error("var_negative_binomial: p must be a positive probability")
1684 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1685 then error("var_negative_binomial: n must be a positive integer")
1688 std_negative_binomial(n,p) :=
1689 if maybe(p > 0 and p <= 1) = false
1690 then error("std_negative_binomial: p must be a positive probability")
1691 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1692 then error("std_negative_binomial: n must be a positive integer")
1693 else sqrt(n*(1-p))/p $
1695 skewness_negative_binomial(n,p) :=
1696 if maybe(p > 0 and p <= 1) = false
1697 then error("skewness_negative_binomial: p must be a positive probability")
1698 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1699 then error("skewness_negative_binomial: n must be a positive integer")
1700 else (2-p)/sqrt(n*(1-p)) $
1702 kurtosis_negative_binomial(n,p) :=
1703 if maybe(p > 0 and p <= 1) = false
1704 then error("kurtosis_negative_binomial: p must be a positive probability")
1705 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1706 then error("kurtosis_negative_binomial: n must be a positive integer")
1707 else (p*p+6-6*p)/(n*(1-p)) $
1709 random_negative_binomial(n,p,[num]) :=
1710 if maybe(p > 0 and p <= 1) = false
1711 then error("random_negative_binomial: p must be a positive probability")
1712 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1713 then error("random_negative_binomial: n must be a positive integer")
1714 else block([no, fp:float(p), fn:float(n)],
1715 if not numberp(fp) or not numberp(fn)
1716 then error("random_negative_binomial: need numeric argument for approximate procedure"),
1717 if length(num) = 0 then no: 0 else no: num[1],
1719 then ?rndnegbinom(fn,fp,no)
1720 else error("random_negative_binomial: check sample size")) $
1724 /* GENERAL FINITE DISCRETE MODEL */
1726 pdf_general_finite_discrete(x,v) :=
1727 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1728 then error("pdf_general_finite_discrete: v must be a list of non negative expressions")
1729 elseif not numberp(float(x))
1730 then error("pdf_general_finite_discrete: x must be a number")
1731 elseif member(sign(x), ['neg, 'zero, 'nz]) or sign(length(v)-x) = 'neg or x-floor(x) > 0
1733 else v[floor(x)] / sum(v[k],k,1,length(v)) $
1735 cdf_general_finite_discrete(x,v) :=
1736 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1737 then error("cdf_general_finite_discrete: v must be a list of non negative expressions")
1738 elseif not numberp(float(x))
1739 then error("cdf_general_finite_discrete: x must be a number")
1740 elseif sign(x-1) = 'neg
1742 elseif member(sign(x - length(v)), ['pos,'zero, 'pz])
1744 else sum(v[k],k,1,floor(x)) / sum(v[k],k,1,length(v))$
1746 quantile_general_finite_discrete(q,v) :=
1747 if not listp(v) or length(v)=0 or
1748 every(lambda([z], numberp(float(z)) and maybe(z >= 0)), v) = false
1749 then error("cdf_general_finite_discrete: v must be a list of non negative numbers")
1750 elseif maybe(q >= 0 and q <= 1) = false
1751 then error("quantile_general_finite_discrete: q must be a probability")
1752 elseif sign(q-1) = 'zero
1754 elseif sign(q) = 'zero
1756 else block([s:0, p, k:1],
1757 p: makelist(s:s+i, i, v/apply("+",v)),
1758 while (q>p[k]) do k: k+1,
1761 mean_general_finite_discrete(v) :=
1762 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1763 then error("mean_general_finite_discrete: v must be a list of non negative expressions")
1765 p: v / apply("+", v),
1766 makelist(k,k,1,length(v)) . p ) $
1768 var_general_finite_discrete(v) :=
1769 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1770 then error("var_general_finite_discrete: v must be a list of non negative expressions")
1772 p: v / apply("+", v),
1773 m: makelist(k,k,1,length(v)) . p,
1774 (makelist(k,k,1,length(v)) - m)^2 . p ) $
1776 std_general_finite_discrete(v) :=
1777 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1778 then error("std_general_finite_discrete: v must be a list of non negative expressions")
1780 p: v / apply("+", v),
1781 m: makelist(k,k,1,length(v)) . p,
1782 sqrt((makelist(k,k,1,length(v)) - m)^2 . p)) $
1784 skewness_general_finite_discrete(v) :=
1785 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1786 then error("skewness_general_finite_discrete: v must be a list of non negative expressions")
1788 p: v / apply("+", v),
1789 m: makelist(k,k,1,length(v)) . p,
1790 (makelist(k,k,1,length(v)) - m)^3 . p / var_discrete_model(v)^(3/2)) $
1792 kurtosis_general_finite_discrete(v) :=
1793 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1794 then error("kurtosis_general_finite_discrete: v must be a list of non negative expressions")
1796 p: v / apply("+", v),
1797 m: makelist(k,k,1,length(v)) . p,
1798 (makelist(k,k,1,length(v)) - m)^4 . p / var_discrete_model(v)^2 - 3) $
1800 random_general_finite_discrete(v,[num]) :=
1801 if not listp(v) or length(v)=0 or
1802 every(lambda([z], numberp(float(z)) and maybe(z >= 0)), v) = false
1803 then error("random_general_finite_discrete: v must be a list of non negative numbers")
1804 else (if length(num) = 0 then no: 0 else no: num[1],
1806 then block([fv: float(v), s: 0, p, k, r],
1807 fv: fv / apply("+", fv),
1808 p: makelist(s:s+k, k, fv),
1813 while (r > p[k]) do k: k+1,
1816 makelist((r: random(1.0),
1818 while (r > p[k]) do k: k+1,
1821 else error("random_general_finite_discrete: check sample size")) $