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_*)
63 Maximum likelihood estimates (mle_*)
66 pdf_student_t(x,n) is the density function of the Student distribution
67 with n degrees of freedom
68 std_pareto(a,b) is the standard deviation of the Pareto distribution
69 with parameters a and b
70 kurtosis_poisson(m) is the kurtosis coefficient of the Poisson distribution
73 Note: the Cauchy model has no moments, in this case only the density and
74 the distribution functions, 'pdf_cauchy' and 'cdf_cauchy', are defined.
76 For questions, suggestions, bugs and the like, feel free
79 riotorto @@@ yahoo DOT com
82 put('distrib, 2, 'version) $
84 /* This business about trying to infer whether a package is loaded is kind of terrible ...
85 * Maxima would benefit from a more organized package management system.
88 if get ('descriptive, 'version) = false then load ("descriptive");
90 if ?fboundp ('lbfgs) = false then load ("lbfgs");
92 /* Sets the random state according to the computer clock time */
93 set_random_state(make_random_state(true))$
96 /* Loads numerical routines */
97 load("numdistrib.lisp")$
101 /* NORMAL (OR GAUSSIAN) DISTRIBUTION */
104 if maybe(s > 0) = false
105 then error("pdf_normal: standard deviation must be greater than zero")
106 else exp(-(x-m)^2/(2*s^2))/(sqrt(2*%pi)*s)$
109 if maybe(s > 0) = false
110 then error("cdf_normal: standard deviation must be greater than zero")
111 else 1/2+erf((x-m)/(s*sqrt(2)))/2 $
113 /* R: qnorm(q,m,s) */
114 quantile_normal(q,m,s) :=
115 if maybe(s > 0 and q >= 0 and q <= 1) = false
116 then error("quantile_normal: illegal parameters")
117 else if equal(q, 0) then minf
118 elseif equal(q, 1) then inf
119 else m + sqrt(2)*s*inverse_erf(2*q-1) $
122 if maybe(s > 0) = false
123 then error("mean_normal: standard deviation must be greater than zero")
127 if maybe(s > 0) = false
128 then error("var_normal: standard deviation must be greater than zero")
132 if maybe(s > 0) = false
133 then error("std_normal: standard deviation must be greater than zero")
136 skewness_normal(m,s) :=
137 if maybe(s > 0) = false
138 then error("skewness_normal: standard deviation must be greater than zero")
141 kurtosis_normal(m,s) :=
142 if maybe(s > 0) = false
143 then error("kurtosis_normal: standard deviation must be greater than zero")
146 random_normal(m,s,[num]) :=
147 if maybe(s > 0) = false
148 then error("random_normal: standard deviation must be greater than zero")
150 if length(num) = 0 then no: 0 else no: num[1],
151 if integerp(no) and no >= 0
152 then m + s * ?rndnormal(no)
153 else error("random_normal: check sample size")) $
155 mle_normal (x, [w]) :=
157 then ['location = und, 'scale = und]
160 then ['location = mean (x), 'scale = std (x)]
161 else ['location = mean (x, w[1]), 'scale = std (x, w[1])];
164 /* STUDENT DISTRIBUTION */
166 pdf_student_t(x,n) :=
167 if maybe(n > 0) = false
168 then error("pdf_student: number of degrees must be greater than zero")
169 else gamma((n+1)/2) * (1+x*x/n)^(-(n+1)/2) / (sqrt(n*%pi) * gamma(n/2)) $
172 cdf_student_t(x,n) :=
173 if maybe(n > 0) = false
174 then error("cdf_student_t: number of degrees must be greater than zero")
175 else (1+signum(x))/2 - signum(x) * beta_incomplete_regularized(n/2,1/2,n/(n+x^2)) / 2 $
178 quantile_student_t(q,n) :=
179 if maybe(n > 0 and q >= 0 and q <= 1) = false
180 then error("quantile_student_t: illegal parameters")
181 else /* need numerical approximation */
182 block([fq: float(q), fn: float(n), aux, sgn],
183 if numberp(fq) and numberp(fn)
184 then (if fq = 0.0 then return('minf),
185 if fq = 1.0 then return('inf),
186 if fq = 0.5 then return(0),
192 sgn*sqrt(n*(1 / ?iibeta(aux,float(n/2),0.5)-1)))
193 else error("quantile_student: need numeric arguments for approximate procedure")) $
196 if maybe(n > 0) = false
197 then error("mean_student_t:: degrees of freedom must be greater than zero")
201 if maybe(n > 2) = false
202 then error("var_student_t: degrees of freedom must be greater than 2")
206 if maybe(n > 2) = false
207 then error("std_student_t: degrees of freedom must be greater than 2")
208 else sqrt(n / (n-2)) $
210 skewness_student_t(n) :=
211 if maybe(n > 3) = false
212 then error("skewness_student_t: degrees of freedom must be greater than 3")
215 kurtosis_student_t(n) :=
216 if maybe(n > 4) = false
217 then error("kurtosis_student_t: degrees of freedom must be greater than 4")
220 random_student_t(n,[num]) :=
221 if maybe(n > 0) = false
222 then error("random_student_t: degrees of freedom must be greater than zero")
223 else block([no, fn: float(n)],
225 then error("random_student_t: need numeric arguments for approximate procedure"),
226 if length(num) = 0 then no: 0 else no: num[1],
227 if integerp(no) and no >= 0
228 then ?rndstudent(fn,no)
229 else error("random_student_t: check sample size") ) $
233 /* NONCENTRAL STUDENT DISTRIBUTION */
235 /* According to documentation on hgfred, sometimes it might be useful to load */
236 /* package orthopoly. In R, dt(x,n,ncp) */
237 pdf_noncentral_student_t(x,n,ncp) :=
238 if maybe(n > 0) = false
239 then error("pdf_noncentral_student_t: degrees of freedom must be greater than 0")
240 elseif sign(ncp) = 'zero
241 then pdf_student_t(x,n)
242 else n^(n/2) * factorial(n) * exp(-ncp^2/2) /
243 (2^n * (n+x^2)^(n/2) * gamma(n/2)) *
244 (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)) +
245 hgfred([(n+1)/2],[1/2],ncp^2*x^2/(2*(n+x^2))) / (sqrt(n+x^2) * gamma(n/2+1))) $
248 cdf_noncentral_student_t(x,n,ncp) :=
249 if maybe(n > 0) = false
250 then error("cdf_noncentral_student_t: degrees of freedom must be greater than 0")
251 elseif sign(ncp) = 'zero
252 then cdf_student_t(x,n)
253 else /* numerical approximation */
254 block([fx: float(x), fn: float(n), fncp: float(ncp)],
255 if numberp(fx) and numberp(fn) and numberp(fncp)
256 then ?cdfnt(fx,fn,fncp)
257 else error("cdf_noncentral_student_t: need numeric arguments for approximate procedure")) $
260 quantile_noncentral_student_t(q,n,ncp) :=
261 if maybe(n > 0 and q >= 0 and q <= 1) = false
262 then error("quantile_noncentral_student_t: illegal parameters")
263 else /* numerical approximation */
264 block([fq: float(q), fn: float(n), fncp: float(ncp)],
265 if numberp(fq) and numberp(fn)
266 then (if fq = 0.0 then return('minf),
267 if fq = 1.0 then return('inf),
270 then return(quantile_student_t(fq,fn))
271 else ?qnct(fq, fn, fncp))
272 else error("quantile_noncentral_student_t: need numeric arguments for approximate procedure") ) $
274 mean_noncentral_student_t(n,ncp) :=
275 if maybe(n > 1) = false
276 then error("mean_noncentral_student_t: degrees of freedom must be greater than 1")
277 else ncp * sqrt(n/2) * gamma((n-1)/2) / gamma(n/2) $
279 var_noncentral_student_t(n,ncp) :=
280 if maybe(n > 2) = false
281 then error("var_noncentral_student_t: degrees of freedom must be greater than 2")
282 else n*(1+ncp^2)/(n-2) - ncp^2*n/2 * (gamma((n-1)/2) / gamma(n/2))^2 $
284 std_noncentral_student_t(n,ncp) := sqrt(var_noncentral_student_t(n,ncp)) $
286 skewness_noncentral_student_t(n,ncp) :=
287 if maybe(n > 3) = false
288 then error("skewness_noncentral_student_t: degrees of freedom must be greater than 3")
289 else block([m: mean_noncentral_student_t(n,ncp), v: var_noncentral_student_t(n,ncp)],
290 m / v^(3/2) * (n*(2*n-3+ncp^2)/((n-2)*(n-3)) - 2*v) ) $
292 kurtosis_noncentral_student_t(n,ncp) :=
293 if maybe(n > 4) = false
294 then error("kurtosis_noncentral_student_t: degrees of freedom must be greater than 4")
295 else block([m: mean_noncentral_student_t(n,ncp), v: var_noncentral_student_t(n,ncp)],
296 (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) $
298 random_noncentral_student_t(n,ncp,[num]) :=
299 if maybe(n > 0) = false
300 then error("random_noncentral_student_t: degrees of freedom must be greater than zero")
301 else block([no, fn: float(n), fncp: float(ncp)],
302 if numberp(fn) and numberp(fncp)
303 then (if length(num) = 0 then no: 0 else no: num[1],
304 if integerp(no) and no >= 0
305 then ?rndncstudent(fn,fncp,no)
306 else error("random_noncentral_student_t: check sample size"))
307 else error("random_noncentral_student_t: need numeric arguments for approximate procedure") ) $
311 /* CHI-SQUARE (OR PEARSON'S) DISTRIBUTION */
312 /* chi2(n) is equivalent to gamma(n/2,2) */
314 pdf_chi2(x,n) := pdf_gamma(x,n/2,2)$
316 cdf_chi2(x,n) := cdf_gamma(x,n/2,2)$
318 quantile_chi2(q,n) := quantile_gamma(q,n/2,2)$
320 mean_chi2(n) := mean_gamma(n/2,2)$
322 var_chi2(n) := var_gamma(n/2,2)$
324 std_chi2(n) := std_gamma(n/2,2)$
326 skewness_chi2(n) := skewness_gamma(n/2,2)$
328 kurtosis_chi2(n) := kurtosis_gamma(n/2,2)$
330 random_chi2(n,[num]) :=
331 if maybe(n > 0) = false
332 then error("random_chi2: degrees of freedom must be greater than zero")
333 else block([no, fn: float(n)],
335 then error("random_chi2: need numeric arguments for approximate procedure"),
336 if length(num) = 0 then no: 0 else no: num[1],
337 if integerp(no) and no >= 0
339 else error("random_chi2: check sample size")) $
343 /* NONCENTRAL CHI-SQUARE DISTRIBUTION */
345 /* R: dchisq(x,n,ncp) */
346 pdf_noncentral_chi2(x,n,ncp) :=
347 if maybe(n > 0) = false
348 then error("pdf_noncentral_chi2: degrees of freedom must be greater than 0")
349 elseif sign(ncp) = 'zero
351 else 1/2 * exp(-(x+ncp)/2) * (x/ncp)^(n/4-1/2) * bessel_i(n/2-1, sqrt(x*ncp)) * unit_step(x) $
353 /* R: pchisq(x,n,ncp) */
354 cdf_noncentral_chi2(x,n,ncp) :=
355 if maybe(n > 0) = false
356 then error("cdf_noncentral_chi2: degrees of freedom must be greater than 0")
357 elseif float(ncp)=0.0
359 elseif maybe(x >= 0) = false
361 else /* need numerical approximation */
362 block([fx: float(x), fn: float(n), fncp: float(ncp)],
363 if numberp(fx) and numberp(fn) and numberp(fncp)
364 then ?cdfnchi2(fx, fn, fncp,
365 1e-12, /* maximum error */
366 1.4210854715202e-14, /* 8*DBL_EPSILON */
367 1000000.0) /* number of iterations */
368 else error("cdf_noncentral_chi2: need numeric arguments for approximate procedure") ) $
370 /* R: qchisq(q,n,ncp) */
371 quantile_noncentral_chi2(q,n,ncp) :=
372 if maybe(n > 0 and q >= 0 and q <= 1) = false
373 then error("quantile_noncentral_chi2: degrees of freedom must be greater than 0")
374 else /* numerical approximation */
375 block([fq: float(q), fn: float(n), fncp: float(ncp)],
376 if numberp(fq) and numberp(fn) and numberp(fncp)
377 then (if fq = 0.0 then return(0),
378 if fq = 1.0 then return('inf),
379 if fncp=0.0 then return(quantile_chi2(q,n)),
380 ?qnchi2(fq, fn, fncp))
381 else error("quantile_noncentral_chi2: need numeric arguments for approximate procedure")) $
383 mean_noncentral_chi2(n,ncp) :=
384 if maybe(n > 0) = false
385 then error("mean_noncentral_chi2: degrees of freedom must be greater than 0")
388 var_noncentral_chi2(n,ncp) :=
389 if maybe(n > 0) = false
390 then error("var_noncentral_chi2: degrees of freedom must be greater than 0")
393 std_noncentral_chi2(n,ncp) := sqrt(var_noncentral_chi2(n,ncp)) $
395 skewness_noncentral_chi2(n,ncp) :=
396 if maybe(n > 0) = false
397 then error("skewness_noncentral_chi2: degrees of freedom must be greater than 0")
398 else 2^(3/2) * (n+3*ncp) /(n+2*ncp)^(3/2) $
400 kurtosis_noncentral_chi2(n,ncp) :=
401 if maybe(n > 0) = false
402 then error("kurtosis_noncentral_chi2: degrees of freedom must be greater than 0")
403 else 12 * (n+4*ncp) /(n+2*ncp)^2 $
405 random_noncentral_chi2(n,ncp,[num]) :=
406 if maybe(n > 0) = false
407 then error("random_noncentral_chi2: degrees of freedom must be greater than 0")
408 else block([no, fn: float(n), fncp: float(ncp)],
409 if not numberp(fn) or not numberp(fncp)
410 then error("random_noncentral_chi2: need numeric arguments for approximate procedure"),
411 if length(num) = 0 then no: 0 else no: num[1],
412 if integerp(no) and no >= 0
413 then ?rndnchi2(fn,fncp,no)
414 else error("random_noncentral_chi2: check sample size")) $
421 if maybe(n > 0 and m > 0) = false
422 then error("pdf_f: degrees of freedom must be greater than 0")
423 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) $
427 if maybe(n > 0 and m > 0) = false
428 then error("cdf_f: degrees of freedom must be greater than 0")
429 else (1 - beta_incomplete_regularized(n/2, m/2, n/(n+m*x))) * unit_step(x) $
433 if maybe(n > 0 and m > 0 and q >= 0 and q <= 1) = false
434 then error("quantile_f: check input parameters")
435 else block([fq: float(q), fn: float(n), fm: float(m)],
436 if numberp(fq) and numberp(fn) and numberp(fm)
437 then(if fq = 0.0 then return(0),
438 if fq = 1.0 then return('inf),
439 fn * (1 / ?iibeta(1-fq, fn/2, fm/2) - 1) / fm)
440 else error("quantile_f: need numeric arguments for approximate procedure")) $
443 if maybe(n > 2 and m > 0) = false
444 then error("mean_f: degrees of freedom must be m>0 and n>2")
448 if maybe(n > 4 and m > 0) = false
449 then error("var_f: degrees of freedom must be m>0 and n>4")
450 else 2*n*n*(m+n-2)/(m*(n-2)*(n-2)*(n-4)) $
452 std_f(m,n) := sqrt(var_f(m,n)) $
455 if maybe(n > 6 and m > 0) = false
456 then error("skewness_f: degrees of freedom must be m>0 and n>6")
457 else (2*m+n-2)*sqrt(8*(n-4))/(sqrt(m*(m+n-2))*(n-6)) $
460 if maybe(n > 8 and m > 0) = false
461 then error("kurtosis_f: degrees of freedom must be m>0 and n>8")
462 else 12*((n-2)*(n-2)*(n-4)+m*(m+n-2)*(5*n-22)) / (m*(n-6)*(n-8)*(m+n-2)) $
464 random_f(m,n,[num]) :=
465 if maybe(n > 0 and m > 0) = false
466 then error("pdf_f: degrees of freedom must be greater than 0")
467 else block([no, fm: float(m), fn: float(n)],
468 if not numberp(fn) or not numberp(fm)
469 then error("random_f: need numeric arguments for approximate procedure"),
470 if length(num) = 0 then no: 0 else no: num[1],
471 if integerp(no) and no >= 0
473 else error("random_f: check sample size")) $
477 /* EXPONENTIAL DISTRIBUTION */
478 /* exp(m) equivalent to Weibull(1,1/m) */
480 pdf_exp(x,m) := pdf_weibull(x,1,1/m)$
482 cdf_exp(x,m) := cdf_weibull(x,1,1/m)$
484 quantile_exp(q,m) := quantile_weibull(q,1,1/m)$
486 mean_exp(m) := mean_weibull(1,1/m)$
488 var_exp(m) := var_weibull(1,1/m)$
490 std_exp(m) := std_weibull(1,1/m)$
492 skewness_exp(m) := skewness_weibull(1,1/m)$
494 kurtosis_exp(m) := kurtosis_weibull(1,1/m)$
496 random_exp(m,[num]) :=
497 if maybe(m > 0) = false
498 then error("random_exp: rate must be greater than 0")
499 else block([no, fm: float(m)],
501 then error("random_exp: need numeric arguments for approximate procedure"),
502 if length(num) = 0 then no: 0 else no: num[1],
503 if integerp(no) and no >= 0
505 else error("random_exp: check sample size") ) $
510 else (w: if w = [] then 1 else w[1],
511 ['rate = 1 / mean(x, w)]);
514 /* LOGNORMAL DISTRIBUTION */
516 pdf_lognormal(x,m,s) :=
517 if maybe(s > 0) = false
518 then error("pdf_lognormal: parameter s must be greater than 0")
519 else exp(-(log(x)-m)^2/(2*s^2))/(sqrt(2*%pi)*s*x) * unit_step(x) $
521 cdf_lognormal(x,m,s) :=
522 if maybe(s > 0) = false
523 then error("cdf_lognormal: parameter s must be greater than 0")
524 else (1/2+erf((log(x)-m)/(s*sqrt(2)))/2) * unit_step(x) $
526 /* R: qlnorm(p,m,s)*/
527 quantile_lognormal(q,m,s) :=
528 if maybe(s > 0 and q >= 0 and q <= 1) = false
529 then error("quantile_lognormal: check input parameters")
531 if equal (q, 0) then 0
532 elseif equal (q, 1) then inf
533 else exp(m + sqrt(2)*s*inverse_erf(2*q-1)) $
535 mean_lognormal(m,s) :=
536 if maybe(s > 0) = false
537 then error("mean_lognormal: parameter s must be greater than 0")
540 var_lognormal(m,s) :=
541 if maybe(s > 0) = false
542 then error("var_lognormal: parameter s must be greater than 0")
543 else exp(2*m+s^2)*(exp(s^2)-1) $
545 std_lognormal(m,s) := sqrt(var_lognormal(m,s)) $
547 skewness_lognormal(m,s) :=
548 if maybe(s > 0) = false
549 then error("skewness_lognormal: parameter s must be greater than 0")
550 else (exp(s^2)+2)*sqrt(exp(s^2)-1) $
552 kurtosis_lognormal(m,s) :=
553 if maybe(s > 0) = false
554 then error("kurtosis_lognormal: parameter s must be greater than 0")
555 else exp(4*s^2)+2*exp(3*s^2)+3*exp(2*s^2)-3 $
557 random_lognormal(m,s,[num]) :=
558 if maybe(s > 0) = false
559 then error("random_lognormal: parameter s must be greater than 0")
561 if length(num) = 0 then no: 0 else no: num[1],
562 if integerp(no) and no >= 0
563 then exp(m + s * ?rndnormal(no))
564 else error("random_lognormal: check sample size") ) $
566 mle_lognormal (x, [w]) :=
568 then ['log_location = und, 'log_scale = und]
571 then ['log_location = mean (log (x)), 'log_scale = std (log (x))]
572 else ['log_location = mean (log (x), w[1]), 'log_scale = std (log (x), w[1])];
576 /* GAMMA DISTRIBUTION */
578 /* R: dgamma(x,a,1/b) */
580 if maybe(a > 0 and b > 0) = false
581 then error("pdf_gamma: parameters a and b must be greater than 0")
582 else x^(a-1)*exp(-x/b)/(b^a*gamma(a)) * unit_step(x) $
584 /* R: pgamma(x,a,1/b) */
586 if maybe(a > 0 and b > 0) = false
587 then error("cdf_gamma: parameters a and b must be greater than 0")
588 else (1 - gamma_incomplete_regularized(a,x/b)) * unit_step(x) $
590 /* R: qgamma(q,a,1/b) */
591 quantile_gamma(q,a,b) :=
592 if maybe(a > 0 and b >0 and q >= 0 and q <= 1) = false
593 then error("quantile_gamma: check input parameters")
595 if equal (q, 0) then 0
596 elseif equal (q, 1) then inf
597 else /* approximate procedure */
598 block([fq: float(q), fa: float(a)],
599 if numberp(fq) and numberp(fa)
600 then(if fq = 0.0 then return(0),
601 if fq = 1.0 then return('inf),
602 b * ?iigamma(fq, fa))
603 else error("quantile_gamma: need numeric arguments for approximate procedure")) $
606 if maybe(a > 0 and b > 0) = false
607 then error("mean_gamma: parameters a and b must be greater than 0")
611 if maybe(a > 0 and b > 0) = false
612 then error("var_gamma: parameters a and b must be greater than 0")
615 std_gamma(a,b) := sqrt(var_gamma(a,b)) $
617 skewness_gamma(a,b) :=
618 if maybe(a > 0 and b > 0) = false
619 then error("skewness_gamma: parameters a and b must be greater than 0")
622 kurtosis_gamma(a,b) :=
623 if maybe(a > 0 and b > 0) = false
624 then error("kurtosis_gamma: parameters a and b must be greater than 0")
627 random_gamma(a,b,[num]) :=
628 if maybe(a > 0 and b > 0) = false
629 then error("random_gamma: parameters a and b must be greater than 0")
630 else block([no, fa:float(a), fb:float(b)],
631 if not numberp(fa) or not numberp(fb)
632 then error("random_gamma: need numeric arguments for approximate procedure"),
633 if length(num) = 0 then no: 0 else no: num[1],
634 if integerp(no) and no >= 0
635 then ?rndgamma(fa,fb,no)
636 else error("random_gamma: check sample size") ) $
638 mle_gamma (x, [w]) :=
640 then ['shape = und, 'scale = und]
641 else block ([shape_estimate, scale_estimate],
642 w: if w = [] then 1 else w[1],
643 shape_estimate: mle_gamma_shape (x, w),
644 scale_estimate: mle_gamma_scale (x, shape_estimate, w),
645 ['shape = shape_estimate, 'scale = scale_estimate]);
647 mle_gamma_shape_tol: 1e-8;
649 /* Newton-Raphson iteration as described under "Maximum likelihood estimation"
650 * in https://en.wikipedia.org/wiki/Gamma_distribution
653 mle_gamma_shape (x, [w]) :=
654 block ([s, shape, shape_update],
655 w: if w = [] then 1 else w[1],
656 s: ev (log (mean (x, w)) - mean (log (x), w), numer),
657 shape: (3 - s + sqrt ((s - 3)^2 + 24*s)) / (12*s),
658 shape_update_function: lambda ([shape], shape - (log(shape) - psi[0](shape) - s) / (1/shape - psi[1](shape))),
659 shape_update: shape_update_function (shape),
660 while abs (shape_update - shape) > mle_gamma_shape_tol
661 do [shape, shape_update]: [shape_update, shape_update_function (shape_update)],
664 mle_gamma_scale (x, shape, [w]) :=
667 else mean(x, w[1]) / shape;
670 /* BETA DISTRIBUTION */
673 if maybe(a > 0 and b > 0) = false
674 then error("pdf_beta: parameters a and b must be greater than 0")
675 else x^(a-1)*(1-x)^(b-1)/beta(a,b)*(unit_step(x)-unit_step(x-1)) $
677 /* R: pbeta(x,a,b) */
679 if maybe(a > 0 and b > 0) = false
680 then error("cdf_beta: parameters a and b must be greater than 0")
681 else beta_incomplete_regularized(a,b,x) * (unit_step(x)-unit_step(x-1)) + unit_step(x-1)$
683 /* R: qbeta(q,a,b) */
684 quantile_beta(q,a,b) :=
685 if maybe(a > 0 and b >0 and q >= 0 and q <= 1) = false
686 then error("quantile_beta: check input parameters")
688 if equal (q, 0) then 0
689 elseif equal (q, 1) then 1
690 else block([fq: float(q), fa: float(a), fb: float(b)],
691 if numberp(fq) and numberp(fa) and numberp(fb)
692 then(if fq = 0.0 then return(0),
693 if fq = 1.0 then return(1),
695 else error("quantile_beta: need numeric arguments for approximate procedure")) $
698 if maybe(a > 0 and b > 0) = false
699 then error("mean_beta: parameters a and b must be greater than 0")
703 if maybe(a > 0 and b > 0) = false
704 then error("var_beta: parameters a and b must be greater than 0")
705 else a*b/((a+b)^2*(a+b+1)) $
707 std_beta(a,b) := sqrt(var_beta(a,b)) $
709 skewness_beta(a,b) :=
710 if maybe(a > 0 and b > 0) = false
711 then error("skewness_beta: parameters a and b must be greater than 0")
712 else 2*(b-a)*sqrt(a+b+1)/(sqrt(a*b)*(a+b+2)) $
714 kurtosis_beta(a,b) :=
715 if maybe(a > 0 and b > 0) = false
716 then error("kurtosis_beta: parameters a and b must be greater than 0")
717 else 3*(a+b+1)*(2*(a+b)^2+a*b*(a+b-6)) / (a*b*(a+b+2)*(a+b+3)) - 3 $
719 random_beta(a,b,[num]) :=
720 if maybe(a > 0 and b > 0) = false
721 then error("random_beta: parameters a and b must be greater than 0")
722 else block([no, fa:float(a), fb:float(b)],
723 if not numberp(fa) or not numberp(fb)
724 then error("random_beta: need numeric arguments for approximate procedure"),
725 if length(num) = 0 then no: 0 else no: num[1],
726 if integerp(no) and no >= 0
727 then ?rndbeta(fa,fb,no)
728 else error("random_beta: check sample size") ) $
732 then ['shape_1 = und, 'shape_2 = und]
733 else block ([log_pdf, nll, fom, u, listarithm: true],
734 w: if w = [] then 1 else w[1],
735 log_pdf: ev (log (pdf_beta (u, shape_1, shape_2)), logexpand = super),
736 nll: - lsum (w_log_p1, w_log_p1, w * map (lambda ([x1], subst (u = x1, log_pdf)), x)),
737 /* rescale nll by 1/n to make problem invariant wrt number of data */
738 fom: nll / length(x),
739 lbfgs (fom, [shape_1, shape_2], mle_beta_initial_estimates (x, w), mle_beta_tol, mle_beta_iprint));
742 mle_beta_iprint: [1, 0];
744 /* WIKIPEDIA [1] SAYS THE FOLLOWING ESTIMATES ARE VALID IF ALPHA HAT > 1 AND BETA HAT > 1,
745 * WHICH IS A LITTLE SUSPECT SINCE THE CRITERION SEEMS BETTER STATED IN TERMS OF THE INPUT FACTORS,
746 * AND ALSO IS PROBLEMATIC SINCE THERE IS NO SUGGESTION WHAT TO DO OTHERWISE.
747 * [1] https://en.wikipedia.org/wiki/Beta_distribution#Statistical_inference
750 mle_beta_initial_estimates (x, w) :=
751 block ([G_hat_X, G_hat_1_minus_X, ab_denom],
752 G_hat_X: ev (mean (log(x), w), numer),
753 G_hat_1_minus_X: ev (mean (log (1 - x), w), numer),
754 ab_denom: 2*(1 - G_hat_X - G_hat_1_minus_X),
755 [1/2 + G_hat_X / ab_denom, 1/2 + G_hat_1_minus_X / ab_denom]);
758 /* CONTINUOUS UNIFORM DISTRIBUTION */
760 pdf_continuous_uniform(x,a,b) :=
761 if maybe(b - a > 0) = false
762 then error("pdf_continuous_uniform: parameter b must be greater than a")
763 else (unit_step(x-a)-unit_step(x-b))/(b-a) $
765 cdf_continuous_uniform(x,a,b) :=
766 if maybe(b - a > 0) = false
767 then error("cdf_continuous_uniform: parameter b must be greater than a")
768 else (x-a)/(b-a)*(unit_step(x-a)-unit_step(x-b)) + unit_step(x-b) $
770 quantile_continuous_uniform(q,a,b) :=
771 if maybe(b - a > 0 and q >= 0 and q <= 1) = false
772 then error("quantile_continuous_uniform: check input parameters")
774 if equal (q, 0) then a
775 elseif equal (q, 1) then b
778 mean_continuous_uniform(a,b) :=
779 if maybe(b - a > 0) = false
780 then error("mean_continuous_uniform: parameter b must be greater than a")
783 var_continuous_uniform(a,b) :=
784 if maybe(b - a > 0) = false
785 then error("var_continuous_uniform: parameter b must be greater than a")
788 std_continuous_uniform(a,b) := sqrt(var_continuous_uniform(a,b))$
790 skewness_continuous_uniform(a,b) :=
791 if maybe(b - a > 0) = false
792 then error("skewness_continuous_uniform: parameter b must be greater than a")
795 kurtosis_continuous_uniform(a,b) :=
796 if maybe(b - a > 0) = false
797 then error("kurtosis_continuous_uniform: parameter b must be greater than a")
800 /* This is a direct application of the maxima */
801 /* random function. Make describe(random) for details */
802 random_continuous_uniform(a,b,[num]) :=
803 if maybe(b - a > 0) = false
804 then error("random_continuous_uniform: parameter b must be greater than a")
805 else block([no, f:float(b-a), listarith:true],
807 then error("random_continuous_uniform: need numeric arguments for approximate procedure"),
808 if length(num) = 0 then no: 0 else no: num[1],
812 else a + makelist(random(f),k,no)
813 else error("random_continuous_uniform: check sample size") ) $
817 /* LOGISTIC DISTRIBUTION */
819 pdf_logistic(x,a,b) :=
820 if maybe(b > 0) = false
821 then error("pdf_logistic: parameter b must be greater than 0")
822 else block([y: exp((a-x)/b)], y/(b*(1+y)^2)) $
824 cdf_logistic(x,a,b) :=
825 if maybe(b > 0) = false
826 then error("cdf_logistic: parameter b must be greater than 0")
827 else 1/(1+exp((a-x)/b)) $
829 quantile_logistic(q,a,b) :=
830 if maybe(b > 0 and q >= 0 and q <= 1) = false
831 then error("quantile_logistic: check input parameters")
833 if equal (q, 0) then minf
834 elseif equal (q, 1) then inf
835 else a - b * log(1/q-1) $
837 mean_logistic(a,b) :=
838 if maybe(b > 0) = false
839 then error("mean_logistic: parameter b must be greater than 0")
843 if maybe(b > 0) = false
844 then error("var_logistic: parameter b must be greater than 0")
847 std_logistic(a,b) := sqrt(var_logistic(a,b)) $
849 skewness_logistic(a,b) :=
850 if maybe(b > 0) = false
851 then error("skewness_logistic: parameter b must be greater than 0")
854 kurtosis_logistic(a,b) :=
855 if maybe(b > 0) = false
856 then error("kurtosis_logistic: parameter b must be greater than 0")
860 random_logistic(a,b,[num]) :=
861 if maybe(b > 0) = false
862 then error("random_logistic: parameter b must be greater than 0")
863 else block([no, fa:float(a), fb:float(b)],
864 if not numberp(fa) or not numberp(fb)
865 then error("random_logistic: need numeric arguments for approximate procedure"),
866 if length(num) = 0 then no: 0 else no: num[1],
869 then a - b * log(1/random(1.0) - 1.0)
870 else a - b * map('log,1/makelist(random(1.0),k,no) - 1.0)
871 else error("random_logistic: check sample size")) $
875 /* PARETO DISTRIBUTION */
878 if maybe(a > 0 and b > 0) = false
879 then error("pdf_pareto: parameters a and b must be greater than 0")
880 else a*b^a*x^(-a-1) * unit_step(x-b) $
883 if maybe(a > 0 and b > 0) = false
884 then error("pdf_pareto: parameters a and b must be greater than 0")
885 else (1-(b/x)^a) * unit_step(x-b) $
887 quantile_pareto(q,a,b) :=
888 if maybe(a > 0 and b > 0 and q >= 0 and q <= 1) = false
889 then error("quantile_pareto: check input parameters")
891 if equal (q, 0) then b
892 elseif equal (q, 1) then inf
893 else b / (1-q)^(1/a) $
896 if maybe(a > 1) = false
897 then error("mean_pareto: parameter a must be greater than 1")
898 elseif maybe(b > 0) = false
899 then error("mean_pareto: parameter b must be greater than 0")
903 if maybe(a > 2) = false
904 then error("var_pareto: parameter a must be greater than 2")
905 elseif maybe(b > 0) = false
906 then error("var_pareto: parameter b must be greater than 0")
907 else a*b*b/((a-2)*(a-1)^2) $
910 if maybe(a > 2) = false
911 then error("std_pareto: parameter a must be greater than 2")
912 elseif maybe(b > 0) = false
913 then error("std_pareto: parameter b must be greater than 0")
914 else b*sqrt(a/(a-2))/(a-1) $
916 skewness_pareto(a,b) :=
917 if maybe(a > 3) = false
918 then error("skewness_pareto: parameter a must be greater than 3")
919 elseif maybe(b > 0) = false
920 then error("skewness_pareto: parameter b must be greater than 0")
921 else 2*(a+1)*sqrt(a-2)/((a-3)*sqrt(a)) $
923 kurtosis_pareto(a,b) :=
924 if maybe(a > 4) = false
925 then error("kurtosis_pareto: parameter a must be greater than 4")
926 elseif maybe(b > 0) = false
927 then error("kurtosis_pareto: parameter b must be greater than 0")
928 else (6*(a^3+a^2-6*a-2)) / (a*(a^2-7*a+12)) - 3 $
931 random_pareto(a,b,[num]) :=
932 if maybe(a > 0 and b > 0) = false
933 then error("random_pareto: parameters a and b must be greater than 0")
934 else block([no, fa:float(a), fb:float(b)],
935 if not numberp(fa) or not numberp(fb)
936 then error("random_pareto: need numeric arguments for approximate procedure"),
937 if length(num) = 0 then no: 0 else no: num[1],
940 then b / (1-random(1.0))^(1.0/a)
941 else b / (1-makelist(random(1.0),k,1,no))^(1.0/a)
942 else error("random_pareto: check sample size")) $
946 /* WEIBULL DISTRIBUTION */
948 pdf_weibull(x,a,b) :=
949 if maybe(a > 0 and b > 0) = false
950 then error("pdf_weibull: parameters a and b must be greater than 0")
951 else a/b*(x/b)^(a-1)*exp(-(x/b)^a) * unit_step(x) $
953 cdf_weibull(x,a,b) :=
954 if maybe(a > 0 and b > 0) = false
955 then error("cdf_weibull: parameters a and b must be greater than 0")
956 else (1-exp(-(x/b)^a)) * unit_step(x) $
958 /* R: qweibull(q,a,b) */
959 quantile_weibull(q,a,b) :=
960 if maybe(a > 0 and b > 0 and q >= 0 and q <= 1) = false
961 then error("quantile_weibull: check input parameters")
963 if equal (q, 0) then 0
964 elseif equal (q, 1) then inf
965 else b * (-log(1-q))^(1/a) $
968 if maybe(a > 0 and b > 0) = false
969 then error("mean_weibull: parameters a and b must be greater than 0")
970 else gamma(1/a+1)*b $
973 if maybe(a > 0 and b > 0) = false
974 then error("var_weibull: parameters a and b must be greater than 0")
975 else (gamma(2/a+1)-gamma(1/a+1)^2)*b^2 $
978 if maybe(a > 0 and b > 0) = false
979 then error("std_weibull: parameters a and b must be greater than 0")
980 else sqrt((gamma(2/a+1)-gamma(1/a+1)^2))*b $
982 skewness_weibull(a,b) :=
983 if maybe(a > 0 and b > 0) = false
984 then error("skewness_weibull: parameters a and b must be greater than 0")
985 else (gamma(3/a+1)-3*gamma(1/a+1)*gamma(2/a+1)+2*gamma(1/a+1)^3) /
986 (gamma(2/a+1)-gamma(1/a+1)^2)^(3/2) $
988 kurtosis_weibull(a,b) :=
989 if maybe(a > 0 and b > 0) = false
990 then error("kurtosis_weibull: parameters a and b must be greater than 0")
991 else (gamma(4/a+1)-4*gamma(1/a+1)*gamma(3/a+1)+
992 6*gamma(1/a+1)^2*gamma(2/a+1)-3*gamma(1/a+1)^4) /
993 (gamma(2/a+1)-gamma(1/a+1)^2)^2 - 3 $
996 random_weibull(a,b,[num]) :=
997 if maybe(a > 0 and b > 0) = false
998 then error("random_weibull: parameters a and b must be greater than 0")
999 else block([no, fa:float(a), fb:float(b)],
1000 if not numberp(fa) or not numberp(fb)
1001 then error("random_weibull: need numeric arguments for approximate procedure"),
1002 if length(num) = 0 then no: 0 else no: num[1],
1005 then b * (-log(random(1.0)))^(1.0/a)
1006 else b * (-map('log,makelist(random(1.0),k,1,no)))^(1.0/a)
1007 else error("random_weibull: check sample size")) $
1009 mle_weibull (x, [w]) :=
1011 then ['shape = und, 'scale = und]
1012 else block ([shape, scale],
1013 w: if w = [] then 1 else w[1],
1014 shape: mle_weibull_shape (x, w),
1015 scale: mle_weibull_scale (x, shape, w),
1016 ['shape = shape, 'scale = scale]);
1018 mle_weibull_shape (x, [w]) :=
1019 block ([listarith: true, shape_eq, eq1],
1020 w: if w = [] then 1 else w[1],
1022 /* The shape parameter is unchanged by rescaling x,
1023 * so we could try to avoid overflow for large x and large k
1024 * by rescaling; however, it's not clear what's a strategy
1025 * for rescaling which works for very large and very small
1026 * values at the same time. Just let it be for now.
1029 shape_eq: lambda ([k], mean (x^k*log(x), w) / mean (x^k, w) - 1/k - mean (log(x), w)),
1031 /* Shape equation is monotonically increasing in k; see:
1032 * N. Balakrishnan and M. Kateri. "On the maximum likelihood estimation of parameters
1033 of Weibull distribution based on complete and censored data,"
1034 * Statistics and Probability Letters, vol. 78 (2008), pp. 2971--2975.
1036 * Shape equation is negative for sufficiently small k,
1037 * evaluate at k = 1 and then step down (if positive there)
1038 * or step up (if negative) to find the other end point for search interval.
1044 then block ([k1: 1, k0: 1],
1045 while shape_eq(k0) >= 0 do k0: k0/2,
1046 find_root (shape_eq, k0, k1))
1047 else block ([k0: 1, k1: 1],
1048 while shape_eq(k1) <= 0 do k1: k1*2,
1049 find_root (shape_eq, k0, k1)));
1051 mle_weibull_scale (x, shape, [w]) :=
1053 then (noncentral_moment (x, shape))^(1/shape)
1054 else (noncentral_moment (x, shape, w[1]))^(1/shape);
1057 /* RAYLEIGH DISTRIBUTION */
1058 /* Rayleigh(b) is equivalent to Weibull(2,1/b) */
1060 pdf_rayleigh(x,b):=pdf_weibull(x,2,1/b)$
1062 cdf_rayleigh(x,b):=cdf_weibull(x,2,1/b)$
1064 quantile_rayleigh(q,b):=quantile_weibull(q,2,1/b)$
1066 mean_rayleigh(b):=mean_weibull(2,1/b)$
1068 var_rayleigh(b):=var_weibull(2,1/b)$
1070 std_rayleigh(b):=std_weibull(2,1/b)$
1072 skewness_rayleigh(b):=skewness_weibull(2,1/b)$
1074 kurtosis_rayleigh(b):=kurtosis_weibull(2,1/b)$
1076 /* inverse method */
1077 random_rayleigh(b,[num]) :=
1078 if maybe(b > 0) = false
1079 then error("random_rayleigh: parameter b must be greater than 0")
1080 else block([no, fb:float(b)],
1082 then error("random_rayleigh: need numeric argument for approximate procedure"),
1083 if length(num) = 0 then no: 0 else no: num[1],
1086 then sqrt(-log(random(1.0))) / b
1087 else sqrt(-map('log,makelist(random(1.0),k,1,no))) / b
1088 else error("random_rayleigh: check sample size")) $
1092 /* LAPLACE DISTRIBUTION */
1094 pdf_laplace(x,a,b) :=
1095 if maybe(b > 0) = false
1096 then error("pdf_laplace: parameter b must be greater than 0")
1097 else exp(-abs(x-a)/b)/(2*b) $
1099 cdf_laplace(x,a,b) :=
1100 if maybe(b > 0) = false
1101 then error("pdf_laplace: parameter b must be greater than 0")
1102 else (1+signum(x-a)-signum(x-a)*exp(-abs(x-a)/b)) / 2 $
1104 quantile_laplace(q,a,b) :=
1105 if maybe(b > 0 and q >= 0 and q <= 1) = false
1106 then error("quantile_laplace: check input parameters")
1108 if equal (q, 0) then minf
1109 elseif equal (q, 1) then inf
1110 else a - b * signum(2*q-1) * log(1 - signum(2*q-1) * (2*q-1))$
1112 mean_laplace(a,b) :=
1113 if maybe(b > 0) = false
1114 then error("mean_laplace: parameter b must be greater than 0")
1118 if maybe(b > 0) = false
1119 then error("var_laplace: parameter b must be greater than 0")
1123 if maybe(b > 0) = false
1124 then error("std_laplace: parameter b must be greater than 0")
1127 skewness_laplace(a,b) :=
1128 if maybe(b > 0) = false
1129 then error("skewness_laplace: parameter b must be greater than 0")
1132 kurtosis_laplace(a,b) :=
1133 if maybe(b > 0) = false
1134 then error("kurtosis_laplace: parameter b must be greater than 0")
1137 /* inverse method */
1138 random_laplace(a,b,[num]) :=
1139 if maybe(b > 0) = false
1140 then error("random_laplace: parameter b must be greater than 0")
1141 else block([no, fa:float(a), fb:float(b)],
1142 if not numberp(fa) or not numberp(fb)
1143 then error("random_laplace: need numeric arguments for approximate procedure"),
1144 if length(num) = 0 then no: 0 else no: num[1],
1147 then quantile_laplace(random(1.0),a,b)
1148 else makelist(quantile_laplace(random(1.0),a,b),k,1,no)
1149 else error("random_laplace: check sample size")) $
1153 /* CAUCHY (OR LORENTZ) DISTRIBUTION */
1155 pdf_cauchy(x,a,b) :=
1156 if maybe(b > 0) = false
1157 then error("pdf_cauchy: parameter b must be greater than 0")
1158 else b/(%pi*((x-a)^2+b^2)) $
1160 cdf_cauchy(x,a,b) :=
1161 if maybe(b > 0) = false
1162 then error("pdf_cauchy: parameter b must be greater than 0")
1163 else 1/2+atan((x-a)/b)/%pi $
1165 quantile_cauchy(q,a,b) :=
1166 if maybe(b > 0 and q >= 0 and q <= 1) = false
1167 then error("quantile_cauchy: check input parameters")
1169 if equal (q, 0) then minf
1170 elseif equal (q, 1) then inf
1171 else a + b * tan(%pi * (q - 1/2)) $
1173 /* Note: integrals for Cauchy moments are divergent */
1175 /* inverse method */
1176 random_cauchy(a,b,[num]) :=
1177 if maybe(b > 0) = false
1178 then error("random_cauchy: parameter b must be greater than 0")
1179 else block([no, fa:float(a), fb:float(b)],
1180 if not numberp(fa) or not numberp(fb)
1181 then error("random_cauchy: need numeric arguments for approximate procedure"),
1182 if length(num) = 0 then no: 0 else no: num[1],
1185 then tan (float(%pi) * (random(1.0)-0.5))*fb+fa
1186 else fa + fb * map('tan, 3.141592653589793 * (makelist(random(1.0),k,1,no)-0.5))
1187 else error("random_cauchy: check sample size")) $
1191 /* GUMBEL (OR EXTREME VALUE) DISTRIBUTION */
1193 pdf_gumbel(x,a,b) :=
1194 if maybe(b > 0) = false
1195 then error("pdf_gumbel: parameter b must be greater than 0")
1196 else exp((a-x)/b-exp((a-x)/b))/b $
1198 cdf_gumbel(x,a,b) :=
1199 if maybe(b > 0) = false
1200 then error("cdf_gumbel: parameter b must be greater than 0")
1201 else exp(-exp((a-x)/b)) $
1203 quantile_gumbel(q,a,b) :=
1204 if maybe(b > 0 and q >= 0 and q <= 1) = false
1205 then error("quantile_gumbel: check input parameters")
1207 if equal (q, 0) then minf
1208 elseif equal (q, 1) then inf
1209 else a - b * log(-log(q)) $
1212 if maybe(b > 0) = false
1213 then error("mean_gumbel: parameter b must be greater than 0")
1214 else /* %gamma=Euler-Mascheroni constant */
1218 if maybe(b > 0) = false
1219 then error("var_gumbel: parameter b must be greater than 0")
1220 else b*b*%pi*%pi/6 $
1223 if maybe(b > 0) = false
1224 then error("std_gumbel: parameter b must be greater than 0")
1225 else b*%pi/sqrt(6) $
1227 skewness_gumbel(a,b) :=
1228 if maybe(b > 0) = false
1229 then error("std_gumbel: parameter b must be greater than 0")
1230 else 12*sqrt(6)*zeta(3)/%pi^3 $
1232 kurtosis_gumbel(a,b) :=
1233 if maybe(b > 0) = false
1234 then error("kurtosis_gumbel: parameter b must be greater than 0")
1237 /* inverse method */
1238 random_gumbel(a,b,[num]) :=
1239 if maybe(b > 0) = false
1240 then error("random_gumbel: parameter b must be greater than 0")
1241 else block([no, fa:float(a), fb:float(b)],
1242 if not numberp(fa) or not numberp(fb)
1243 then error("random_gumbel: need numeric arguments for approximate procedure"),
1244 if length(num) = 0 then no: 0 else no: num[1],
1247 then a - b * log(-log(random(1.0)))
1248 else a - b * map('log,-map('log,makelist(random(1.0),k,1,no)))
1249 else error("random_gumbel: check sample size")) $
1253 /* BINOMIAL DISTRIBUTION */
1255 /* R: dbinom(x,n,p) */
1256 pdf_binomial(x,n,p) :=
1257 if maybe(p >= 0 and p <= 1) = false
1258 then error("pdf_binomial: p must be a probability")
1259 /* when n is not an integer, R returns NaN, we throw an error */
1260 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1261 then error("pdf_binomial: n must be a positive integer")
1264 then kron_delta(x,0)
1266 then kron_delta(x,n)
1267 elseif x < 0 or x > n or x-floor(x) > 0
1269 else binomial(n,x)*p^x*(1-p)^(n-x) $
1271 /* R: pbinom(x,n,p) */
1272 cdf_binomial(x,n,p):=
1273 if maybe(p >= 0 and p <= 1) = false
1274 then error("cdf_binomial: p must be a probability")
1275 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1276 then error("cdf_binomial: n must be a positive integer")
1279 elseif x >= n then 1
1280 else beta_incomplete_regularized(n-floor(x),floor(x)+1,1-p) $
1282 /* R: qbinom(q,n,p) */
1283 quantile_binomial(q,n,p):=
1284 if maybe(p >= 0 and p <= 1) = false
1285 then error("quantile_binomial: p must be a probability")
1286 elseif maybe(q >= 0 and q <= 1) = false
1287 then error("quantile_binomial: q must be a probability")
1288 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1289 then error("quantile_binomial: n must be a positive integer")
1291 if equal (q, 0) then 0
1292 elseif equal (q, 1) then n
1293 elseif float(q) <= float((1-p)^n) then 0
1294 elseif numberp(float(q)) and numberp(float(n)) and numberp(float(p))
1295 then /* partition method */
1296 block([a:0, b:n, m],
1299 if cdf_binomial(m,n,p) < q
1303 else error("quantile_binomial: need numeric arguments for approximate procedure") $
1305 mean_binomial(n,p) :=
1306 if maybe(p >= 0 and p <= 1) = false
1307 then error("mean_binomial: p must be a probability")
1308 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1309 then error("mean_binomial: n must be a positive integer")
1312 var_binomial(n,p) :=
1313 if maybe(p >= 0 and p <= 1) = false
1314 then error("var_binomial: p must be a probability")
1315 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1316 then error("var_binomial: n must be a positive integer")
1319 std_binomial(n,p) :=
1320 if maybe(p >= 0 and p <= 1) = false
1321 then error("std_binomial: p must be a probability")
1322 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1323 then error("std_binomial: n must be a positive integer")
1324 else sqrt(n*p*(1-p)) $
1326 skewness_binomial(n,p) :=
1327 if maybe(p >= 0 and p <= 1) = false
1328 then error("std_binomial: p must be a probability")
1329 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1330 then error("std_binomial: n must be a positive integer")
1331 else (1-2*p)/sqrt(n*p*(1-p)) $
1333 kurtosis_binomial(n,p) :=
1334 if maybe(p >= 0 and p <= 1) = false
1335 then error("kurtosis_binomial: p must be a probability")
1336 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1337 then error("kurtosis_binomial: n must be a positive integer")
1338 else (1-6*p*(1-p))/(n*p*(1-p)) $
1340 random_binomial(n,p,[num]) :=
1341 if maybe(p >= 0 and p <= 1) = false
1342 then error("random_binomial: p must be a probability")
1343 elseif maybe(n>=0)=false or numberp(n) and n-floor(n) > 0
1344 then error("random_binomial: n must be a positive integer")
1345 else block([no, fn:float(n), fp:float(p)],
1346 if not numberp(fn) or not numberp(fp)
1347 then error("random_binomial: need numeric arguments for approximate procedure"),
1348 if length(num) = 0 then no: 0 else no: num[1],
1350 then ?rndbinomial(n,fp,no)
1351 else error("random_binomial: check sample size")) $
1355 /* POISSON DISTRIBUTION */
1359 if maybe(m >= 0) = false
1360 then error("pdf_poisson: m must be positive")
1362 if equal (m, 0) then kron_delta(0,x)
1363 elseif x < 0 or x-floor(x) > 0 then 0
1364 else exp(-m)*m^x/x! $
1368 if maybe(m >= 0) = false
1369 then error("cdf_poisson: m must be positive")
1372 else gamma_incomplete_regularized(floor(x)+1, m) $
1375 quantile_poisson(q,m):=
1376 if maybe(m >= 0) = false
1377 then error("quantile_poisson: m must be positive")
1378 elseif maybe(q >= 0 and q <= 1) = false
1379 then error("quantile_poisson: q must be a probability")
1381 if equal (m, 0) then 0
1382 elseif q <= exp(- m) then 0
1383 elseif equal (q, 1) then inf
1384 elseif numberp(float(q)) and numberp(float(m))
1385 then /* partition method */
1386 block([a, b:1.0,mm],
1387 while (cdf_poisson(b,m) < q) do b : 2.0*b,
1391 if cdf_poisson(mm,m) < q
1395 else error("quantile_poisson: need numeric arguments for approximate procedure") $
1398 if maybe(m >= 0) = false
1399 then error("mean_poisson: m must be positive")
1403 if maybe(m >= 0) = false
1404 then error("var_poisson: m must be positive")
1408 if maybe(m >= 0) = false
1409 then error("std_poisson: m must be positive")
1412 skewness_poisson(m):=
1413 if maybe(m >= 0) = false
1414 then error("skewness_poisson: m must be positive")
1417 kurtosis_poisson(m):=
1418 if maybe(m >= 0) = false
1419 then error("kurtosis_poisson: m must be positive")
1422 random_poisson(m,[num]) :=
1423 if maybe(m >= 0) = false
1424 then error("random_poisson: m must be positive")
1425 else block([no, fm:float(m)],
1427 then error("random_poisson: need numeric argument for approximate procedure"),
1428 if length(num) = 0 then no: 0 else no: num[1],
1430 then ?rndpoisson(fm,no)
1431 else error("random_poisson: check sample size")) $
1435 /* BERNOULLI DISTRIBUTION */
1436 /* Bernoulli(p) is equivalent to binomial(1,p) */
1438 pdf_bernoulli(x,p) :=
1439 if maybe(p >= 0 and p <= 1) = false
1440 then error("pdf_bernoulli: p must be a probability")
1442 if x < 0 or x > 1 or x-floor(x) > 0 then 0
1443 elseif equal (p, 0) then kron_delta(x,0)
1444 elseif equal (p, 1) then kron_delta(x,1)
1445 else p^x*(1-p)^(1-x) $
1447 cdf_bernoulli(x,p):= cdf_binomial(x,1,p)$
1449 quantile_bernoulli(q,p):= quantile_binomial(q,1,p)$
1451 mean_bernoulli(p):=mean_binomial(1,p)$
1453 var_bernoulli(p):=var_binomial(1,p)$
1455 std_bernoulli(p):=std_binomial(1,p)$
1457 skewness_bernoulli(p):=skewness_binomial(1,p)$
1459 kurtosis_bernoulli(p):=kurtosis_binomial(1,p)$
1461 /* This is a direct application of the maxima
1462 random function. Make describe(random) for details */
1463 random_bernoulli(p,[num]) :=
1464 if maybe(p >= 0 and p <= 1) = false
1465 then error("random_bernoulli: p must be a probability")
1466 else block([no, fp:float(p)],
1468 then error("random_bernoulli: need numeric argument for approximate procedure"),
1469 if length(num) = 0 then no: 0 else no: num[1],
1472 then if random(1.0)<=fp then 1 else 0
1473 else makelist(if random(1.0)<=fp then 1 else 0,k,1,no)
1474 else error("random_bernoulli: check sample size")) $
1478 /* GEOMETRIC (OR PASCAL) DISTRIBUTION */
1481 pdf_geometric(x,p) :=
1482 if maybe(p > 0 and p <= 1) = false
1483 then error("pdf_geometric: p must be a non zero probability")
1486 then if equal (x, 0) then 1 else 0
1487 elseif x < 0 or x-floor(x) > 0 then 0
1491 cdf_geometric(x,p) :=
1492 if maybe(p > 0 and p <= 1) = false
1493 then error("cdf_geometric: p must be a non zero probability")
1496 then if x >= 0 then 1 else 0
1498 else 1-(1-p)^(floor(x)+1) $
1501 quantile_geometric(q,p) :=
1502 if maybe(p > 0 and p <= 1) = false
1503 then error("quantile_geometric: p must be a non zero probability")
1504 elseif maybe(q >= 0 and q <= 1) = false
1505 then error("quantile_geometric: q must be a probability")
1507 if equal (q, 1) then inf
1508 elseif equal (q, 0) then 0
1509 elseif equal (p, 1) then 1
1510 else ceiling(log(1-q)/log(1-p)-1) $
1512 mean_geometric(p) :=
1513 if maybe(p > 0 and p <= 1) = false
1514 then error("mean_geometric: p must be a non zero probability")
1518 if maybe(p > 0 and p <= 1) = false
1519 then error("var_geometric: p must be a non zero probability")
1523 if maybe(p > 0 and p <= 1) = false
1524 then error("std_geometric: p must be a non zero probability")
1527 skewness_geometric(p) :=
1528 if maybe(p > 0 and p <= 1) = false
1529 then error("skewness_geometric: p must be a non zero probability")
1530 else (2-p)/sqrt(1-p) $
1532 kurtosis_geometric(p) :=
1533 if maybe(p > 0 and p <= 1) = false
1534 then error("kurtosis_geometric: p must be a non zero probability")
1535 else (p^2+6-6*p)/(1-p) $
1537 random_geometric(p,[num]) :=
1538 if maybe(p > 0 and p <= 1) = false
1539 then error("random_geometric: p must be a non zero probability")
1540 else block([no, fp:float(p)],
1542 then error("random_geometric: need numeric argument for approximate procedure"),
1543 if length(num) = 0 then no: 0 else no: num[1],
1546 else error("random_geometric: check sample size")) $
1550 /* DISCRETE UNIFORM DISTRIBUTION */
1552 pdf_discrete_uniform(x,n) :=
1553 if maybe(n > 0) = false or numberp(n) and n-floor(n) > 0
1554 then error("pdf_discrete_uniform: n must be a positive integer")
1556 if x < 1 or x > n or x-floor(x) > 0
1560 cdf_discrete_uniform(x,n) :=
1561 if maybe(n > 0) = false or n-floor(n) > 0
1562 then error("cdf_discrete_uniform: n must be a positive integer")
1565 elseif x >= n then 1
1568 quantile_discrete_uniform(q,n) :=
1569 if maybe(n > 0) = false or n-floor(n) > 0
1570 then error("cdf_discrete_uniform: n must be a positive integer")
1571 elseif maybe(q >= 0 and q <= 1) = false
1572 then error("quantile_discrete_uniform: q must be a probability")
1574 if equal (q, 1) then n
1575 elseif equal (q, 0) then 1
1578 mean_discrete_uniform(n) :=
1579 if maybe(n > 0) = false or n-floor(n) > 0
1580 then error("mean_discrete_uniform: n must be a positive integer")
1583 var_discrete_uniform(n) :=
1584 if maybe(n > 0) = false or n-floor(n) > 0
1585 then error("var_discrete_uniform: n must be a positive integer")
1588 std_discrete_uniform(n) :=
1589 if maybe(n > 0) = false or n-floor(n) > 0
1590 then error("std_discrete_uniform: n must be a positive integer")
1591 else sqrt((n^2-1)/12) $
1593 skewness_discrete_uniform(n) :=
1594 if maybe(n > 0) = false or n-floor(n) > 0
1595 then error("skewness_discrete_uniform: n must be a positive integer")
1598 kurtosis_discrete_uniform(n) :=
1599 if maybe(n > 0) = false or n-floor(n) > 0
1600 then error("kurtosis_discrete_uniform: n must be a positive integer")
1601 else -6/5-12/(5*(n^2-1)) $
1603 /* This is a direct application of the maxima
1604 random function. Make describe(random) for details */
1605 random_discrete_uniform(n,[num]) :=
1606 if maybe(n > 0) = false or numberp(n) and n-floor(n) > 0
1607 then error("random_discrete_uniform: n must be a positive integer")
1608 else block([no, fn:float(n)],
1610 then error("random_discrete_uniform: need numeric argument for approximate procedure"),
1611 if length(num) = 0 then no: 0 else no: num[1],
1615 else 1+makelist(random(n),k,1,no)
1616 else error("random_discrete_uniform: check sample size")) $
1620 /* HYPERGEOMETRIC DISTRIBUTION */
1622 /* R: dhyper(x, n1, n2, n) */
1623 pdf_hypergeometric(x,n1,n2,n) :=
1624 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1625 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1626 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1627 then error("pdf_hypergeometric: n1, n2, n must be a positive integers")
1628 elseif maybe (n <= n1 +n2) = false
1629 then error("pdf_hypergeometric: n must be less or equal than n1 + n2")
1631 if x < max(0,n-n2) or min(n1,n) < x or x-floor(x) > 0
1633 else binomial(n1,x)*binomial(n2,n-x)/binomial(n1+n2,n) $
1635 /* R: phyper(x, n1, n2, n) */
1636 cdf_hypergeometric(x,n1,n2,n) :=
1637 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1638 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1639 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1640 then error("pdf_hypergeometric: n1, n2, n must be a positive integers")
1641 elseif maybe (n <= n1 +n2) = false
1642 then error("cdf_hypergeometric: n must be less or equal than n1 + n2")
1644 if x < max(0,n-n2) then 0
1645 elseif x > min(n1,n) then 1
1646 else sum(binomial(n1,k)*binomial(n2,n-k) / binomial(n1+n2,n),k,0,floor(x)) $
1648 quantile_hypergeometric(q, n1, n2, n) :=
1649 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1650 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1651 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1652 then error("quantile_hypergeometric: n1, n2, n must be a positive integers")
1653 elseif maybe (n <= n1 +n2) = false
1654 then error("quantile_hypergeometric: n must be less or equal than n1 + n2")
1655 elseif maybe(q >= 0 and q <= 1) = false
1656 then error("quantile_hypergeometric: q must be a probability")
1658 if equal (q, 1) then min(n1,n)
1659 elseif q <= pdf_hypergeometric(max(0, n-n2),n1,n2,n) then max(0, n-n2)
1660 elseif numberp(float(q)) and numberp(float(n1)) and numberp(float(n2)) and numberp(float(n))
1661 then /* partition method */
1662 block([a: max(0, n-n2), b: min(n1,n),m],
1664 m: floor(0.5*(a+b)),
1665 if cdf_hypergeometric(m,n1,n2,n) < q
1669 else error("quantile_hypergeometric: need numeric arguments for approximate procedure") $
1671 mean_hypergeometric(n1,n2,n) :=
1672 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1673 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1674 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1675 then error("mean_hypergeometric: n1, n2, n must be a positive integers")
1676 elseif maybe (n <= n1 +n2) = false
1677 then error("mean_hypergeometric: n must be less or equal than n1 + n2")
1680 var_hypergeometric(n1,n2,n) :=
1681 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1682 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1683 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1684 then error("var_hypergeometric: n1, n2, n must be a positive integers")
1685 elseif maybe (n <= n1 +n2) = false
1686 then error("var_hypergeometric: n must be less or equal than n1 + n2")
1687 else block([t:n1+n2], n*n1*n2*(t-n)/(t*t*(t-1))) $
1689 std_hypergeometric(n1,n2,n) :=
1690 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1691 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1692 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1693 then error("std_hypergeometric: n1, n2, n must be a positive integers")
1694 elseif maybe (n <= n1 +n2) = false
1695 then error("std_hypergeometric: n must be less or equal than n1 + n2")
1696 else block([t:n1+n2], sqrt(n*n1*n2*(t-n)/(t-1))/t) $
1698 skewness_hypergeometric(n1,n2,n) :=
1699 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1700 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1701 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1702 then error("skewness_hypergeometric: n1, n2, n must be a positive integers")
1703 elseif maybe (n <= n1 +n2) = false
1704 then error("skewness_hypergeometric: n must be less or equal than n1 + n2")
1705 else block([t:n1+n2], (n2-n1)*(t-2*n)*sqrt((t-1)/(n*n1*n2*(t-n)))/(t-2)) $
1707 kurtosis_hypergeometric(n1,n2,n) :=
1708 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1709 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1710 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1711 then error("kurtosis_hypergeometric: n1, n2, n must be a positive integers")
1712 elseif maybe (n <= n1 +n2) = false
1713 then error("kurtosis_hypergeometric: n must be less or equal than n1 + n2")
1714 else block([t:n1+n2],
1715 t*t*(t-1)/((t-2)*(t-3)*n*n1*n2*(t-n)) *
1716 (t*(t+1)-6*n*(t-n)+3*n1*n2*(t*t*(n-2)-t*n*n+6*n*(t-n))/t^2) - 3) $
1718 random_hypergeometric(n1,n2,n,[num]) :=
1719 if maybe(n1 >= 0) = false or numberp(n1) and n1-floor(n1) > 0 or
1720 maybe(n2 >= 0) = false or numberp(n2) and n2-floor(n2) > 0 or
1721 maybe( n >= 0) = false or numberp(n) and n-floor(n) > 0
1722 then error("random_hypergeometric: n1, n2, n must be positive integers")
1723 elseif maybe (n <= n1 +n2) = false
1724 then error("random_hypergeometric: n must be less or equal than n1 + n2")
1726 if not integerp(n1) or not integerp(n2) or not integerp(n)
1727 then error("random_hypergeometric: need numeric argument for approximate procedure"),
1728 if length(num) = 0 then no: 0 else no: num[1],
1730 then ?rndhypergeo(n1,n2,n,no)
1731 else error("random_hypergeometric: check sample size")) $
1735 /* NEGATIVE BINOMIAL DISTRIBUTION */
1737 /* R: dnbinom(x, n, p) */
1738 pdf_negative_binomial(x,n,p) :=
1739 if maybe(p > 0 and p <= 1) = false
1740 then error("pdf_negative_binomial: p must be a positive probability")
1741 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1742 then error("pdf_negative_binomial: n must be a positive integer")
1744 if equal (p, 1) or x < 0 or x-floor(x) > 0 then 0
1745 else gamma(n+x)*p^n*(1-p)^x/(x!*gamma(n)) $
1747 /* R: pnbinom(x, n, p) */
1748 cdf_negative_binomial(x,n,p) :=
1749 if maybe(p > 0 and p <= 1) = false
1750 then error("cdf_negative_binomial: p must be a positive probability")
1751 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1752 then error("cdf_negative_binomial: n must be a positive integer")
1755 else beta_incomplete_regularized(n,floor(x)+1,p) $
1757 /* R: qnbinom(q,n,p) */
1758 quantile_negative_binomial(q,n,p) :=
1759 if maybe(p > 0 and p <= 1) = false
1760 then error("quantile_negative_binomial: p must be a positive probability")
1761 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1762 then error("quantile_negative_binomial: n must be a positive integer")
1763 elseif maybe(q >= 0 and q <= 1) = false
1764 then error("quantile_negative_binomial: q must be a probability")
1767 elseif equal (q, 1) then inf
1768 elseif numberp(float(q)) and numberp(float(n)) and numberp(float(p))
1769 then /* partition method */
1770 block([a, b: 1.0, m, fq: float(q)],
1771 while (float(beta_incomplete_regularized(n,floor(b)+1,p)) < fq) do b: b*2,
1774 m: floor(0.5*(a+b)),
1775 if float(beta_incomplete_regularized(n,m+1,p)) < fq
1779 else error("quantile_negative_binomial: need numeric arguments for approximate procedure") $
1781 mean_negative_binomial(n,p) :=
1782 if maybe(p > 0 and p <= 1) = false
1783 then error("mean_negative_binomial: p must be a positive probability")
1784 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1785 then error("mean_negative_binomial: n must be a positive integer")
1788 var_negative_binomial(n,p) :=
1789 if maybe(p > 0 and p <= 1) = false
1790 then error("var_negative_binomial: p must be a positive probability")
1791 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1792 then error("var_negative_binomial: n must be a positive integer")
1795 std_negative_binomial(n,p) :=
1796 if maybe(p > 0 and p <= 1) = false
1797 then error("std_negative_binomial: p must be a positive probability")
1798 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1799 then error("std_negative_binomial: n must be a positive integer")
1800 else sqrt(n*(1-p))/p $
1802 skewness_negative_binomial(n,p) :=
1803 if maybe(p > 0 and p <= 1) = false
1804 then error("skewness_negative_binomial: p must be a positive probability")
1805 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1806 then error("skewness_negative_binomial: n must be a positive integer")
1807 else (2-p)/sqrt(n*(1-p)) $
1809 kurtosis_negative_binomial(n,p) :=
1810 if maybe(p > 0 and p <= 1) = false
1811 then error("kurtosis_negative_binomial: p must be a positive probability")
1812 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1813 then error("kurtosis_negative_binomial: n must be a positive integer")
1814 else (p*p+6-6*p)/(n*(1-p)) $
1816 random_negative_binomial(n,p,[num]) :=
1817 if maybe(p > 0 and p <= 1) = false
1818 then error("random_negative_binomial: p must be a positive probability")
1819 elseif maybe(n>0)=false or numberp(n) and n-floor(n) > 0
1820 then error("random_negative_binomial: n must be a positive integer")
1821 else block([no, fp:float(p), fn:float(n)],
1822 if not numberp(fp) or not numberp(fn)
1823 then error("random_negative_binomial: need numeric argument for approximate procedure"),
1824 if length(num) = 0 then no: 0 else no: num[1],
1826 then ?rndnegbinom(fn,fp,no)
1827 else error("random_negative_binomial: check sample size")) $
1831 /* GENERAL FINITE DISCRETE MODEL */
1833 pdf_general_finite_discrete(x,v) :=
1834 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1835 then error("pdf_general_finite_discrete: v must be a list of non negative expressions")
1836 elseif not numberp(float(x))
1837 then error("pdf_general_finite_discrete: x must be a number")
1839 if x <= 0 or x > length(v) or x-floor(x) > 0
1841 else v[floor(x)] / sum(v[k],k,1,length(v)) $
1843 cdf_general_finite_discrete(x,v) :=
1844 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1845 then error("cdf_general_finite_discrete: v must be a list of non negative expressions")
1846 elseif not numberp(float(x))
1847 then error("cdf_general_finite_discrete: x must be a number")
1850 elseif x >= length(v) then 1
1851 else sum(v[k],k,1,floor(x)) / sum(v[k],k,1,length(v))$
1853 quantile_general_finite_discrete(q,v) :=
1854 if not listp(v) or length(v)=0 or
1855 every(lambda([z], numberp(float(z)) and maybe(z >= 0)), v) = false
1856 then error("cdf_general_finite_discrete: v must be a list of non negative numbers")
1857 elseif maybe(q >= 0 and q <= 1) = false
1858 then error("quantile_general_finite_discrete: q must be a probability")
1860 if equal (q, 1) then length(v)
1861 elseif equal (q, 0) then 1
1862 else block([s:0, p, k:1],
1863 p: makelist(s:s+i, i, v/apply("+",v)),
1864 while (q>p[k]) do k: k+1,
1867 mean_general_finite_discrete(v) :=
1868 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1869 then error("mean_general_finite_discrete: v must be a list of non negative expressions")
1871 p: v / apply("+", v),
1872 makelist(k,k,1,length(v)) . p ) $
1874 var_general_finite_discrete(v) :=
1875 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1876 then error("var_general_finite_discrete: v must be a list of non negative expressions")
1878 p: v / apply("+", v),
1879 m: makelist(k,k,1,length(v)) . p,
1880 (makelist(k,k,1,length(v)) - m)^2 . p ) $
1882 std_general_finite_discrete(v) :=
1883 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1884 then error("std_general_finite_discrete: v must be a list of non negative expressions")
1886 p: v / apply("+", v),
1887 m: makelist(k,k,1,length(v)) . p,
1888 sqrt((makelist(k,k,1,length(v)) - m)^2 . p)) $
1890 skewness_general_finite_discrete(v) :=
1891 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1892 then error("skewness_general_finite_discrete: v must be a list of non negative expressions")
1894 p: v / apply("+", v),
1895 m: makelist(k,k,1,length(v)) . p,
1896 (makelist(k,k,1,length(v)) - m)^3 . p / var_discrete_model(v)^(3/2)) $
1898 kurtosis_general_finite_discrete(v) :=
1899 if not listp(v) or length(v)=0 or every(lambda([z], maybe(z >= 0)), v) = false
1900 then error("kurtosis_general_finite_discrete: v must be a list of non negative expressions")
1902 p: v / apply("+", v),
1903 m: makelist(k,k,1,length(v)) . p,
1904 (makelist(k,k,1,length(v)) - m)^4 . p / var_discrete_model(v)^2 - 3) $
1906 random_general_finite_discrete(v,[num]) :=
1907 if not listp(v) or length(v)=0 or
1908 every(lambda([z], numberp(float(z)) and maybe(z >= 0)), v) = false
1909 then error("random_general_finite_discrete: v must be a list of non negative numbers")
1910 else (if length(num) = 0 then no: 0 else no: num[1],
1912 then block([fv: float(v), s: 0, p, k, r],
1913 fv: fv / apply("+", fv),
1914 p: makelist(s:s+k, k, fv),
1919 while (r > p[k]) do k: k+1,
1922 makelist((r: random(1.0),
1924 while (r > p[k]) do k: k+1,
1927 else error("random_general_finite_discrete: check sample size")) $
1930 /* INVERSE GAMMA DISTRIBUTION
1932 * Formulas from: https://en.wikipedia.org/wiki/Inverse-gamma_distribution
1934 * Two real parameters, a > 0 (shape), and b > 0 (scale).
1939 pdf_inverse_gamma (x, a, b) :=
1940 if maybe (a > 0) = false or maybe (b > 0) = false
1941 then error ("pdf_inverse_gamma: parameters must be positive; found:", a, b)
1942 else if x > 0 then b^a/gamma(a) * x^(-a-1) * exp(-b/x) else 0;
1944 cdf_inverse_gamma (x, a, b) :=
1945 if maybe (a > 0) = false or maybe (b > 0) = false
1946 then error ("cdf_inverse_gamma: parameters must be positive; found:", a, b)
1947 else if x > 0 then gamma_incomplete(a, b/x) / gamma(a) else 0;
1949 quantile_inverse_gamma (x, a, b) :=
1950 if maybe (a > 0) = false or maybe (b > 0) = false
1951 then error ("quantile_inverse_gamma: parameters must be positive; found:", a, b)
1952 else if equal(x, 0) then 0
1953 elseif equal(x, 1) then inf
1954 else 1/quantile_gamma(1 - x, a, 1/b);
1956 mean_inverse_gamma (a, b) :=
1957 if maybe (a > 0) = false or maybe (b > 0) = false
1958 then error ("mean_inverse_gamma: parameters must be positive; found:", a, b)
1959 elseif maybe (a > 1) = false
1960 then error ("mean_inverse_gamma: mean undefined for shape parameter =", a)
1963 mode_inverse_gamma (a, b) :=
1964 if maybe (a > 0) = false or maybe (b > 0) = false
1965 then error ("mode_inverse_gamma: parameters must be positive; found:", a, b)
1968 var_inverse_gamma (a, b) :=
1969 if maybe (a > 0) = false or maybe (b > 0) = false
1970 then error ("var_inverse_gamma: parameters must be positive; found:", a, b)
1971 elseif maybe (a > 2) = false
1972 then error ("var_inverse_gamma: variance undefined for shape parameter =", a)
1973 else b^2/(a - 1)^2/(a - 2);
1975 std_inverse_gamma (a, b) :=
1976 if maybe (a > 0) = false or maybe (b > 0) = false
1977 then error ("std_inverse_gamma: parameters must be positive; found:", a, b)
1978 elseif maybe (a > 2) = false
1979 then error ("std_inverse_gamma: standard deviation undefined for shape parameter =", a)
1980 else b/(a - 1)/sqrt(a - 2);
1982 skewness_inverse_gamma (a, b) :=
1983 if maybe (a > 0) = false or maybe (b > 0) = false
1984 then error ("skewness_inverse_gamma: parameters must be positive; found:", a, b)
1985 elseif maybe (a > 3) = false
1986 then error ("skewness_inverse_gamma: skewness undefined for shape parameter =", a)
1987 else 4*sqrt(a - 2)/(a - 3);
1989 kurtosis_inverse_gamma (a, b) :=
1990 if maybe (a > 0) = false or maybe (b > 0) = false
1991 then error ("kurtosis_inverse_gamma: parameters must be positive; found:", a, b)
1992 elseif maybe (a > 4) = false
1993 then error ("kurtosis_inverse_gamma: kurtosis undefined for shape parameter =", a)
1994 else 6*(5*a - 11)/(a - 3)/(a - 4);
1996 random_inverse_gamma (a, b, [n]) :=
1997 if maybe (a > 0) = false or maybe (b > 0) = false
1998 then error ("random_inverse_gamma: parameters must be positive; found:", a, b)
1999 else block ([listarith: true],
2000 1/random_gamma (a, 1/b, if n = [] then 1 else n[1]));