ruststat/
lib.rs

1#![doc = include_str!("../README.md")]
2
3// ==========================================
4// ==========================================
5// ruststat
6// ==========================================
7// ==========================================
8
9//! Utilities for working with many common random variables.
10//! - probability mass function (pmf), probability density function (pdf)
11//! - cumulative distribution function (cdf)
12//! - percentiles (inverse cdf)
13//! - random number generation
14//! - mean, variance
15//!
16//! Distributions:
17//! - Continuous: beta, chi-square, exponential, F, gamma, normal, log-normal, Pareto (1 thru 4),
18//! Student's t, continuous uniform
19//! - Discrete: binomial, geometric, hypergeometric, negative binomial, poisson
20//!
21//! # Quick Start
22//! ```
23//! use ruststat::*;
24//! // X~N(mu=0,sigma=1.0), find 97.5th percentile
25//! println!("normal percentile: {}", normal_per(0.975, 0.0, 1.0));
26//! // X~Bin(n=10,p=0.7), compute P(X=4)
27//! println!("binomial probability: {}", bin_pmf(4, 10, 0.7));
28//! ```
29//! For convenience, functions can also be accessed via `Structs`.
30//! ```
31//! use ruststat::*;
32//! // X~Beta(alpha=0.5,beta=2.0)
33//! let mut mybeta = BetaDist{alpha:0.5, beta:2.0};
34//! // 30th percentile
35//! println!("percentile: {}", mybeta.per(0.3));
36//! // P(X <= 0.4)
37//! println!("cdf: {}", mybeta.cdf(0.4));
38//! // Random draw
39//! println!("random draw: {}", mybeta.ran());
40//! // Variance
41//! println!("variance: {}", mybeta.var());
42//! ```
43
44// use std::collections::btree_set::Iter;
45use std::f64::consts::PI;
46use rand::{random, Rng};
47use rand::prelude::IndexedRandom;
48// use rand::prelude::IndexedRandom;
49
50const GAMMA: f64 = 0.577215664901532860606512090082;
51
52
53/// Computes sample mean of elements in a Vec
54///
55/// # Example
56/// ```
57/// use ruststat::sample_mean;
58/// let x = vec![1.5, 2.0, 3.5];
59/// println!("Sample mean: {}", sample_mean(&x));
60/// ```
61pub fn sample_mean(x: &Vec<f64>) -> f64 {
62    let x_iter= x.into_iter();
63    let n = x_iter.len();
64    let sum: f64 = x_iter.sum();
65    return sum / n as f64;
66}
67
68/// Computes sample variance of elements in a Vec
69///
70/// # Example
71/// ```
72/// use ruststat::sample_var;
73/// let x = vec![1.5, 2.0, 3.5];
74/// println!("Sample variance: {}", sample_var(&x));
75/// ```
76pub fn sample_var(x: &Vec<f64>) -> f64 {
77    let n = x.len();
78    let xbar = sample_mean(&x);
79    let ss = x.iter().map(|xx| (xx - xbar).powi(2)).sum::<f64>();
80    return ss / (n-1) as f64;
81}
82
83/// Computes sample standard deviation of elements in a Vec
84///
85/// # Example
86/// ```
87/// use ruststat::sample_sd;
88/// let x = vec![1.5, 2.0, 3.5];
89/// println!("Sample SD: {}", sample_sd(&x));
90/// ```
91pub fn sample_sd(x: &Vec<f64>) -> f64 {
92    return sample_var(&x).sqrt();
93}
94
95// ==========================================
96// ==========================================
97// ==========================================
98// Continuous RVs
99// ==========================================
100// ==========================================
101// ==========================================
102
103
104// ==========================================
105// ==========================================
106// Beta Distribution
107// ==========================================
108// ==========================================
109
110/// Struct for the beta distribution `X ~ Beta(alpha, beta)`.
111///
112/// # Parameters
113/// - `alpha > 0`
114/// - `beta > 0`
115/// # Support
116/// - `0 < x < 1`
117/// # Example
118/// Suppose `X ~ Beta(alpha=0.5, beta=2.0)`.
119/// ```
120/// use ruststat::BetaDist;
121/// let mut mybeta = BetaDist{alpha:0.5, beta:2.0};
122/// println!("Probability density function f(0.7): {}", mybeta.pdf(0.7));
123/// println!("Cumulative distribution function P(X<=0.7): {}", mybeta.cdf(0.7));
124/// println!("99th percentile: {}", mybeta.per(0.99));
125/// println!("Random draw: {}", mybeta.ran());
126/// println!("Random vector: {:?}", mybeta.ranvec(5));
127/// println!("Mean: {}", mybeta.mean());
128/// println!("Variance: {}", mybeta.var());
129/// println!("Standard deviation: {}", mybeta.sd());
130/// ```
131pub struct BetaDist {
132    pub alpha: f64,
133    pub beta: f64,
134}
135impl BetaDist {
136    pub fn pdf(&mut self, x: f64) -> f64 {
137        return beta_pdf(x, self.alpha, self.beta);
138    }
139    pub fn cdf(&mut self, x: f64) -> f64 {
140        return beta_cdf(x, self.alpha, self.beta);
141    }
142    pub fn per(&mut self, x: f64) -> f64 {
143        return beta_per(x,self.alpha, self.beta);
144    }
145    pub fn ran(&mut self) -> f64 {
146        return beta_ran(self.alpha, self.beta);
147    }
148    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
149        return beta_ranvec(n, self.alpha, self.beta);
150    }
151    pub fn mean(&mut self) -> f64 {
152        return self.alpha / (self.alpha + self.beta);
153    }
154    pub fn var(&mut self) -> f64 {
155        return self.alpha * self.beta /
156            ((self.alpha + self.beta).powi(2) * (self.alpha + self.beta + 1.0));
157    }
158    pub fn sd(&mut self) -> f64 {
159        return self.var().sqrt();
160    }
161}
162
163
164/// Computes probability density function (pdf) for `X ~ Beta(alpha, beta)`.
165///
166/// # Parameters
167/// - `alpha > 0`
168/// - `beta > 0`
169/// # Support
170/// - `0 < x < 1`
171/// # Example
172/// Suppose `X ~ Beta(alpha=0.5, beta=2.0)`.
173/// ```
174/// use ruststat::beta_pdf;
175/// println!("Probability density function f(0.7): {}", beta_pdf(0.7, 0.5, 2.0));
176/// ```
177pub fn beta_pdf(x: f64, alpha: f64, beta: f64) -> f64 {
178    if alpha <= 0.0 || beta <= 0.0 {
179        println!("NAN produced. Error in function beta_pdf");
180        return f64::NAN;
181    }
182    if x <= 0.0 || x >= 1.0 {
183        return 0.0;
184    }
185    return x.powf(alpha - 1.0) * (1.0 - x).powf(beta - 1.0) / beta_fn(alpha, beta);
186}
187
188
189/// Computes cumulative distribution function (cdf) for `X ~ Beta(alpha, beta)`.
190///
191/// # Parameters
192/// - `alpha > 0`
193/// - `beta > 0`
194/// # Support
195/// - `0 < x < 1`
196/// # Example
197/// Suppose `X ~ Beta(alpha=0.5, beta=2.0)`.
198/// ```
199/// use ruststat::beta_cdf;
200/// println!("P(X <= 0.7): {}", beta_cdf(0.7, 0.5, 2.0));
201/// ```
202pub fn beta_cdf(x: f64, alpha: f64, beta: f64) -> f64 {
203    if alpha <= 0.0 || beta <= 0.0 {
204        println!("NAN produced. Error in function beta_cdf");
205        return f64::NAN;
206    }
207    if x <= 0.0 {
208        return 0.0;
209    }
210    if x >= 1.0 {
211        return 1.0;
212    }
213    return betai(x, alpha, beta);
214}
215
216
217/// Computes a percentile for `X ~ Beta(alpha,beta)`
218/// # Note
219/// Determines the value of `x` such that `P(X <= x) = q`.
220/// # Parameters
221/// - `alpha > 0`
222/// - `beta > 0`
223/// # Support
224/// - `0 < x < 1`
225/// # Example
226/// Suppose `X ~ Beta(alpha=0.5, beta=2.0)`. To find the 80th percentile, use `q=0.80` and
227/// ```
228/// use ruststat::beta_per;
229/// println!("Percentile: {}", beta_per(0.8, 0.5, 2.0));
230/// ```
231pub fn beta_per(q: f64, alpha: f64, beta: f64) -> f64 {
232    return betai_inv(q, alpha, beta);
233
234}
235
236
237/// Random draw from `X ~ Beta(alpha,beta)` distribution.
238///
239/// # Parameters
240/// - `alpha > 0`
241/// - `beta > 0`
242/// # Support
243/// - `0 < x < 1`
244/// # Example
245/// Suppose `X ~ Beta(alpha=0.5, beta=2.0)`. Use
246/// ```
247/// use ruststat::beta_ran;
248/// println!("Random draw: {}", beta_ran(0.5, 2.0));
249/// ```
250pub fn beta_ran(alpha: f64, beta: f64) -> f64 {
251    let x = gamma_ran(alpha, 1.0);
252    let y = gamma_ran(beta, 1.0);
253    return x / (x+y);
254}
255
256
257/// Save random draws from `X ~ Beta(alpha, beta)` distribution into a `Vec`
258///
259/// # Parameters
260/// - `alpha > 0`
261/// - `beta > 0`
262/// # Support
263/// - `0 < x < 1`
264/// # Example
265/// Suppose `X ~ Beta(alpha=0.5, beta=2.0)`. Use
266/// ```
267/// use ruststat::beta_ranvec;
268/// println!("Random Vec: {:?}", beta_ranvec(10, 0.5, 2.0));
269/// ```
270pub fn beta_ranvec(n: i32, alpha: f64, beta: f64) -> Vec<f64> {
271    let mut xvec: Vec<f64> = Vec::new();
272    for _ in 0..n {
273        xvec.push(beta_ran(alpha, beta));
274    }
275    return xvec;
276}
277
278
279// ==========================================
280// ==========================================
281// ChiSquare Distribution
282// ==========================================
283// ==========================================
284
285/// Struct for the chi-square distribution `X ~ ChiSq(nu)`.
286///
287/// # Parameters
288/// - `nu > 0`
289/// # Support
290/// - `x > 0`
291/// # Example
292/// Suppose `X ~ ChiSq(nu=8.0)`. Use.
293/// ```
294/// use ruststat::ChiSqDist;
295/// let mut mychisq = ChiSqDist{nu:8.0};
296/// println!("Probability density function f(4.5): {}", mychisq.pdf(4.5));
297/// println!("Cumulative distribution function P(X<=4.5): {}", mychisq.cdf(4.5));
298/// println!("99th percentile: {}", mychisq.per(0.99));
299/// println!("Random draw: {}", mychisq.ran());
300/// println!("Random vector: {:?}", mychisq.ranvec(5));
301/// println!("Mean: {}", mychisq.mean());
302/// println!("Variance: {}", mychisq.var());
303/// println!("Standard deviation: {}", mychisq.sd());
304/// ```
305pub struct ChiSqDist {
306    pub nu: f64,
307}
308impl ChiSqDist {
309    pub fn pdf(&mut self, x: f64) -> f64 {
310        return chisq_pdf(x, self.nu);
311    }
312    pub fn cdf(&mut self, x: f64) -> f64 {
313        return chisq_cdf(x, self.nu);
314    }
315    pub fn per(&mut self, x: f64) -> f64 {
316        return chisq_per(x, self.nu);
317    }
318    pub fn ran(&mut self) -> f64 {
319        return chisq_ran(self.nu);
320    }
321    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
322        return chisq_ranvec(n, self.nu);
323    }
324    pub fn mean(&mut self) -> f64 {
325        return self.nu;
326    }
327    pub fn var(&mut self) -> f64 {
328        return 2.0 * self.nu;
329    }
330    pub fn sd(&mut self) -> f64 {
331        return self.var().sqrt();
332    }
333}
334
335
336/// Computes probability density function (pdf) for `X ~ ChiSq(nu)`.
337///
338/// # Parameters
339/// - `nu > 0`
340/// # Support
341/// - `x > 0`
342/// # Example
343/// Suppose `X ~ ChiSq(nu=8.0)`.
344/// ```
345/// use ruststat::chisq_pdf;
346/// println!("Probability density function f(5.2): {}", chisq_pdf(5.2, 8.0));
347/// ```
348pub fn chisq_pdf(x: f64, nu: f64) -> f64 {
349    if nu <= 0.0 {
350        println!("NAN produced. Error in function chisq_pdf");
351        return f64::NAN;
352    }
353    if x <= 0.0 {
354        return 0.0;
355    }
356    return gamma_pdf(x, nu/2.0,1.0/2.0);
357}
358
359
360/// Computes cumulative distribution function (cdf) for `X ~ ChiSq(nu)`.
361///
362/// # Parameters
363/// - `nu > 0`
364/// # Support
365/// - `x > 0`
366/// # Example
367/// Suppose `X ~ ChiSq(nu=8.0)`.
368/// ```
369/// use ruststat::chisq_cdf;
370/// println!("P(X<=5.2): {}", chisq_cdf(5.2, 8.0));
371/// ```
372pub fn chisq_cdf(x: f64, nu: f64) -> f64 {
373    if nu <= 0.0 {
374        println!("NAN produced. Error in function chisq_cdf");
375        return f64::NAN;
376    }
377    if x <= 0.0 {
378        return 0.0;
379    }
380    gamma_cdf(x, nu / 2.0, 0.5)
381}
382
383
384/// Computes a percentile for `X ~ ChiSq(nu)`
385/// # Note
386/// Determines the value of `x` such that `P(X <= x) = q`.
387/// # Parameters
388/// - `nu > 0`
389/// # Support
390/// - `x > 0`
391/// # Example
392/// Suppose `X ~ ChiSq(nu=8.0)`. To find the 80th percentile, use `q=0.80` and
393/// ```
394/// use ruststat::chisq_per;
395/// println!("Percentile: {}", chisq_per(0.8, 8.0));
396/// ```
397pub fn chisq_per(p: f64, nu: f64) -> f64 {
398    return gamma_per(p, nu/2.0, 1.0/2.0);
399
400    // let f = |x| { chisq_cdf(x, nu) - p};
401    // let eps = 1.0e-15;
402    // let mut convergency = SimpleConvergency { eps, max_iter:30 };
403    //
404    // let percentile = find_root_secant(eps, 1.0-eps, &f, &mut convergency);
405    //
406    // if p < 0.0 || p > 1.0 || nu <= 0.0 || percentile.is_err() {
407    //     println!("Error in function gamma_percentile");
408    //     return f64::NAN;
409    // }
410    //
411    // return percentile.unwrap();
412}
413
414
415/// Random draw from `X ~ ChiSq(nu)` distribution.
416///
417/// # Parameters
418/// - `nu > 0`
419/// # Support
420/// - `x > 0`
421/// # Example
422/// Suppose `X ~ ChiSq(nu=8.0)`. Use
423/// ```
424/// use ruststat::chisq_ran;
425/// println!("Random draw: {}", chisq_ran(8.0));
426/// ```
427pub fn chisq_ran(nu: f64) -> f64 {
428    return gamma_ran(nu/2.0, 1.0/2.0);
429}
430
431
432/// Save random draws from `X ~ ChiSq(nu)` into a `Vec`.
433///
434/// # Parameters
435/// - `nu > 0`
436/// # Support
437/// - `x > 0`
438/// # Example
439/// Suppose `X ~ ChiSq(nu=8.0)`. Use
440/// ```
441/// use ruststat::chisq_ranvec;
442/// println!("Random Vec: {:?}", chisq_ranvec(10, 8.0));
443/// ```
444pub fn chisq_ranvec(n: i32, nu: f64) -> Vec<f64> {
445    let mut xvec: Vec<f64> = Vec::new();
446    for _ in 0..n {
447        xvec.push(chisq_ran(nu));
448    }
449    return xvec;
450}
451
452
453// ==========================================
454// ==========================================
455// Exponential Distribution
456// ==========================================
457// ==========================================
458
459/// Struct for the exponential distribution `X ~ Exp(lambda)`.
460///
461/// # Parameters
462/// - `lambda > 0`
463/// # Support
464/// - `x > 0`
465/// # Example
466/// Suppose `X ~ Exp(lambda=3.5)`. Use.
467/// ```
468/// use ruststat::ExpDist;
469/// let mut myexp = ExpDist{lambda:3.5};
470/// println!("Probability density function f(1.2): {}", myexp.pdf(1.2));
471/// println!("Cumulative distribution function P(X<=1.2): {}", myexp.cdf(1.2));
472/// println!("99th percentile: {}", myexp.per(0.99));
473/// println!("Random draw: {}", myexp.ran());
474/// println!("Random vector: {:?}", myexp.ranvec(5));
475/// println!("Mean: {}", myexp.mean());
476/// println!("Variance: {}", myexp.var());
477/// println!("Standard deviation: {}", myexp.sd());
478/// ```
479pub struct ExpDist {
480    pub lambda: f64,
481}
482impl ExpDist {
483    pub fn pdf(&mut self, x: f64) -> f64 {
484        return exp_pdf(x, self.lambda);
485    }
486    pub fn cdf(&mut self, x: f64) -> f64 {
487        return exp_cdf(x, self.lambda);
488    }
489    pub fn per(&mut self, x: f64) -> f64 {
490        return exp_per(x, self.lambda);
491    }
492    pub fn ran(&mut self) -> f64 {
493        return exp_ran(self.lambda);
494    }
495    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
496        return exp_ranvec(n, self.lambda);
497    }
498    pub fn mean(&mut self) -> f64 {
499        return 1.0 / self.lambda;
500    }
501    pub fn var(&mut self) -> f64 {
502        return 1.0 / self.lambda.powi(2);
503    }
504    pub fn sd(&mut self) -> f64 {
505        return self.var().sqrt();
506    }
507}
508
509
510/// Computes probability density function (pdf) for `X ~ Exp(lambda)`.
511///
512/// # Parameters
513/// - `lambda > 0`
514/// # Support
515/// - `x > 0`
516/// # Example
517/// Suppose `X ~ Exp(lambda=8.0)`.
518/// ```
519/// use ruststat::exp_pdf;
520/// println!("Probability density function f(0.2): {}", exp_pdf(0.2, 8.0));
521/// ```
522pub fn exp_pdf(x: f64, lambda: f64) -> f64 {
523    if lambda <= 0.0 {
524        println!("NAN produced. Error in function exp_pdf");
525        return f64::NAN;
526    }
527    if x <= 0.0 {
528        return 0.0;
529    }
530    return lambda * (-lambda*x).exp();
531}
532
533
534/// Computes cumulative distribution function (cdf) for `X ~ Exp(lambda)`.
535///
536/// # Parameters
537/// - `lambda > 0`
538/// # Support
539/// - `x > 0`
540/// # Example
541/// Suppose `X ~ Exp(lambda=8.0)`.
542/// ```
543/// use ruststat::exp_cdf;
544/// println!("P(X<=0.8): {}", exp_cdf(0.8, 8.0));
545/// ```
546pub fn exp_cdf(x: f64, lambda: f64) -> f64 {
547    if lambda <= 0.0 {
548        println!("NAN produced. Error in function exp_cdf");
549        return f64::NAN;
550    }
551    if x <= 0.0 {
552        return 0.0;
553    }
554
555    return if x < 2.0 {
556        gser(x * lambda, 1.0)
557    } else {
558        1.0 - gcf(x * lambda, 1.0)
559    }
560}
561
562/// Computes a percentile for `X ~ Exp(lambda)`
563/// # Note
564/// Determines the value of `x` such that `P(X <= x) = q`.
565/// # Parameters
566/// - `lambda > 0`
567/// # Support
568/// - `x > 0`
569/// # Example
570/// Suppose `X ~ Exp(lambda=8.0)`. To find the 80th percentile, use `q=0.80` and
571/// ```
572/// use ruststat::exp_per;
573/// println!("Percentile: {}", exp_per(0.8, 8.0));
574/// ```
575pub fn exp_per(p: f64, lambda: f64) -> f64 {
576    return -(1.0-p).ln() / lambda;
577
578    // let f = |x| { exp_cdf(x,lambda) - p};
579    // let eps = 1.0e-15;
580    // let mut convergency = SimpleConvergency { eps, max_iter:30 };
581    //
582    // let percentile = find_root_secant(0.0, 1.0/lambda, &f, &mut convergency);
583    //
584    // if p < 0.0 || p > 1.0 || lambda <= 0.0 || percentile.is_err() {
585    //     println!("Error in function ficdf");
586    //     return f64::NAN;
587    // }
588    //
589    // return percentile.unwrap();
590}
591
592
593/// Random draw from `X ~ Exp(lambda)` distribution.
594///
595/// # Parameters
596/// - `lambda > 0`
597/// # Support
598/// - `x > 0`
599/// # Example
600/// Suppose `X ~ Exp(lambda=8.0)`. Use
601/// ```
602/// use ruststat::exp_ran;
603/// println!("Random draw: {}", exp_ran(8.0));
604/// ```
605pub fn exp_ran(lambda: f64) -> f64 {
606    let u: f64;
607    u = random();
608    // u = rand::thread_rng().gen();
609    return -(1.0-u).ln()/lambda;
610}
611
612
613/// Save random draws from `X ~ Exp(lambda)` into a `Vec`.
614///
615/// # Parameters
616/// - `lambda > 0`
617/// # Support
618/// - `x > 0`
619/// # Example
620/// Suppose `X ~ Exp(lambda=8.0)`. Use
621/// ```
622/// use ruststat::exp_ranvec;
623/// println!("Random vector: {:?}", exp_ranvec(10, 8.0));
624/// ```
625pub fn exp_ranvec(n: i32, lambda: f64) -> Vec<f64> {
626    let mut xvec: Vec<f64> = Vec::new();
627    for _ in 0..n {
628        xvec.push(exp_ran(lambda));
629    }
630    return xvec;
631}
632
633
634// ==========================================
635// ==========================================
636// F Distribution
637// ==========================================
638// ==========================================
639
640/// Struct for the F distribution `X ~ F(nu1, nu2)`.
641///
642/// # Parameters
643/// - `nu1 > 0`
644/// - `nu2 > 0`
645/// # Support
646/// - `x > 0`
647/// # Example
648/// Suppose `X ~ F(nu1=4.0, nu2=18.0)`. Use.
649/// ```
650/// use ruststat::FDist;
651/// let mut myf = FDist{nu1:4.0, nu2:18.0};
652/// println!("Probability density function f(2.5): {}", myf.pdf(2.5));
653/// println!("Cumulative distribution function P(X<=2.5): {}", myf.cdf(2.5));
654/// println!("99th percentile: {}", myf.per(0.99));
655/// println!("Random draw: {}", myf.ran());
656/// println!("Random vector: {:?}", myf.ranvec(5));
657/// println!("Mean: {}", myf.mean());
658/// println!("Variance: {}", myf.var());
659/// println!("Standard deviation: {}", myf.sd());
660/// ```
661pub struct FDist {
662    pub nu1: f64,
663    pub nu2: f64,
664}
665impl FDist {
666    pub fn pdf(&mut self, x: f64) -> f64 {
667        return f_pdf(x, self.nu1, self.nu2);
668    }
669    pub fn cdf(&mut self, x: f64) -> f64 {
670        return f_cdf(x, self.nu1, self.nu2);
671    }
672    pub fn per(&mut self, x: f64) -> f64 {
673        return f_per(x, self.nu1, self.nu2);
674    }
675    pub fn ran(&mut self) -> f64 {
676        return f_ran(self.nu1, self.nu2);
677    }
678    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
679        return f_ranvec(n, self.nu1, self.nu2);
680    }
681    pub fn mean(&mut self) -> f64 {
682        return self.nu2 / (self.nu2-2.0);
683    }
684    pub fn var(&mut self) -> f64 {
685        return 2.0 * self.nu2.powi(2) * (self.nu1 + self.nu2 - 2.0) /
686            (self.nu1 * (self.nu2 - 2.0).powi(2) * (self.nu2 - 4.0));
687    }
688    pub fn sd(&mut self) -> f64 {
689        return self.var().sqrt();
690    }
691}
692
693
694/// Computes probability density function (pdf) for `X ~ F(nu1, nu2)`.
695///
696/// # Parameters
697/// - `nu1 > 0`
698/// - `nu2 > 0`
699/// # Support
700/// - `x > 0`
701/// # Example
702/// Suppose `X ~ F(nu1=4.0, nu2=18.0)`. Use.
703/// ```
704/// use ruststat::f_pdf;
705/// println!("Probability density function f(2.5): {}", f_pdf(2.5, 4.0, 18.0));
706/// ```
707pub fn f_pdf(x: f64, nu1: f64, nu2: f64) -> f64 {
708    if nu1 <= 0.0 || nu2 <= 0.0 {
709        println!("NAN produced. Error in function f_pdf");
710        return f64::NAN;
711    }
712    if x <= 0.0 {
713        return 0.0;
714    }
715    return ((nu1*x).powf(nu1) * nu2.powf(nu2) / (nu1*x + nu2).powf(nu1+nu2)).sqrt() /
716        (x * beta_fn(nu1/2.0, nu2/2.0));
717}
718
719
720/// Computes cumulative distribution function (cdf) for `X ~ F(nu1, nu2)`.
721///
722/// # Parameters
723/// - `nu1 > 0`
724/// - `nu2 > 0`
725/// # Support
726/// - `x > 0`
727/// # Example
728/// Suppose `X ~ F(nu1=4.0, nu2=18.0)`. Use.
729/// ```
730/// use ruststat::f_cdf;
731/// println!("P(X<=2.5): {}", f_cdf(2.5, 4.0, 18.0));
732/// ```
733pub fn f_cdf(x: f64, nu1: f64, nu2: f64) -> f64 {
734    if nu1 <= 0.0 || nu2 <= 0.0 {
735        println!("NAN produced. Error in function f_cdf");
736        return f64::NAN;
737    }
738    if x <= 0.0 {
739        return 0.0;
740    }
741    return 1.0 - betai(nu2 / (nu2 + nu1 * x), nu2 / 2.0, nu1 / 2.0);
742}
743
744
745/// Computes a percentile for `X ~ F(nu1, nu2)`.
746///
747/// # Note
748/// Determines the value of `x` such that `P(X <= x) = q`.
749/// # Parameters
750/// - `nu1 > 0`
751/// - `nu2 > 0`
752/// # Support
753/// - `x > 0`
754/// # Example
755/// Suppose `X ~ F(nu1=4.0, nu2=18.0)`. To find the 80th percentile, use `q=0.80` and
756/// ```
757/// use ruststat::f_per;
758/// println!("Percentile: {}", f_per(0.8, 4.0, 18.0));
759/// ```
760pub fn f_per(p: f64, nu1: f64, nu2: f64) -> f64 {
761    return nu2/nu1 * (1.0 / beta_per(1.0-p,nu2/2.0,nu1/2.0) - 1.0);
762    // let f = |x| { f_cdf(x,nu1, nu2) - p};
763    // let eps = 1.0e-30;
764    // let mut convergency = SimpleConvergency { eps, max_iter:30 };
765    //
766    // let percentile = find_root_secant(0f64, 1f64, &f, &mut convergency);
767    //
768    // if p < 0.0 || p > 1.0 || nu1 <= 0.0 || nu2 <= 0.0 || percentile.is_err() {
769    //     println!("Error in function ficdf");
770    //     return f64::NAN;
771    // }
772    //
773    // return percentile.unwrap();
774}
775
776
777/// Random draw from `X ~ F(nu1, nu2)` distribution.
778///
779/// # Parameters
780/// - `nu1 > 0`
781/// - `nu2 > 0`
782/// # Support
783/// - `x > 0`
784/// # Example
785/// Suppose `X ~ F(nu1=4.0, nu2=18.0)`. Use
786/// ```
787/// use ruststat::f_ran;
788/// println!("Random draw: {}", f_ran(4.0, 18.0));
789/// ```
790pub fn f_ran(nu1: f64, nu2: f64) -> f64 {
791    let x = beta_ran(nu1/2.0, nu2/2.0);
792    return nu2 * x / (nu1 * (1.0-x));
793}
794
795/// Save random draws from `X ~ F(nu1, nu2)` distribution into a `Vec`
796///
797/// # Parameters
798/// - `nu1 > 0`
799/// - `nu2 > 0`
800/// # Support
801/// - `x > 0`
802/// # Example
803/// Suppose `X ~ F(alpha=4.0, beta=18.0)`. Use
804/// ```
805/// use ruststat::f_ranvec;
806/// println!("Random Vec: {:?}", f_ranvec(10, 4.0, 18.0));
807/// ```
808pub fn f_ranvec(n: i32, nu1: f64, nu2: f64) -> Vec<f64> {
809    let mut xvec: Vec<f64> = Vec::new();
810    for _ in 0..n {
811        xvec.push(f_ran(nu1, nu2));
812    }
813    return xvec;
814}
815
816
817// ==========================================
818// ==========================================
819// Gamma Distribution
820// ==========================================
821// ==========================================
822
823/// Struct for the gamma distribution `X ~ Gamma(alpha, beta)`.
824///
825/// # Parameters
826/// - `alpha > 0`
827/// - `beta > 0`
828/// # Support
829/// - `x > 0`
830/// # Example
831/// Suppose `X ~ Gamma(alpha=4.0, beta=2.7)`. Use.
832/// ```
833/// use ruststat::GammaDist;
834/// let mut mygamma = GammaDist{alpha:4.0, beta:2.7};
835/// println!("Probability density function f(3.9): {}", mygamma.pdf(3.9));
836/// println!("Cumulative distribution function P(X<=3.9): {}", mygamma.cdf(3.9));
837/// println!("99th percentile: {}", mygamma.per(0.99));
838/// println!("Random draw: {}", mygamma.ran());
839/// println!("Random vector: {:?}", mygamma.ranvec(5));
840/// println!("Mean: {}", mygamma.mean());
841/// println!("Variance: {}", mygamma.var());
842/// println!("Standard deviation: {}", mygamma.sd());
843/// ```
844pub struct GammaDist {
845    pub alpha: f64,
846    pub beta: f64,
847}
848impl GammaDist {
849    pub fn pdf(&mut self, x: f64) -> f64 {
850        return gamma_pdf(x, self.alpha, self.beta);
851    }
852    pub fn cdf(&mut self, x: f64) -> f64 {
853        return gamma_cdf(x, self.alpha, self.beta);
854    }
855    pub fn per(&mut self, x: f64) -> f64 {
856        return gamma_per(x, self.alpha, self.beta);
857    }
858    pub fn ran(&mut self) -> f64 {
859        return gamma_ran(self.alpha, self.beta);
860    }
861    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
862        return gamma_ranvec(n, self.alpha, self.beta);
863    }
864    pub fn mean(&mut self) -> f64 {
865        return self.alpha / self.beta;
866    }
867    pub fn var(&mut self) -> f64 {
868        return self.alpha / self.beta.powi(2);
869    }
870    pub fn sd(&mut self) -> f64 {
871        return self.var().sqrt();
872    }
873}
874
875
876/// Computes probability density function (pdf) for `X ~ Gamma(alpha, beta)`.
877///
878/// # Parameters
879/// - `alpha > 0`
880/// - `beta > 0`
881/// # Support
882/// - `x > 0`
883/// # Example
884/// Suppose `X ~ Gamma(alpha=4.0, beta=2.7)`. Use.
885/// ```
886/// use ruststat::gamma_pdf;
887/// println!("Probability density function f(3.9): {}", gamma_pdf(3.9, 4.0, 2.7));
888pub fn gamma_pdf(x: f64, alpha: f64, beta: f64) -> f64 {
889    if alpha <= 0.0 || beta <= 0.0 {
890        println!("NAN produced. Error in function gamma_pdf");
891        return f64::NAN;
892    }
893    if x <= 0.0 {
894        return 0.0;
895    }
896    return beta.powf(alpha) / gamma(alpha) * x.powf(alpha-1.0) * (-beta*x).exp();
897}
898
899
900/// Computes cumulative distribution function (cdf) for `X ~ Gamma(alpha, beta)`.
901///
902/// # Parameters
903/// - `alpha > 0`
904/// - `beta > 0`
905/// # Support
906/// - `x > 0`
907/// # Example
908/// Suppose `X ~ Gamma(alpha=4.0, beta=2.7)`. Use.
909/// ```
910/// use ruststat::gamma_cdf;
911/// println!("P(X<=3.9): {}", gamma_cdf(3.9, 4.0, 2.7));
912/// ```
913pub fn gamma_cdf(x: f64, alpha: f64, beta: f64) -> f64 {
914    if alpha <= 0.0 || beta <= 0.0 {
915        println!("NAN produced. Error in function gamma_pdf");
916        return f64::NAN;
917    }
918    if x <= 0.0 {
919        return 0.0;
920    }
921
922    return if x < (alpha + 1.0) {
923        gser(x * beta, alpha)
924    } else {
925        1.0 - gcf(x * beta, alpha)
926    }
927}
928
929
930/// Computes a percentile for `X ~ Gamma(alpha, beta)`.
931///
932/// # Note
933/// Determines the value of `x` such that `P(X <= x) = q`.
934/// # Parameters
935/// - `alpha > 0`
936/// - `beta > 0`
937/// # Support
938/// - `x > 0`
939/// # Example
940/// Suppose `X ~ Gamma(alpha=4.0, beta=2.7)`. To find the 80th percentile, use `q=0.80` and
941/// ```
942/// use ruststat::gamma_per;
943/// println!("Percentile: {}", gamma_per(0.8, 4.0, 2.7));
944/// ```
945pub fn gamma_per(p: f64, alpha: f64, beta: f64) -> f64 {
946    return gammai_inv(p, alpha) / beta;
947    // let f = |x| { gamma_cdf(x,a,b) - p};
948    // let eps = 1.0e-15;
949    // let mut convergency = SimpleConvergency { eps, max_iter:30 };
950    //
951    // let percentile = find_root_secant(eps, a/b, &f, &mut convergency);
952    //
953    // if p < 0.0 || p > 1.0 || a <= 0.0 || b <= 0.0 ||percentile.is_err() {
954    //     println!("Error in function gamma_percentile");
955    //     return f64::NAN;
956    // }
957    //
958    // return percentile.unwrap();
959}
960
961
962/// Random draw from `X ~ Gamma(alpha, beta)` distribution.
963///
964/// # Parameters
965/// - `alpha > 0`
966/// - `beta > 0`
967/// # Support
968/// - `x > 0`
969/// # Example
970/// Suppose `X ~ Gamma(alpha=4.0, beta=2.7)`. Use
971/// ```
972/// use ruststat::gamma_ran;
973/// println!("Random draw: {}", gamma_ran(4.0, 2.7));
974/// ```
975pub fn gamma_ran(alpha: f64, beta: f64) -> f64 {
976
977    let (d, c, mut x, mut v, mut u): (f64, f64, f64, f64, f64);
978    d = alpha - 1.0/3.0;
979    c = 1.0/(9.0*d).sqrt();
980
981    loop {
982        x = normal_ran(0.0, 1.0);
983        v = 1.0 + c * x;
984        while v <= 0.0 {
985            x = normal_ran(0.0, 1.0);
986            v = 1.0 + c * x;
987            break;
988        }
989
990        v = v.powi(3);
991        u = random();
992        // u = rand::thread_rng().gen();
993
994        if u < 1.0 - 0.0331 * x.powi(4) {
995            return d * v / beta;
996        }
997        if u.ln() < 0.5 * x.powi(2) + d * (1.0 - v + v.ln()) {
998            return d * v / beta;
999        }
1000    }
1001}
1002
1003
1004/// Save random draws from `X ~ Gamma(alpha, beta)` distribution into a `Vec`
1005///
1006/// # Parameters
1007/// - `alpha > 0`
1008/// - `beta > 0`
1009/// # Support
1010/// - `x > 0`
1011/// # Example
1012/// Suppose `X ~ Gamma(alpha=4.0, beta=2.7)`. Use
1013/// ```
1014/// use ruststat::gamma_ranvec;
1015/// println!("Random Vec: {:?}", gamma_ranvec(10, 4.0, 2.7));
1016/// ```
1017pub fn gamma_ranvec(n: i32, alpha: f64, beta: f64) -> Vec<f64> {
1018    let mut xvec: Vec<f64> = Vec::new();
1019    for _ in 0..n {
1020        xvec.push(gamma_ran(alpha, beta));
1021    }
1022    return xvec;
1023}
1024
1025
1026// ==========================================
1027// ==========================================
1028// Gumbel Distribution
1029// ==========================================
1030// ==========================================
1031
1032/// Struct for the Gumbel distribution `X ~ Gumbel(mu, beta)`.
1033///
1034/// # Parameters
1035/// - Location: `-infinity < mu < infinity`
1036/// - Scale: `beta > 0`
1037/// # Support
1038/// - `-infinity < x < infinity`
1039/// # Example
1040/// Suppose `X ~ Gumbel(mu=4.2, beta=1.8)`. Use.
1041/// ```
1042/// use ruststat::GumbelDist;
1043/// let mut mygum = GumbelDist{mu:4.2, beta:1.8};
1044/// println!("Probability density function f(3.9): {}", mygum.pdf(3.9));
1045/// println!("Cumulative distribution function P(X<=3.9): {}", mygum.cdf(3.9));
1046/// println!("99th percentile: {}", mygum.per(0.99));
1047/// println!("Random draw: {}", mygum.ran());
1048/// println!("Random vector: {:?}", mygum.ranvec(5));
1049/// println!("Mean: {}", mygum.mean());
1050/// println!("Variance: {}", mygum.var());
1051/// println!("Standard deviation: {}", mygum.sd());
1052/// ```
1053pub struct GumbelDist {
1054    pub mu: f64,    //location
1055    pub beta: f64,  //scale
1056}
1057impl GumbelDist {
1058    pub fn pdf(&mut self, x: f64) -> f64 {
1059        return gumbel_pdf(x, self.mu, self.beta);
1060    }
1061    pub fn cdf(&mut self, x: f64) -> f64 {
1062        return gumbel_cdf(x, self.mu, self.beta);
1063    }
1064    pub fn per(&mut self, x: f64) -> f64 {
1065        return gumbel_per(x, self.mu, self.beta);
1066    }
1067    pub fn ran(&mut self) -> f64 {
1068        return gumbel_ran(self.mu, self.beta);
1069    }
1070    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
1071        return gumbel_ranvec(n, self.mu, self.beta);
1072    }
1073    pub fn mean(&mut self) -> f64 {
1074        return self.mu + self.beta * GAMMA;
1075    }
1076    pub fn var(&mut self) -> f64 {
1077        return PI.powi(2)/6.0 * self.beta.powi(2);
1078    }
1079    pub fn sd(&mut self) -> f64 {
1080        return self.var().sqrt();
1081    }
1082}
1083
1084
1085/// Computes probability density function (pdf) for `X ~ Gumbel(mu, beta)`.
1086///
1087/// # Parameters
1088/// - Location: `-infinity < mu < infinity`
1089/// - Scale: `beta > 0`
1090/// # Support
1091/// - `-infinity < x < infinity`
1092/// # Example
1093/// Suppose `X ~ Gumbel(mu=5.5, beta=2.0)`. Use.
1094/// ```
1095/// use ruststat::gumbel_pdf;
1096/// println!("Probability density function f(3.9): {}", gumbel_pdf(3.9, 5.5, 2.0));
1097pub fn gumbel_pdf(x: f64, mu: f64, beta: f64) -> f64 {
1098    if beta <= 0.0 {
1099        println!("NAN produced. Error in function gumbel_pdf");
1100        return f64::NAN;
1101    }
1102    return 1.0 / beta * (-((x-mu)/beta + (-(x-mu)/beta).exp())).exp();
1103}
1104
1105
1106/// Computes cumulative distribution function (cdf) for `X ~ Gumbel(mu, beta)`.
1107///
1108/// # Parameters
1109/// - Location: `-infinity < mu < infinity`
1110/// - Scale: `beta > 0`
1111/// # Support
1112/// - `-infinity < x < infinity`
1113/// # Example
1114/// Suppose `X ~ Gumbel(mu=5.5, beta=2.0)`. Use.
1115/// ```
1116/// use ruststat::gumbel_cdf;
1117/// println!("P(X<=3.9): {}", gumbel_cdf(3.9, 5.5, 2.0));
1118/// ```
1119pub fn gumbel_cdf(x: f64, mu: f64, beta: f64) -> f64 {
1120    if beta <= 0.0 {
1121        println!("NAN produced. Error in function gumbel_pdf");
1122        return f64::NAN;
1123    }
1124
1125    return (-(-(x-mu)/beta).exp()).exp();
1126}
1127
1128
1129/// Computes a percentile for `X ~ Gumbel(mu, beta)`.
1130///
1131/// # Note
1132/// Determines the value of `x` such that `P(X <= x) = q`.
1133/// # Parameters
1134/// - Location: `-infinity < mu < infinity`
1135/// - Scale: `beta > 0`
1136/// # Support
1137/// - `-infinity < x < infinity`
1138/// # Example
1139/// Suppose `X ~ Gumbel(mu=5.5, beta=2.0)`. To find the 80th percentile, use `q=0.80` and
1140/// ```
1141/// use ruststat::gumbel_per;
1142/// println!("Percentile: {}", gumbel_per(0.8, 5.5, 2.0));
1143/// ```
1144pub fn gumbel_per(p: f64, mu: f64, beta: f64) -> f64 {
1145    return mu - beta * (-p.ln()).ln();
1146}
1147
1148
1149/// Random draw from `X ~ Gumbel(mu, beta)` distribution.
1150///
1151/// # Parameters
1152/// - Location: `-infinity < mu < infinity`
1153/// - Scale: `beta > 0`
1154/// # Support
1155/// - `-infinity < x < infinity`
1156/// # Example
1157/// Suppose `X ~ Gumbel(mu=5.5, beta=2.0)`. Use
1158/// ```
1159/// use ruststat::gumbel_ran;
1160/// println!("Random draw: {:?}", gumbel_ran(5.5, 2.0));
1161/// ```
1162pub fn gumbel_ran(mu: f64, beta: f64) -> f64 {
1163    return mu - beta * (-unif_ran(0.0,1.0).ln()).ln();
1164}
1165
1166
1167/// Random Vector taken from `X ~ Gumbel(mu, beta)` distribution.
1168///
1169/// # Parameters
1170/// - Location: `-infinity < mu < infinity`
1171/// - Scale: `beta > 0`
1172/// # Support
1173/// - `-infinity < x < infinity`
1174/// # Example
1175/// Suppose `X ~ Gumbel(mu=5.5, beta=2.0)`. Use
1176/// ```
1177/// use ruststat::gumbel_ranvec;
1178/// println!("Random Vec: {:?}", gumbel_ranvec(10, 5.5, 2.0));
1179/// ```
1180pub fn gumbel_ranvec(n: i32, mu: f64, beta: f64) -> Vec<f64> {
1181    let mut xvec: Vec<f64> = Vec::new();
1182    for _ in 0..n {
1183        xvec.push(mu - beta * (-unif_ran(0.0,1.0).ln()).ln());
1184    }
1185    return xvec;
1186}
1187
1188
1189// ==========================================
1190// ==========================================
1191// LogNormal Distribution
1192// ==========================================
1193// ==========================================
1194
1195/// Struct for the log-normal distribution `X ~ LogNormal(mu, sigma)`.
1196///
1197/// # Parameters
1198/// - `-infinity < mu < infinity`
1199/// - `sigma > 0`
1200/// # Support
1201/// - `x > 0`
1202/// # Example
1203/// Suppose `X ~ LogNormal(mu=0.0, sigma=1.0)`. Use
1204/// ```
1205/// use ruststat::LogNormalDist;
1206/// let mut mylogn = LogNormalDist{mu:0.0, sigma:1.0};
1207/// println!("Probability density function f(5.2): {}", mylogn.pdf(5.2));
1208/// println!("Cumulative distribution function P(X<=5.2): {}", mylogn.cdf(5.2));
1209/// println!("99th percentile: {}", mylogn.per(0.99));
1210/// println!("Random draw: {}", mylogn.ran());
1211/// println!("Random vector: {:?}", mylogn.ranvec(5));
1212/// println!("Mean: {}", mylogn.mean());
1213/// println!("Variance: {}", mylogn.var());
1214/// println!("Standard deviation: {}", mylogn.sd());
1215/// ```
1216pub struct LogNormalDist {
1217    pub mu: f64,
1218    pub sigma: f64,
1219}
1220impl LogNormalDist {
1221    pub fn pdf(&mut self, x: f64) -> f64 {
1222        return lognormal_pdf(x, self.mu, self.sigma);
1223    }
1224    pub fn cdf(&mut self, x: f64) -> f64 {
1225        return lognormal_cdf(x, self.mu, self.sigma);
1226    }
1227    pub fn per(&mut self, x: f64) -> f64 {
1228        return lognormal_per(x,self.mu, self.sigma);
1229    }
1230    pub fn ran(&mut self) -> f64 {
1231        return lognormal_ran(self.mu, self.sigma);
1232    }
1233    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
1234        return lognormal_ranvec(n, self.mu, self.sigma);
1235    }
1236    pub fn mean(&mut self) -> f64 {
1237        return (self.mu + 0.5 * self.sigma.powi(2)).exp();
1238    }
1239    pub fn var(&mut self) -> f64 {
1240        return (self.sigma.powi(2).exp() - 1.0) *
1241            (2.0 * self.mu + self.sigma.powi(2)).exp();
1242    }
1243    pub fn sd(&mut self) -> f64 {
1244        return self.var().sqrt();
1245    }
1246}
1247
1248
1249/// Computes probability density function (pdf) for `X ~ LogNormal(mu, sigma)`.
1250///
1251/// # Parameters
1252/// - `-infinity < mu < infinity`
1253/// - `sigma > 0`
1254/// # Support
1255/// - `x > 0`
1256/// # Example
1257/// Suppose `X ~ LogNormal(mu=0.0, sigma=1.0)`. Use.
1258/// ```
1259/// use ruststat::lognormal_pdf;
1260/// println!("Probability density function f(2.1): {}", lognormal_pdf(2.0, 0.0, 1.0));
1261pub fn lognormal_pdf(x: f64, mu: f64, sigma: f64) -> f64 {
1262    if sigma <= 0.0 {
1263        println!("NAN produced. Error in function lognormal_pdf");
1264        return f64::NAN;
1265    }
1266    if x <= 0.0 {
1267        return 0.0;
1268    }
1269    return (-(x.ln()-mu).powi(2) / (2.0*sigma.powi(2))).exp() /
1270            (x * sigma * (2.0 * PI).sqrt());
1271}
1272
1273
1274/// Computes cumulative distribution function (cdf) for `X ~ LogNormal(mu, sigma)`.
1275///
1276/// # Parameters
1277/// - `-infinity < mu < infinity`
1278/// - `sigma > 0`
1279/// # Support
1280/// - `x > 0`
1281/// # Example
1282/// Suppose `X ~ LogNormal(mu=0.0, sigma=1.0)`. Use.
1283/// ```
1284/// use ruststat::lognormal_cdf;
1285/// println!("P(X<=2.1): {}", lognormal_cdf(2.0, 0.0, 1.0));
1286/// ```
1287pub fn lognormal_cdf(x: f64, mu: f64, sigma: f64) -> f64 {
1288    if sigma <= 0.0 {
1289        println!("NAN produced. Error in function lognormal_cdf");
1290        return f64::NAN;
1291    }
1292    if x <= 0.0 {
1293        return 0.0;
1294    }
1295
1296    return 0.5 * (1.0 + erf((x.ln() - mu)/(sigma*2.0f64.sqrt())));
1297}
1298
1299
1300/// Computes a percentile for `X ~ LogNormal(mu, sigma)`.
1301///
1302/// # Note
1303/// Determines the value of `x` such that `P(X <= x) = q`.
1304/// # Parameters
1305/// - `-infinity < mu < infinity`
1306/// - `sigma > 0`
1307/// # Support
1308/// - `x > 0`
1309/// # Example
1310/// Suppose `X ~ LogNormal(mu=0.0, sigma=1.0)`. To find the 80th percentile, use `q=0.80` and
1311/// ```
1312/// use ruststat::lognormal_per;
1313/// println!("Percentile: {}", lognormal_per(0.8, 0.0, 1.0));
1314/// ```
1315pub fn lognormal_per(p: f64, mu: f64, sigma: f64) -> f64 {
1316    return (2f64.sqrt() * sigma * erf_inv(2.0*p-1.0) + mu).exp();
1317}
1318
1319
1320/// Random draw from `X ~ LogNormal(mu, sig)` distribution.
1321///
1322/// # Parameters
1323/// - `-infinity < mu < infinity`
1324/// - `sigma > 0`
1325/// # Support
1326/// - `x > 0`
1327/// # Example
1328/// Suppose `X ~ LogNormal(mu=0.0, sigma=1.0)`. Use
1329/// ```
1330/// use ruststat::lognormal_ran;
1331/// println!("Random draw: {}", lognormal_ran(0.0, 1.0));
1332/// ```
1333pub fn lognormal_ran(mu: f64, sigma: f64) -> f64 {
1334    return normal_ran(mu, sigma).exp();
1335}
1336
1337
1338/// Save random draws from `X ~ LogNormal(mu, sigma)` distribution into a `Vec`
1339///
1340/// # Parameters
1341/// - `-infinity < mu < infinity`
1342/// - `sigma > 0`
1343/// # Support
1344/// - `x > 0`
1345/// # Example
1346/// Suppose `X ~ LogNormal(mu=0.0, sigma=1.0)`. Use
1347/// ```
1348/// use ruststat::lognormal_ranvec;
1349/// println!("Random Vec: {:?}", lognormal_ranvec(10, 0.5, 2.0));
1350/// ```
1351pub fn lognormal_ranvec(n: i32, mu: f64, sigma: f64) -> Vec<f64> {
1352    let mut xvec: Vec<f64> = Vec::new();
1353    for _ in 0..n {
1354        xvec.push(lognormal_ran(mu, sigma));
1355    }
1356    return xvec;
1357}
1358
1359
1360// ==========================================
1361// ==========================================
1362// Normal Distribution
1363// ==========================================
1364// ==========================================
1365
1366/// Struct for the normal distribution `X ~ Normal(mu, sigma)`.
1367///
1368/// # Parameters
1369/// - `-infinity < mu < infinity`
1370/// - `sigma > 0`
1371/// # Support
1372/// - `-infinity < x < infinity`
1373/// # Example
1374/// Suppose `X ~ Normal(mu=100.0, sigma=16.0)`. Use
1375/// ```
1376/// use ruststat::NormalDist;
1377/// let mut mynormal = NormalDist{mu:100.0, sigma:16.0};
1378/// println!("Probability density function f(110.0): {}", mynormal.pdf(110.0));
1379/// println!("Cumulative distribution function P(X<=110.0): {}", mynormal.cdf(110.0));
1380/// println!("99th percentile: {}", mynormal.per(0.99));
1381/// println!("Random draw: {}", mynormal.ran());
1382/// println!("Random vector: {:?}", mynormal.ranvec(5));
1383/// println!("Mean: {}", mynormal.mean());
1384/// println!("Variance: {}", mynormal.var());
1385/// println!("Standard deviation: {}", mynormal.sd());
1386/// ```
1387pub struct NormalDist {
1388    pub mu: f64,
1389    pub sigma: f64,
1390}
1391impl NormalDist {
1392    pub fn pdf(&mut self, x: f64) -> f64 {
1393        return normal_pdf(x, self.mu, self.sigma);
1394    }
1395    pub fn cdf(&mut self, x: f64) -> f64 {
1396        return normal_cdf(x, self.mu, self.sigma);
1397    }
1398    pub fn per(&mut self, x: f64) -> f64 {
1399        return normal_per(x,self.mu, self.sigma);
1400    }
1401    pub fn ran(&mut self) -> f64 {
1402        return normal_ran(self.mu, self.sigma);
1403    }
1404    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
1405        return normal_ranvec(n,self.mu, self.sigma);
1406    }
1407    pub fn mean(&mut self) -> f64 {
1408        return self.mu;
1409    }
1410    pub fn var(&mut self) -> f64 {
1411        return self.sigma * self.sigma;
1412    }
1413    pub fn sd(&mut self) -> f64 {
1414        return self.sigma;
1415    }
1416}
1417
1418
1419/// Computes probability density function (pdf) for `X ~ Normal(mu, sigma)`.
1420///
1421/// # Parameters
1422/// - `-infinity < mu < infinity`
1423/// - `sigma > 0`
1424/// # Support
1425/// - `-infinity < x < infinity`
1426/// # Example
1427/// Suppose `X ~ Normal(mu=100.0, sigma=16.0)`. Use.
1428/// ```
1429/// use ruststat::normal_pdf;
1430/// println!("Probability density function f(110.0): {}", normal_pdf(110.0, 100.0, 16.0));
1431pub fn normal_pdf(x: f64, mu: f64, sigma: f64) -> f64 {
1432    if sigma <= 0.0 {
1433        println!("NAN produced. Error in function normal_pdf");
1434        return f64::NAN;
1435    }
1436    return 1.0 / (2.0 * PI * sigma.powi(2)).sqrt() *
1437        (-0.5*((x-mu)/sigma).powi(2)).exp();
1438}
1439
1440
1441/// Computes cumulative distribution function (cdf) for `X ~ Normal(mu, sigma)`.
1442///
1443/// # Parameters
1444/// - `-infinity < mu < infinity`
1445/// - `sigma > 0`
1446/// # Support
1447/// - `-infinity < x < infinity`
1448/// # Example
1449/// Suppose `X ~ Normal(mu=100.0, sigma=16.0)`. Use.
1450/// ```
1451/// use ruststat::normal_cdf;
1452/// println!("P(X<=110.0): {}", normal_cdf(110.0, 100.0, 16.0));
1453/// ```
1454pub fn normal_cdf(x: f64, mu: f64, sigma: f64) -> f64 {
1455    if sigma <= 0.0 {
1456        println!("NAN produced. Error in function normal_cdf");
1457        return f64::NAN;
1458    }
1459
1460    return 0.5 * (1.0 + erf(((x-mu)/sigma) / 2.0f64.sqrt()));
1461}
1462
1463
1464/// Computes a percentile for `X ~ Normal(mu, sigma)`.
1465///
1466/// # Note
1467/// Determines the value of `x` such that `P(X <= x) = q`.
1468/// # Parameters
1469/// - `-infinity < mu < infinity`
1470/// - `sigma > 0`
1471/// # Support
1472/// - `-infinity < x < infinity`
1473/// # Example
1474/// Suppose `X ~ Normal(mu=100.0, sigma=16.0)`. To find the 80th percentile, use `q=0.80` and
1475/// ```
1476/// use ruststat::normal_per;
1477/// println!("Percentile: {}", normal_per(0.8, 100.0, 16.0));
1478/// ```
1479pub fn normal_per(p: f64, mu: f64, sigma: f64) -> f64 {
1480    return mu + sigma * 2.0f64.sqrt() * erf_inv(2.0*p-1.0);
1481}
1482
1483
1484/// Random draw from `X ~ Normal(mu, sigma)` distribution.
1485///
1486/// # Parameters
1487/// - `-infinity < mu < infinity`
1488/// - `sigma > 0`
1489/// # Support
1490/// - `-infinity < x < infinity`
1491/// # Example
1492/// Suppose `X ~ Normal(mu=100.0, sigma=16.0)`. Use
1493/// ```
1494/// use ruststat::normal_ran;
1495/// println!("Random draw: {}", normal_ran(100.0, 16.0));
1496/// ```
1497pub fn normal_ran(mu: f64, sigma: f64) -> f64 {
1498    let mut rng = rand::rng();
1499    let u1: f64;
1500    let u2: f64;
1501    let z1: f64;
1502    // let mut z2: f64;
1503
1504    if sigma <= 0.0 {
1505        println!("Bad argument to normal_rand");
1506        return f64::NAN;
1507    }
1508
1509    u1 = rng.random();
1510    u2 = rng.random();
1511    z1 = mu + sigma * (-2.0 * u1.ln()).sqrt() * (2.0 * PI * u2).cos();
1512    // z2 = mu + sig * (-2.0 * u1.ln()).sqrt() * (2.0 * PI * u2).sin();
1513
1514    return z1;
1515}
1516
1517
1518/// Save random draws from `X ~ Normal(mu, sigma)` distribution into a `Vec`
1519///
1520/// # Parameters
1521/// - `-infinity < mu < infinity`
1522/// - `sigma > 0`
1523/// # Support
1524/// - `-infinity < x < infinity`
1525/// # Example
1526/// Suppose `X ~ Normal(mu=100.0, sigma=16.0)`. Use
1527/// ```
1528/// use ruststat::normal_ranvec;
1529/// println!("Random Vec of normals: {:?}", normal_ranvec(10, 100.0, 16.0));
1530/// ```
1531pub fn normal_ranvec(n: i32, mu: f64, sigma: f64) -> Vec<f64> {
1532    let mut rng = rand::rng();
1533    let mut u1: f64;
1534    let mut u2: f64;
1535    let mut z1: f64;
1536    let mut z2: f64;
1537
1538    let mut zvecthr: Vec<f64> = Vec::new();
1539
1540    let niter: i32;
1541    if n <= 0 || sigma <= 0.0 {
1542        println!("Bad argument to normal_rand");
1543        return vec![f64::NAN];
1544    }
1545
1546    if 0==n%2 {
1547        niter = n / 2;
1548    }
1549    else {
1550        niter = (n + 1) / 2;
1551    }
1552
1553    // let now = Instant::now();
1554
1555    for _ in 0..niter {
1556        u1 = rng.random();
1557        u2 = rng.random();
1558        z1 = mu + sigma * (-2.0 * u1.ln()).sqrt() * (2.0 * PI * u2).cos();
1559        z2 = mu + sigma * (-2.0 * u1.ln()).sqrt() * (2.0 * PI * u2).sin();
1560        zvecthr.push(z1);
1561        zvecthr.push(z2);
1562    }
1563
1564    // let elapsed = now.elapsed();
1565    // println!("Elapsed: {:.2?}", elapsed);
1566
1567    if 0!=n%2 { // n is odd --- throw one out
1568        zvecthr.pop();
1569    }
1570
1571    return zvecthr;
1572}
1573
1574// pub fn normal_rand2(mu: f64, sig: f64, rng: &mut impl Rng) -> f64 {
1575//     // let mut rng = rand::thread_rng();
1576//     let u1: f64;
1577//     let u2: f64;
1578//     let z1: f64;
1579//     // let mut z2: f64;
1580//
1581//     if sig <= 0.0 {
1582//         println!("Bad argument to normal_rand");
1583//         return f64::NAN;
1584//     }
1585//
1586//     u1 = rng.gen();
1587//     u2 = rng.gen();
1588//     z1 = mu + sig * (-2.0 * u1.ln()).sqrt() * (2.0 * PI * u2).cos();
1589//     // z2 = mu + sig * (-2.0 * u1.ln()).sqrt() * (2.0 * PI * u2).sin();
1590//
1591//     return z1;
1592// }
1593
1594
1595// ==========================================
1596// ==========================================
1597// Pareto (Type I) Distribution
1598// ==========================================
1599// ==========================================
1600
1601/// Struct for the Pareto (type I) distribution `X ~ Pareto1(sigma, alpha)`.
1602///
1603/// # Parameters
1604/// - `sigma > 0`
1605/// - `alpha > 0`
1606/// # Support
1607/// - `x >= sigma`
1608/// # Example
1609/// Suppose `X ~ Pareto1(sigma=2.0, alpha=0.5)`. Use
1610/// ```
1611/// use ruststat::Pareto1Dist;
1612/// let mut mydist = Pareto1Dist{sigma:2.0, alpha:0.5};
1613/// println!("Probability density function f(2.5): {}", mydist.pdf(2.5));
1614/// println!("Cumulative distribution function P(X<=110.0): {}", mydist.cdf(2.5));
1615/// println!("99th percentile: {}", mydist.per(0.99));
1616/// println!("Random draw: {}", mydist.ran());
1617/// println!("Random vector: {:?}", mydist.ranvec(5));
1618/// println!("Mean: {}", mydist.mean());
1619/// println!("Variance: {}", mydist.var());
1620/// println!("Standard deviation: {}", mydist.sd());
1621/// ```
1622pub struct Pareto1Dist {
1623    pub sigma: f64,
1624    pub alpha: f64,
1625}
1626impl Pareto1Dist {
1627    pub fn pdf(&mut self, x: f64) -> f64 {
1628        return pareto4_pdf(x, self.sigma, self.sigma, 1.0, self.alpha);
1629    }
1630    pub fn cdf(&mut self, x: f64) -> f64 {
1631        return pareto4_cdf(x, self.sigma, self.sigma, 1.0, self.alpha);
1632    }
1633    pub fn per(&mut self, x: f64) -> f64 {
1634        return pareto4_per(x,self.sigma, self.sigma, 1.0, self.alpha);
1635    }
1636    pub fn ran(&mut self) -> f64 {
1637        return pareto4_ran(self.sigma, self.sigma, 1.0, self.alpha);
1638    }
1639    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
1640        return pareto4_ranvec(n, self.sigma, self.sigma, 1.0, self.alpha);
1641    }
1642    pub fn mean(&mut self) -> f64 {
1643        return self.sigma + self.sigma * gamma(self.alpha-1.0) *
1644            gamma(1.0 + 1.0) / gamma(self.alpha);
1645    }
1646    pub fn var(&mut self) -> f64 {
1647        return self.sigma.powi(2) * gamma(self.alpha - 1.0 * 2.0) *
1648            gamma(1.0 + 1.0 * 2.0) / gamma(self.alpha) - self.mean().powi(2);
1649    }
1650    pub fn sd(&mut self) -> f64 {
1651        return self.var().sqrt();
1652    }
1653}
1654
1655
1656// ==========================================
1657// ==========================================
1658// Pareto (Type II) Distribution
1659// ==========================================
1660// ==========================================
1661
1662/// Struct for the Pareto (type II) distribution `X ~ Pareto2(mu, sigma, alpha)`.
1663///
1664/// # Parameters
1665/// - `-infinity < mu < infinity`
1666/// - `sigma > 0`
1667/// - `alpha > 0`
1668/// # Support
1669/// - `x >= mu`
1670/// # Example
1671/// Suppose `X ~ Pareto2(mu=1.0, sigma=2.0, alpha=0.5)`. Use
1672/// ```
1673/// use ruststat::Pareto2Dist;
1674/// let mut mydist = Pareto2Dist{mu: 1.0, sigma:2.0, alpha:0.5};
1675/// println!("Probability density function f(2.5): {}", mydist.pdf(2.5));
1676/// println!("Cumulative distribution function P(X<=110.0): {}", mydist.cdf(2.5));
1677/// println!("99th percentile: {}", mydist.per(0.99));
1678/// println!("Random draw: {}", mydist.ran());
1679/// println!("Random vector: {:?}", mydist.ranvec(5));
1680/// println!("Mean: {}", mydist.mean());
1681/// println!("Variance: {}", mydist.var());
1682/// println!("Standard deviation: {}", mydist.sd());
1683/// ```
1684pub struct Pareto2Dist {
1685    pub mu: f64,
1686    pub sigma: f64,
1687    pub alpha: f64,
1688}
1689impl Pareto2Dist {
1690    pub fn pdf(&mut self, x: f64) -> f64 {
1691        return pareto4_pdf(x, self.mu, self.sigma, 1.0, self.alpha);
1692    }
1693    pub fn cdf(&mut self, x: f64) -> f64 {
1694        return pareto4_cdf(x, self.mu, self.sigma, 1.0, self.alpha);
1695    }
1696    pub fn per(&mut self, x: f64) -> f64 {
1697        return pareto4_per(x,self.mu, self.sigma, 1.0, self.alpha);
1698    }
1699    pub fn ran(&mut self) -> f64 {
1700        return pareto4_ran(self.mu, self.sigma, 1.0, self.alpha);
1701    }
1702    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
1703        return pareto4_ranvec(n,self.mu, self.sigma, 1.0, self.alpha);
1704    }
1705    pub fn mean(&mut self) -> f64 {
1706        return self.mu + self.sigma * gamma(self.alpha-1.0) *
1707            gamma(1.0 + 1.0) / gamma(self.alpha);
1708    }
1709    pub fn var(&mut self) -> f64 {
1710        return self.sigma.powi(2) * gamma(self.alpha - 1.0 * 2.0) *
1711            gamma(1.0 + 1.0 * 2.0) / gamma(self.alpha) - self.mean().powi(2);
1712    }
1713    pub fn sd(&mut self) -> f64 {
1714        return self.var().sqrt();
1715    }
1716}
1717
1718
1719// ==========================================
1720// ==========================================
1721// Pareto (Type III) Distribution
1722// ==========================================
1723// ==========================================
1724
1725/// Struct for the Pareto (type III) distribution `X ~ Pareto3(mu, sigma, gamma)`.
1726///
1727/// # Parameters
1728/// - `-infinity < mu < infinity`
1729/// - `sigma > 0`
1730/// - `gamma > 0`
1731/// # Support
1732/// - `x >= mu`
1733/// # Example
1734/// Suppose `X ~ Pareto3(mu=0.0, sigma=1.0, gamma=2.0)`. Use
1735/// ```
1736/// use ruststat::Pareto3Dist;
1737/// let mut mydist = Pareto3Dist{mu:0.0, sigma:1.0, gamma:2.0};
1738/// println!("Probability density function f(1.5): {}", mydist.pdf(1.5));
1739/// println!("Cumulative distribution function P(X<=110.0): {}", mydist.cdf(1.5));
1740/// println!("99th percentile: {}", mydist.per(0.99));
1741/// println!("Random draw: {}", mydist.ran());
1742/// println!("Random vector: {:?}", mydist.ranvec(5));
1743/// println!("Mean: {}", mydist.mean());
1744/// println!("Variance: {}", mydist.var());
1745/// println!("Standard deviation: {}", mydist.sd());
1746/// ```
1747pub struct Pareto3Dist {
1748    pub mu: f64,
1749    pub sigma: f64,
1750    pub gamma: f64,
1751}
1752impl Pareto3Dist {
1753    pub fn pdf(&mut self, x: f64) -> f64 {
1754        return pareto4_pdf(x, self.mu, self.sigma, self.gamma, 1.0);
1755    }
1756    pub fn cdf(&mut self, x: f64) -> f64 {
1757        return pareto4_cdf(x, self.mu, self.sigma, self.gamma, 1.0);
1758    }
1759    pub fn per(&mut self, x: f64) -> f64 {
1760        return pareto4_per(x,self.mu, self.sigma, self.gamma, 1.0);
1761    }
1762    pub fn ran(&mut self) -> f64 {
1763        return pareto4_ran(self.mu, self.sigma, self.gamma, 1.0);
1764    }
1765    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
1766        return pareto4_ranvec(n,self.mu, self.sigma, self.gamma, 1.0);
1767    }
1768    pub fn mean(&mut self) -> f64 {
1769        return self.mu + self.sigma * gamma(1.0-self.gamma) *
1770            gamma(1.0 + self.gamma) / gamma(1.0);
1771    }
1772    pub fn var(&mut self) -> f64 {
1773        return self.sigma.powi(2) * gamma(1.0 - self.gamma * 2.0) *
1774            gamma(1.0 + self.gamma * 2.0) / gamma(1.0) - self.mean().powi(2);
1775    }
1776    pub fn sd(&mut self) -> f64 {
1777        return self.var().sqrt();
1778    }
1779}
1780
1781
1782// ==========================================
1783// ==========================================
1784// Pareto (Type IV) Distribution
1785// ==========================================
1786// ==========================================
1787
1788/// Struct for the Pareto (type IV) distribution `X ~ Pareto4(mu, sigma, gamma, alpha)`.
1789///
1790/// # Parameters
1791/// - `-infinity < mu < infinity`
1792/// - `sigma > 0`
1793/// - `gamma > 0`
1794/// - `alpha > 0`
1795/// # Support
1796/// - `x >= mu`
1797/// # Example
1798/// Suppose `X ~ Pareto4(mu=0.0, sigma=1.0, gamma=2.0, alpha=0.5)`. Use
1799/// ```
1800/// use ruststat::Pareto4Dist;
1801/// let mut mydist = Pareto4Dist{mu:0.0, sigma:1.0, gamma:2.0, alpha:0.5};
1802/// println!("Probability density function f(1.5): {}", mydist.pdf(1.5));
1803/// println!("Cumulative distribution function P(X<=110.0): {}", mydist.cdf(1.5));
1804/// println!("99th percentile: {}", mydist.per(0.99));
1805/// println!("Random draw: {}", mydist.ran());
1806/// println!("Random vector: {:?}", mydist.ranvec(5));
1807/// println!("Mean: {}", mydist.mean());
1808/// println!("Variance: {}", mydist.var());
1809/// println!("Standard deviation: {}", mydist.sd());
1810/// ```
1811pub struct Pareto4Dist {
1812    pub mu: f64,
1813    pub sigma: f64,
1814    pub gamma: f64,
1815    pub alpha: f64,
1816}
1817impl Pareto4Dist {
1818    pub fn pdf(&mut self, x: f64) -> f64 {
1819        return pareto4_pdf(x, self.mu, self.sigma, self.gamma, self.alpha);
1820    }
1821    pub fn cdf(&mut self, x: f64) -> f64 {
1822        return pareto4_cdf(x, self.mu, self.sigma, self.gamma, self.alpha);
1823    }
1824    pub fn per(&mut self, x: f64) -> f64 {
1825        return pareto4_per(x,self.mu, self.sigma, self.gamma, self.alpha);
1826    }
1827    pub fn ran(&mut self) -> f64 {
1828        return pareto4_ran(self.mu, self.sigma, self.gamma, self.alpha);
1829    }
1830    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
1831        return pareto4_ranvec(n,self.mu, self.sigma, self.gamma, self.alpha);
1832    }
1833    pub fn mean(&mut self) -> f64 {
1834        return self.mu + self.sigma * gamma(self.alpha-self.gamma) *
1835            gamma(1.0 + self.gamma) / gamma(self.alpha);
1836    }
1837    pub fn var(&mut self) -> f64 {
1838        return self.sigma.powi(2) * gamma(self.alpha - self.gamma * 2.0) *
1839            gamma(1.0 + self.gamma * 2.0) / gamma(self.alpha) - self.mean().powi(2);
1840    }
1841    pub fn sd(&mut self) -> f64 {
1842        return self.var().sqrt();
1843    }
1844}
1845
1846
1847/// Computes probability density function (pdf) for `X ~ Pareto(mu, sigma, gamma, alpha)`.
1848///
1849/// # Parameters
1850/// - `-infinity < mu < infinity`
1851/// - `sigma > 0`
1852/// - `gamma > 0`
1853/// - `alpha > 0`
1854/// # Support
1855/// - `x >= mu`
1856/// # Example
1857/// Suppose `X ~ Pareto4(mu=0.0, sigma=1.0, gamma=2.0, alpha=0.5)`. Use.
1858/// ```
1859/// use ruststat::pareto4_pdf;
1860/// println!("Probability density function f(1.5): {}", pareto4_pdf(1.5, 0.0, 1.0, 2.0, 0.5));
1861pub fn pareto4_pdf(x: f64, mu: f64, sigma: f64, gamma: f64, alpha: f64) -> f64 {
1862    if sigma <= 0.0 || gamma <= 0.0 || alpha <= 0.0 {
1863        println!("NAN produced. Error in function pareto_pdf");
1864        return f64::NAN;
1865    }
1866    if x < mu {
1867        return 0.0;
1868    }
1869    return (alpha/(gamma*sigma))*((x-mu)/sigma).powf(1.0/gamma - 1.0)*
1870        (1.0 + ((x-mu)/sigma).powf(1.0/gamma)).powf(-alpha-1.0);
1871}
1872
1873
1874/// Computes cumulative distribution function (cdf) for `X ~ Pareto(mu, sigma, gamma, alpha)`.
1875///
1876/// # Parameters
1877/// - `-infinity < mu < infinity`
1878/// - `sigma > 0`
1879/// - `gamma > 0`
1880/// - `alpha > 0`
1881/// # Support
1882/// - `x >= mu`
1883/// # Example
1884/// Suppose `X ~ Pareto4(mu=0.0, sigma=1.0, gamma=2.0, alpha=0.5)`. Use.
1885/// ```
1886/// use ruststat::pareto4_cdf;
1887/// println!("P(X<=1.5): {}", pareto4_cdf(1.5, 0.0, 1.0, 2.0, 0.5));
1888/// ```
1889pub fn pareto4_cdf(x: f64, mu: f64, sigma: f64, gamma: f64, alpha: f64) -> f64 {
1890    if sigma <= 0.0 || gamma <= 0.0 || alpha <= 0.0 {
1891        println!("NAN produced. Error in function pareto_cdf");
1892        return f64::NAN;
1893    }
1894    if x < mu {
1895        return 0.0;
1896    }
1897
1898    return 1.0 - (1.0 + ((x-mu)/sigma).powf(1.0/gamma)).powf(-alpha);
1899}
1900
1901
1902/// Computes a percentile for `X ~ Pareto(mu, sigma, gamma, alpha)`.
1903///
1904/// # Note
1905/// Determines the value of `x` such that `P(X <= x) = q`.
1906/// # Parameters
1907/// - `-infinity < mu < infinity`
1908/// - `sigma > 0`
1909/// - `gamma > 0`
1910/// - `alpha > 0`
1911/// # Support
1912/// - `x >= mu`
1913/// # Example
1914/// Suppose `X ~ Pareto4(mu=0.0, sigma=1.0, gamma=2.0, alpha=0.5)`. To find the 80th percentile, use `q=0.80` and
1915/// ```
1916/// use ruststat::pareto4_per;
1917/// println!("Percentile: {}", pareto4_per(0.8, 0.0, 1.0, 2.0, 0.5));
1918/// ```
1919pub fn pareto4_per(p: f64, mu: f64, sigma: f64, gamma: f64, alpha: f64) -> f64 {
1920    return mu + sigma * ((1.0-p).powf(-1.0/alpha) - 1.0).powf(gamma);
1921}
1922
1923
1924/// Random draw from `X ~ Pareto(mu, sigma, gamma, alpha)` distribution.
1925///
1926/// # Parameters
1927/// - `-infinity < mu < infinity`
1928/// - `sigma > 0`
1929/// - `gamma > 0`
1930/// - `alpha > 0`
1931/// # Support
1932/// - `x >= mu`
1933/// # Example
1934/// Suppose `X ~ Pareto4(mu=0.0, sigma=1.0, gamma=2.0, alpha=0.5)`. Use
1935/// ```
1936/// use ruststat::pareto4_ran;
1937/// println!("Random draw: {}", pareto4_ran(0.0, 1.0, 2.0, 0.5));
1938/// ```
1939pub fn pareto4_ran(mu: f64, sigma: f64, gamma: f64, alpha: f64) -> f64 {
1940    return mu + sigma * ((1.0-unif_ran(0.0, 1.0)).powf(-1.0/alpha) - 1.0).powf(gamma);
1941}
1942
1943
1944/// Save random draws from `X ~ Pareto(mu, sigma, gamma, alpha)` distribution into a `Vec`
1945///
1946/// # Parameters
1947/// - `-infinity < mu < infinity`
1948/// - `sigma > 0`
1949/// - `gamma > 0`
1950/// - `alpha > 0`
1951/// # Support
1952/// - `x >= mu`
1953/// # Example
1954/// Suppose `X ~ Pareto4(mu=0.0, sigma=1.0, gamma=2.0, alpha=0.5)`. Use
1955/// ```
1956/// use ruststat::pareto4_ranvec;
1957/// println!("Random Vec: {:?}", pareto4_ranvec(10, 0.0, 1.0, 2.0, 0.5));
1958/// ```
1959pub fn pareto4_ranvec(n: i32, mu: f64, sigma: f64, gamma: f64, alpha: f64) -> Vec<f64> {
1960    let mut xvec: Vec<f64> = Vec::new();
1961    for _ in 0..n {
1962        xvec.push(pareto4_ran(mu, sigma, gamma, alpha));
1963    }
1964    return xvec;
1965}
1966
1967
1968// ==========================================
1969// ==========================================
1970// t Distribution
1971// ==========================================
1972// ==========================================
1973
1974/// Struct for Student's t distribution `X ~ t(nu)`.
1975///
1976/// # Parameters
1977/// - `nu > 0`
1978/// # Support
1979/// - `-infinity < x < infinity`
1980/// # Example
1981/// Suppose `X ~ t(nu=25)`. Use
1982/// ```
1983/// use ruststat::TDist;
1984/// let mut myt = TDist{nu:25.0};
1985/// println!("Probability density function f(2.2): {}", myt.pdf(2.2));
1986/// println!("Cumulative distribution function P(X<=2.2): {}", myt.cdf(2.2));
1987/// println!("99th percentile: {}", myt.per(0.99));
1988/// println!("Random draw: {}", myt.ran());
1989/// println!("Random vector: {:?}", myt.ranvec(5));
1990/// println!("Mean: {}", myt.mean());
1991/// println!("Variance: {}", myt.var());
1992/// println!("Standard deviation: {}", myt.sd());
1993/// ```
1994pub struct TDist {
1995    pub nu: f64,
1996}
1997impl TDist {
1998    pub fn pdf(&mut self, x: f64) -> f64 {
1999        return t_pdf(x, self.nu);
2000    }
2001    pub fn cdf(&mut self, x: f64) -> f64 {
2002        return t_cdf(x, self.nu);
2003    }
2004    pub fn per(&mut self, p: f64) -> f64 {
2005        return t_per(p,self.nu);
2006    }
2007    pub fn ran(&mut self) -> f64 {
2008        return t_ran(self.nu);
2009    }
2010    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
2011        return t_ranvec(n, self.nu);
2012    }
2013    pub fn mean(&mut self) -> f64 {
2014        return 0.0;
2015    }
2016    pub fn var(&mut self) -> f64 {
2017        return if self.nu > 2.0 {
2018            self.nu / (self.nu - 2.0)
2019        } else {
2020            f64::NAN
2021        }
2022    }
2023    pub fn sd(&mut self) -> f64 {
2024        return if self.nu > 2.0 {
2025            self.var().sqrt()
2026        } else {
2027            f64::NAN
2028        }
2029    }
2030}
2031
2032
2033/// Computes probability density function (pdf) for `X ~ t(nu)`.
2034///
2035/// # Parameters
2036/// - `nu > 0`
2037/// # Support
2038/// - `-infinity < x < infinity`
2039/// # Example
2040/// Suppose `X ~ t(nu=25.0)`. Use.
2041/// ```
2042/// use ruststat::t_pdf;
2043/// println!("Probability density function f(2.2): {}", t_pdf(2.2, 25.0));
2044pub fn t_pdf(x: f64, nu: f64) -> f64 {
2045    if nu <= 0.0 {
2046        println!("NAN produced. Error in function t_pdf");
2047        return f64::NAN;
2048    }
2049    return gamma((nu+1.0)/2.0) * (1.0 + x.powi(2)/nu).powf(-(nu+1.0)/2.0) /
2050        ((nu * PI).sqrt() * gamma(nu/2.0));
2051}
2052
2053
2054/// Computes cumulative distribution function (cdf) for `X ~ t(nu)`.
2055///
2056/// # Parameters
2057/// - `nu > 0`
2058/// # Support
2059/// - `-infinity < x < infinity`
2060/// # Example
2061/// Suppose `X ~ nu(nu=25.0)`. Use.
2062/// ```
2063/// use ruststat::t_cdf;
2064/// println!("P(X<=2.2): {}", t_cdf(2.2, 25.0));
2065/// ```
2066pub fn t_cdf(x: f64, nu: f64) -> f64 {
2067    if nu <= 0.0 {
2068        println!("NAN produced. Error in function t_cdf");
2069        return f64::NAN;
2070    }
2071
2072    return if x <= 0.0 {
2073        0.5 * betai(nu / (nu + x * x), nu / 2.0, 0.5)
2074    } else {
2075        1.0 - 0.5 * betai(nu / (nu + x * x), nu / 2.0, 0.5)
2076    }
2077}
2078
2079
2080/// Computes a percentile for `X ~ t(nu)`.
2081///
2082/// # Note
2083/// Determines the value of `x` such that `P(X <= x) = q`.
2084/// # Parameters
2085/// - `nu > 0`
2086/// # Support
2087/// - `-infinity < x < infinity`
2088/// # Example
2089/// Suppose `X ~ t(nu=25.0)`. To find the 80th percentile, use `q=0.80` and
2090/// ```
2091/// use ruststat::t_per;
2092/// println!("Percentile: {}", t_per(0.8, 25.0));
2093/// ```
2094pub fn t_per(p: f64, nu: f64) -> f64 {
2095    let (a, x): (f64, f64);
2096    return if p <= 0.5 {
2097        a = betai_inv(2.0 * p, nu / 2.0, 1.0 / 2.0);
2098        x = (nu / a - nu).sqrt();
2099        -x
2100    } else {
2101        a = betai_inv(2.0 * (1.0 - p), nu / 2.0, 1.0 / 2.0);
2102        x = (nu / a - nu).sqrt();
2103        x
2104    }
2105}
2106
2107
2108/// Random draw from `X ~ t(nu)` distribution.
2109///
2110/// # Parameters
2111/// - `nu > 0`
2112/// # Support
2113/// - `-infinity < x < infinity`
2114/// # Example
2115/// Suppose `X ~ t(nu=25.0)`. Use
2116/// ```
2117/// use ruststat::t_ran;
2118/// println!("Random draw: {}", t_ran(25.0));
2119/// ```
2120pub fn t_ran(nu: f64) -> f64 {
2121    return normal_ran(0.0, 1.0) *
2122        (nu / gamma_ran(nu/2.0, 1.0/2.0)).sqrt();
2123}
2124
2125
2126/// Save random draws from `X ~ t(nu)` distribution into a `Vec`
2127///
2128/// # Parameters
2129/// - `nu > 0`
2130/// # Support
2131/// - `-infinity < x < infinity`
2132/// # Example
2133/// Suppose `X ~ t(nu=25.0)`. Use
2134/// ```
2135/// use ruststat::t_ranvec;
2136/// println!("Random Vec: {:?}", t_ranvec(10, 25.0));
2137/// ```
2138pub fn t_ranvec(n: i32, nu: f64) -> Vec<f64> {
2139    let mut xvec: Vec<f64> = Vec::new();
2140    for _ in 0..n {
2141        xvec.push(t_ran(nu));
2142    }
2143    return xvec;
2144}
2145
2146
2147// ==========================================
2148// ==========================================
2149// Continuous Uniform Distribution
2150// ==========================================
2151// ==========================================
2152
2153/// Struct for continuous uniform distribution `X ~ Unif(a,b)`.
2154///
2155/// # Parameters
2156/// - `-infinity < a < infinity`
2157/// - `-infinity < b < infinity`
2158/// - `a < b`
2159/// # Support
2160/// - `a < x < b`
2161/// # Example
2162/// Suppose `X ~ Unif(a=0.0, b=1.0)`. Use
2163/// ```
2164/// use ruststat::UnifDist;
2165/// let mut myunif = UnifDist{a:0.0, b:1.0};
2166/// println!("Probability density function f(0.4): {}", myunif.pdf(0.4));
2167/// println!("Cumulative distribution function P(X<=0.4): {}", myunif.cdf(0.4));
2168/// println!("99th percentile: {}", myunif.per(0.99));
2169/// println!("Random draw: {}", myunif.ran());
2170/// println!("Random vector: {:?}", myunif.ranvec(5));
2171/// println!("Mean: {}", myunif.mean());
2172/// println!("Variance: {}", myunif.var());
2173/// println!("Standard deviation: {}", myunif.sd());
2174/// ```
2175pub struct UnifDist {
2176    pub a: f64,
2177    pub b: f64,
2178}
2179impl UnifDist {
2180    pub fn pdf(&mut self, x: f64) -> f64 {
2181        return unif_pdf(x, self.a, self.b);
2182    }
2183    pub fn cdf(&mut self, x: f64) -> f64 {
2184        return unif_cdf(x, self.a, self.b);
2185    }
2186    pub fn per(&mut self, x: f64) -> f64 {
2187        return unif_per(x,self.a, self.b);
2188    }
2189    pub fn ran(&mut self) -> f64 {
2190        return unif_ran(self.a, self.b);
2191    }
2192    pub fn ranvec(&mut self, n: i32) -> Vec<f64> {
2193        return unif_ranvec(n, self.a, self.b);
2194    }
2195    pub fn mean(&mut self) -> f64 {
2196        return (self.a + self.b) / 2.0;
2197    }
2198    pub fn var(&mut self) -> f64 {
2199        return (self.b - self.a).powi(2) / 12.0;
2200    }
2201    pub fn sd(&mut self) -> f64 {
2202        return self.var().sqrt();
2203    }
2204}
2205
2206
2207/// Computes probability density function (pdf) for `X ~ Unif(a,b)`.
2208///
2209/// # Parameters
2210/// - `-infinity < a < infinity`
2211/// - `-infinity < b < infinity`
2212/// - `a < b`
2213/// # Support
2214/// - `a < x < b`
2215/// # Example
2216/// Suppose `X ~ Unif(a=0.0, b=1.0)`. Use.
2217/// ```
2218/// use ruststat::unif_pdf;
2219/// println!("Probability density function f(0.4): {}", unif_pdf(0.4, 0.0, 1.0));
2220pub fn unif_pdf(x: f64, a: f64, b: f64) -> f64 {
2221    if a >= b {
2222        println!("NAN produced. Error in function unif_pdf");
2223        return f64::NAN;
2224    }
2225    if x < a || x > b {
2226        return 0.0;
2227    }
2228    return 1.0 / (b - a);
2229}
2230
2231
2232/// Computes cumulative distribution function (cdf) for `X ~ Unif(a,b)`.
2233///
2234/// # Parameters
2235/// - `-infinity < a < infinity`
2236/// - `-infinity < b < infinity`
2237/// - `a < b`
2238/// # Support
2239/// - `a < x < b`
2240/// # Example
2241/// Suppose `X ~ Unif(a=0.0, b=1.0)`. Use.
2242/// ```
2243/// use ruststat::unif_cdf;
2244/// println!("P(X<=0.4): {}", unif_cdf(0.4, 0.0, 1.0));
2245/// ```
2246pub fn unif_cdf(x: f64, a: f64, b: f64) -> f64 {
2247    if a >= b {
2248        println!("NAN produced. Error in function unif_cdf");
2249        return f64::NAN;
2250    }
2251    if x < a {
2252        return 0.0;
2253    }
2254    if x > b {
2255        return 1.0;
2256    }
2257
2258    return (x - a) / (b - a);
2259}
2260
2261
2262/// Computes a percentile for `X ~ Unif(a,b)`.
2263///
2264/// # Note
2265/// Determines the value of `x` such that `P(X <= x) = q`.
2266/// # Parameters
2267/// - `-infinity < a < infinity`
2268/// - `-infinity < b < infinity`
2269/// - `a < b`
2270/// # Support
2271/// - `a < x < b`
2272/// # Example
2273/// Suppose `X ~ Unif(a=0.0, b=1.0)`. To find the 80th percentile, use `q=0.80` and
2274/// ```
2275/// use ruststat::unif_per;
2276/// println!("Percentile: {}", unif_per(0.8, 0.0, 1.0));
2277/// ```
2278pub fn unif_per(p: f64, a: f64, b: f64) -> f64 {
2279    return a + p*(b-a);
2280}
2281
2282
2283/// Random draw from `X ~ Unif(a,b)` distribution.
2284///
2285/// # Parameters
2286/// - `-infinity < a < infinity`
2287/// - `-infinity < b < infinity`
2288/// - `a < b`
2289/// # Support
2290/// - `a < x < b`
2291/// # Example
2292/// Suppose `X ~ Unif(a=0.0, b=1.0)`. Use
2293/// ```
2294/// use ruststat::unif_ran;
2295/// println!("Random draw: {}", unif_ran(0.0, 1.0));
2296/// ```
2297pub fn unif_ran(a: f64, b: f64) -> f64 {
2298    let u: f64;
2299    u = random();
2300    // u = rand::thread_rng().gen();
2301    return a + u * (b-a);
2302}
2303
2304
2305/// Save random draws from `X ~ Unif(a,b)` distribution into a `Vec`
2306///
2307/// # Parameters
2308/// - `-infinity < a < infinity`
2309/// - `-infinity < b < infinity`
2310/// - `a < b`
2311/// # Support
2312/// - `a < x < b`
2313/// # Example
2314/// Suppose `X ~ Unif(a=0.0, b=1.0)`. Use
2315/// ```
2316/// use ruststat::unif_ranvec;
2317/// println!("Random Vec: {:?}", unif_ranvec(10, 0.0, 1.0));
2318/// ```
2319pub fn unif_ranvec(n: i32, a: f64, b: f64) -> Vec<f64> {
2320    let mut xvec: Vec<f64> = Vec::new();
2321    for _ in 0..n {
2322        xvec.push(unif_ran(a,b));
2323    }
2324    return xvec;
2325}
2326
2327
2328
2329// ==========================================
2330// ==========================================
2331// ==========================================
2332// Discrete RVs
2333// ==========================================
2334// ==========================================
2335// ==========================================
2336
2337
2338// ==========================================
2339// ==========================================
2340// Binomial Distribution
2341// ==========================================
2342// ==========================================
2343
2344/// Struct for the binomial distirubion `X ~ Bin(n,p)`.
2345///
2346/// # Parameters
2347/// - `n` = number of trials (`n = 1,2,...`)
2348/// - `p` = probability of success (`0 <= p <= 1`)
2349/// # Support
2350/// - `x = 0,1,2,...,n`
2351/// # Example
2352/// Suppose `X ~ Bin(n=100,p=0.9)`. Use
2353/// ```
2354/// use ruststat::BinDist;
2355/// let mut mybin = BinDist{n:100, p:0.9};
2356/// println!("P(X=80): {}", mybin.pmf(80));
2357/// println!("P(X<=80): {}", mybin.cdf(80));
2358/// println!("99th percentile: {}", mybin.per(0.99));
2359/// println!("Random draw: {}", mybin.ran());
2360/// println!("Random vector: {:?}", mybin.ranvec(5));
2361/// println!("Mean: {}", mybin.mean());
2362/// println!("Variance: {}", mybin.var());
2363/// println!("Standard deviation: {}", mybin.sd());
2364/// ```
2365pub struct BinDist {
2366    pub n: i32,
2367    pub p: f64,
2368}
2369impl BinDist {
2370    pub fn pmf(&mut self, x: i32) -> f64 {
2371        return bin_pmf(x, self.n, self.p);
2372    }
2373    pub fn cdf(&mut self, x: i32) -> f64 {
2374        return bin_cdf(x, self.n, self.p);
2375    }
2376    pub fn per(&mut self, q: f64) -> i32 {
2377        return bin_per(q, self.n, self.p);
2378    }
2379    pub fn ran(&mut self) -> i32 {
2380        return bin_ran(self.n, self.p);
2381    }
2382    pub fn ranvec(&mut self, n: i32) -> Vec<i32> {
2383        return bin_ranvec(n, self.n, self.p);
2384    }
2385    pub fn mean(&mut self) -> f64 {
2386        return (self.n as f64) * self.p;
2387    }
2388    pub fn var(&mut self) -> f64 {
2389        return (self.n as f64) * self.p * (1.0-self.p);
2390    }
2391    pub fn sd(&mut self) -> f64 {
2392        return self.var().sqrt();
2393    }
2394}
2395
2396
2397/// Computes probability mass function (pmf) for `X ~ Bin(n,p)`
2398///
2399/// # Parameters
2400/// - `n` = number of trials (`n = 1,2,...`)
2401/// - `p` = probability of success (`0 <= p <= 1`)
2402/// # Support
2403/// - `x = 0,1,2,...,n`
2404/// # Example
2405/// Suppose `X ~ Bin(n=10,p=0.6)`. To compute `P(X = 7)`, use
2406/// ```
2407/// use ruststat::bin_pmf;
2408/// println!("P(X=x): {}", bin_pmf(7, 10, 0.6));
2409/// ```
2410pub fn bin_pmf(x: i32, n: i32, p: f64) -> f64 {
2411    if n <= 0 || p < 0.0 || p > 1.0 {
2412        println!("NAN produced. Error in function bin_pmf");
2413        return f64::NAN;
2414    }
2415    if x < 0 || x > n {
2416        return 0.0;
2417    }
2418    return comb(n, x) * p.powi(x) * (1.0-p).powi(n-x);
2419}
2420
2421
2422/// Computes cumulative distribution function (cdf) for `X ~ Bin(n,p)`
2423///
2424/// # Parameters
2425/// - `n` = number of trials (`n = 1,2,...`)
2426/// - `p` = probability of success (`0 <= p <= 1`)
2427/// # Support
2428/// - `x = 0,1,2,...,n`
2429/// # Example
2430/// Suppose `X ~ Bin(n=10,p=0.6)`. To compute `P(X <= 7)`, use
2431/// ```
2432/// use ruststat::bin_cdf;
2433/// println!("P(X<=x): {}", bin_cdf(7, 10, 0.6));
2434/// ```
2435pub fn bin_cdf(x: i32, n: i32, p: f64) -> f64 {
2436    if n <= 0 || p < 0.0 || p > 1.0 {
2437        println!("NAN produced. Error in function bin_cdf");
2438        return f64::NAN;
2439    }
2440    if x < 0 {
2441        return 0.0;
2442    }
2443    if x > n {
2444        return 1.0;
2445    }
2446
2447    let mut sum = 0.0;
2448    for i in 0..=x {
2449        sum += bin_pmf(i, n, p);
2450    }
2451    return if sum < 1.0 {
2452        sum
2453    } else {
2454        1.0
2455    }
2456}
2457
2458
2459/// Computes a percentile for `X ~ Bin(n,p)`
2460/// # Note
2461/// Determines the smallest (integer) value of `x` such that `P(X <= x) >= q`.
2462/// # Parameters
2463/// - `n` = number of trials (`n = 1,2,...`)
2464/// - `p` = probability of success (`0 <= p <= 1`)
2465/// # Support
2466/// - `x = 0,1,2,...,n`
2467/// # Example
2468/// Suppose `X ~ Bin(n=10,p=0.6)`. To find the 80th percentile, use `q=0.80` and
2469/// ```
2470/// use ruststat::bin_per;
2471/// println!("Percentile: {}", bin_per(0.8, 10, 0.6));
2472/// ```
2473pub fn bin_per(q: f64, n: i32, p: f64) -> i32 {
2474    let mut x = 0;
2475
2476    if n <= 0 || p < 0.0 || p > 1.0 || q < 0.0 || q > 1.0 {
2477        println!("NAN produced. Error in function bin_per");
2478        return f64::NAN as i32;
2479    }
2480    if q == 0.0 {
2481        return 0;
2482    }
2483    if q == 1.0 {
2484        return n;
2485    }
2486
2487    while bin_cdf(x, n, p) < q {
2488        x += 1;
2489    }
2490    return x;
2491}
2492
2493
2494/// Random draw from `X ~ Bin(n,p)` distribution
2495/// Sheldon Ross, Simulation, (2003)
2496/// # Parameters
2497/// - `n` = number of trials (`n = 1,2,...`)
2498/// - `p` = probability of success (`0 <= p <= 1`)
2499/// # Support
2500/// - `x = 0,1,2,...,n`
2501/// # Example
2502/// Suppose `X ~ Bin(n=10,p=0.6)`. Use
2503/// ```
2504/// use ruststat::bin_ran;
2505/// println!("Random draw: {}", bin_ran(10, 0.6));
2506/// ```
2507pub fn bin_ran(n: i32, p: f64) -> i32 {
2508
2509    if n <= 0 || p < 0.0 || p > 1.0 {
2510        println!("NAN produced. Error in function bin_ran");
2511        return f64::NAN as i32;
2512    }
2513    if p == 0.0 {
2514        return 0;
2515    }
2516    if p == 1.0 {
2517        return n;
2518    }
2519
2520    let u : f64;
2521    u = unif_ran(0.0, 1.0);
2522    let c = p / (1.0 - p);
2523    let mut i = 0;
2524    let mut pr = (1.0 - p).powi(n);
2525    let mut f = pr;
2526    loop {
2527        if u < f {
2528            return i;
2529        }
2530        pr = c * ((n - i) as f64 / (i + 1) as f64) * pr;
2531        f = f + pr;
2532        i = i + 1;
2533    }
2534
2535    // let cdf = rand::thread_rng().gen();
2536    // let mut x = 0;
2537    //
2538    // while bin_cdf(x, n, p) < cdf {
2539    //     x += 1;
2540    // }
2541    //
2542    // return x;
2543}
2544
2545/// Save random draws from `X ~ Bin(n,p)` distribution into a `Vec`
2546/// # Parameters
2547/// - `n` = number of trials (`n = 1,2,...`)
2548/// - `p` = probability of success (`0 <= p <= 1`)
2549/// # Example
2550/// Suppose `X ~ Bin(n=10,p=0.6)`. Use
2551/// ```
2552/// use ruststat::bin_ranvec;
2553/// println!("Random Vec: {:?}", bin_ranvec(10, 10, 0.6));
2554/// ```
2555pub fn bin_ranvec(nn: i32, n: i32, p: f64) -> Vec<i32> {
2556    let mut xvec: Vec<i32> = Vec::new();
2557    for _ in 0..nn {
2558        xvec.push(bin_ran(n,p));
2559    }
2560    return xvec;
2561}
2562
2563
2564// ==========================================
2565// ==========================================
2566// Geometric Distribution
2567// ==========================================
2568// ==========================================
2569
2570/// Struct for the geometric distribution `X ~ Geo(p)` where
2571/// `X =` the number of failures prior to observing the first success.
2572///
2573/// # Parameters
2574/// - `p` = probability of success (`0 < p <= 1`)
2575/// # Support
2576/// - `x = 0,1,2,...`
2577/// # Example
2578/// Suppose `X ~ Geo(p=0.2)`. Use
2579/// ```
2580/// use ruststat::GeoDist;
2581/// let mut mygeo = GeoDist{p:0.2};
2582/// println!("probability mass function: {}", mygeo.pmf(8));
2583/// println!("cumulative distribution function: {}", mygeo.cdf(8));
2584/// println!("percentile: {}", mygeo.per(0.99));
2585/// println!("random: {}", mygeo.ran());
2586/// println!("Random vector: {:?}", mygeo.ranvec(5));
2587/// println!("mean: {}", mygeo.mean());
2588/// println!("variance: {}", mygeo.var());
2589/// println!("standard deviation: {}", mygeo.sd());
2590/// ```
2591pub struct GeoDist {
2592    pub p: f64,
2593}
2594impl GeoDist {
2595    pub fn pmf(&mut self, x: i32) -> f64 {
2596        return geo_pmf(x, self.p);
2597    }
2598    pub fn cdf(&mut self, x: i32) -> f64 {
2599        return geo_cdf(x, self.p);
2600    }
2601    pub fn per(&mut self, q: f64) -> i32 {
2602        return geo_per(q, self.p);
2603    }
2604    pub fn ran(&mut self) -> i32 {
2605        return geo_ran(self.p);
2606    }
2607    pub fn ranvec(&mut self, n: i32) -> Vec<i32> {
2608        return geo_ranvec(n, self.p);
2609    }
2610    pub fn mean(&mut self) -> f64 {
2611        return (1.0 - self.p) / self.p;
2612    }
2613    pub fn var(&mut self) -> f64 {
2614        return (1.0 - self.p) / self.p.powi(2);
2615    }
2616    pub fn sd(&mut self) -> f64 {
2617        return self.var().sqrt();
2618    }
2619}
2620
2621
2622/// Computes probability mass function (pmf) for `X ~ Geo(p)`
2623/// where `X =` the number of failures prior to the first success.
2624///
2625/// # Parameters
2626/// - `p` = probability of success (`0 < p <= 1`)
2627/// # Support
2628/// - `x = 0,1,2,...`
2629/// # Example
2630/// Suppose `X ~ Geo(p=0.6)`. To compute `P(X = 3)`, use
2631/// ```
2632/// use ruststat::geo_pmf;
2633/// println!("P(X=x): {}", geo_pmf(3, 0.6));
2634/// ```
2635pub fn geo_pmf(x: i32, p: f64) -> f64 {
2636    if p <= 0.0 || p > 1.0 {
2637        println!("NAN produced. Error in function geo_pmf");
2638        return f64::NAN;
2639    }
2640    if x < 0 {
2641        return 0.0;
2642    }
2643    return (1.0-p).powi(x) * p;
2644}
2645
2646
2647/// Computes cumulative distribution function (cdf) for `X ~ Geo(p)`
2648/// where `X =` the number of failures prior to the first success.
2649///
2650/// # Parameters
2651/// - `p` = probability of success (`0 <= p <= 1`)
2652/// # Support
2653/// - `x = 0,1,2,...`
2654/// # Example
2655/// Suppose `X ~ Geo(p=0.6)`. To compute `P(X <= 3)`, use
2656/// ```
2657/// use ruststat::geo_cdf;
2658/// println!("P(X<=x): {}", geo_cdf(3, 0.6));
2659/// ```
2660pub fn geo_cdf(x: i32, p: f64) -> f64 {
2661    if p <= 0.0 || p > 1.0 {
2662        println!("NAN produced. Error in function geo_pmf");
2663        return f64::NAN;
2664    }
2665    if x < 0 {
2666        return 0.0;
2667    }
2668
2669    let mut sum = 0.0;
2670    for i in 0..=x {
2671        sum += geo_pmf(i, p);
2672    }
2673    return sum;
2674}
2675
2676
2677/// Computes a percentile for `X ~ Geo(p)`
2678/// where `X =` the number of failures prior to the first success.
2679///
2680/// # Note
2681/// Determines the smallest (integer) value of `x` such that `P(X <= x) >= q`.
2682/// # Parameters
2683/// - `p` = probability of success (`0 < p <= 1`)
2684/// # Support
2685/// - `x = 0,1,2,...`
2686/// # Example
2687/// Suppose `X ~ Geo(p=0.6)`. To find the 80th percentile, use `q=0.80` and
2688/// ```
2689/// use ruststat::geo_per;
2690/// println!("Percentile: {}", geo_per(0.8, 0.6));
2691/// ```
2692pub fn geo_per(q: f64, p: f64) -> i32 {
2693    let mut x = 0;
2694
2695    if p <= 0.0 || p > 1.0 || q < 0.0 || q > 1.0 {
2696        println!("NAN produced. Error in function geo1_per");
2697        return f64::NAN as i32;
2698    }
2699    if q == 0.0 {
2700        return 0;
2701    }
2702    if q == 1.0 {
2703        return i32::MAX;
2704    }
2705
2706    while geo_cdf(x, p) < q {
2707        x += 1;
2708    }
2709    return x;
2710}
2711
2712
2713/// Random draw from `X ~ Geo(p)` distribution
2714/// where `X =` the number of failures prior to the first success.
2715///
2716/// # Parameters
2717/// - `p` = probability of success (`0 < p <= 1`)
2718/// # Example
2719/// Suppose `X ~ Geo(p=0.6)`. Use
2720/// ```
2721/// use ruststat::geo_ran;
2722/// println!("Random draw: {}", geo_ran(0.6));
2723/// ```
2724pub fn geo_ran(p: f64) -> i32 {
2725
2726    if p <= 0.0 || p > 1.0 {
2727        println!("NAN produced. Error in function geo1_ran");
2728        return f64::NAN as i32;
2729    }
2730
2731    let u = unif_ran(0.0, 1.0);
2732    return (u.ln() / (1.0-p).ln()).floor() as i32;
2733
2734    // let cdf = unif_ran(0.0, 1.0);
2735    // let mut x = 0;
2736    //
2737    // while geo_cdf(x, p) < cdf {
2738    //     x += 1;
2739    // }
2740    // return x;
2741}
2742
2743
2744/// Save random draws from `X ~ Geo(p)` distribution into a `Vec`
2745/// # Parameters
2746/// - `p` = probability of success (`0 <= p <= 1`)
2747/// # Example
2748/// Suppose `X ~ Geo(p=0.6)`. Use
2749/// ```
2750/// use ruststat::geo_ranvec;
2751/// println!("Random Vec: {:?}", geo_ranvec(10, 0.6));
2752/// ```
2753pub fn geo_ranvec(nn: i32, p: f64) -> Vec<i32> {
2754    let mut xvec: Vec<i32> = Vec::new();
2755    for _ in 0..nn {
2756        xvec.push(geo_ran(p));
2757    }
2758    return xvec;
2759}
2760
2761
2762// ==========================================
2763// ==========================================
2764// Geometric Distribution 2
2765// ==========================================
2766// ==========================================
2767
2768/// Struct for the geometric distribution `X ~ Geo(p)` where
2769/// `X =` the trial on which the first success is observed.
2770///
2771/// # Parameters
2772/// - `p` = probability of success (`0 < p <= 1`)
2773/// # Support
2774/// - `x = 1,2,3,...`
2775/// # Example
2776/// Suppose `X ~ Geo(p=0.2)`. Use
2777/// ```
2778/// use ruststat::Geo2Dist;
2779/// let mut mygeo = Geo2Dist{p:0.2};
2780/// println!("probability mass function: {}", mygeo.pmf(8));
2781/// println!("cumulative distribution function: {}", mygeo.cdf(8));
2782/// println!("percentile: {}", mygeo.per(0.99));
2783/// println!("random: {}", mygeo.ran());
2784/// println!("Random vector: {:?}", mygeo.ranvec(5));
2785/// println!("mean: {}", mygeo.mean());
2786/// println!("variance: {}", mygeo.var());
2787/// println!("standard deviation: {}", mygeo.sd());
2788/// ```
2789pub struct Geo2Dist {
2790    pub p: f64,
2791}
2792impl Geo2Dist {
2793    pub fn pmf(&mut self, x: i32) -> f64 {
2794        return geo2_pmf(x, self.p);
2795    }
2796    pub fn cdf(&mut self, x: i32) -> f64 {
2797        return geo2_cdf(x, self.p);
2798    }
2799    pub fn per(&mut self, q: f64) -> i32 {
2800        return geo2_per(q, self.p);
2801    }
2802    pub fn ran(&mut self) -> i32 {
2803        return geo2_ran(self.p);
2804    }
2805    pub fn ranvec(&mut self, n: i32) -> Vec<i32> {
2806        return geo2_ranvec(n, self.p);
2807    }
2808    pub fn mean(&mut self) -> f64 {
2809        return 1.0 / self.p;
2810    }
2811    pub fn var(&mut self) -> f64 {
2812        return (1.0 - self.p) / self.p.powi(2);
2813    }
2814    pub fn sd(&mut self) -> f64 {
2815        return self.var().sqrt();
2816    }
2817}
2818
2819
2820/// Computes probability mass function (pmf) for `X ~ Geo(p)`
2821/// where `X =` the trial on which the first success is observed.
2822///
2823/// # Parameters
2824/// - `p` = probability of success (`0 < p <= 1`)
2825/// # Support
2826/// - `x = 1,2,3,...`
2827/// # Example
2828/// Suppose `X ~ Geo(p=0.6)`. To compute `P(X = 3)`, use
2829/// ```
2830/// use ruststat::geo2_pmf;
2831/// println!("P(X=x): {}", geo2_pmf(3, 0.6));
2832/// ```
2833pub fn geo2_pmf(x: i32, p: f64) -> f64 {
2834    if p <= 0.0 || p > 1.0 {
2835        println!("NAN produced. Error in function geo2_pmf");
2836        return f64::NAN;
2837    }
2838    if x < 1 {
2839        return 0.0;
2840    }
2841    return (1.0-p).powi(x-1) * p;
2842}
2843
2844
2845/// Computes cumulative distribution function (cdf) for `X ~ Geo(p)`
2846/// where `X =` the trial on which the first success is observed.
2847///
2848/// # Parameters
2849/// - `p` = probability of success (`0 <= p <= 1`)
2850/// # Support
2851/// - `x = 1,2,3,...`
2852/// # Example
2853/// Suppose `X ~ Geo(p=0.6)`. To compute `P(X <= 3)`, use
2854/// ```
2855/// use ruststat::geo2_cdf;
2856/// println!("P(X<=x): {}", geo2_cdf(3, 0.6));
2857/// ```
2858pub fn geo2_cdf(x: i32, p: f64) -> f64 {
2859    if p <= 0.0 || p > 1.0 {
2860        println!("NAN produced. Error in function geo2_cdf");
2861        return f64::NAN;
2862    }
2863    if x < 1 {
2864        return 0.0;
2865    }
2866
2867    let mut sum = 0.0;
2868    for i in 1..=x {
2869        sum += geo2_pmf(i, p);
2870    }
2871    return sum;
2872}
2873
2874
2875/// Computes a percentile for `X ~ Geo(p)`
2876/// where `X =` the trial on which the first success is observed.
2877///
2878/// # Note
2879/// Determines the smallest (integer) value of `x` such that `P(X <= x) >= q`.
2880/// # Parameters
2881/// - `p` = probability of success (`0 < p <= 1`)
2882/// # Support
2883/// - `x = 1,2,3,...`
2884/// # Example
2885/// Suppose `X ~ Geo(p=0.6)`. To find the 80th percentile, use `q=0.80` and
2886/// ```
2887/// use ruststat::geo2_per;
2888/// println!("Percentile: {}", geo2_per(0.8, 0.6));
2889/// ```
2890pub fn geo2_per(q: f64, p: f64) -> i32 {
2891    let mut x = 1;
2892
2893    if p <= 0.0 || p > 1.0 || q < 0.0 || q > 1.0 {
2894        println!("NAN produced. Error in function geo2_per");
2895        return f64::NAN as i32;
2896    }
2897    if q == 0.0 {
2898        return 1;
2899    }
2900    if q == 1.0 {
2901        return i32::MAX;
2902    }
2903
2904    while geo2_cdf(x, p) < q {
2905        x += 1;
2906    }
2907    return x;
2908}
2909
2910
2911/// Random draw from `X ~ Geo(p)` distribution
2912/// where `X =` the trial on which the first success is observed.
2913///
2914/// # Parameters
2915/// - `p` = probability of success (`0 < p <= 1`)
2916/// # Example
2917/// Suppose `X ~ Geo(p=0.6)`. Use
2918/// ```
2919/// use ruststat::geo2_ran;
2920/// println!("Random draw: {}", geo2_ran(0.6));
2921/// ```
2922pub fn geo2_ran(p: f64) -> i32 {
2923
2924    if p <= 0.0 || p > 1.0 {
2925        println!("NAN produced. Error in function geo2_ran");
2926        return f64::NAN as i32;
2927    }
2928
2929    let u = unif_ran(0.0, 1.0);
2930    return (u.ln() / (1.0-p).ln()).floor() as i32 + 1;
2931
2932    // let cdf = rand::thread_rng().gen();
2933    // let mut x = 1;
2934    //
2935    // while geo2_cdf(x, p) < cdf {
2936    //     x += 1;
2937    // }
2938    // return x;
2939}
2940
2941/// Save random draws from `X ~ Geo(p)` distribution into a `Vec`
2942/// where `X =` the trial on which the first success is observed.
2943///
2944/// # Parameters
2945/// - `p` = probability of success (`0 < p <= 1`)
2946/// # Example
2947/// Suppose `X ~ Geo(p=0.6)`. Use
2948/// ```
2949/// use ruststat::geo2_ranvec;
2950/// println!("Random Vec: {:?}", geo2_ranvec(10, 0.6));
2951/// ```
2952pub fn geo2_ranvec(nn: i32, p: f64) -> Vec<i32> {
2953    let mut xvec: Vec<i32> = Vec::new();
2954    for _ in 0..nn {
2955        xvec.push(geo2_ran(p));
2956    }
2957    return xvec;
2958}
2959
2960
2961// ==========================================
2962// ==========================================
2963// HyperGeometric Distribution
2964// ==========================================
2965// ==========================================
2966
2967/// Struct for the hypergeometric distribution `X ~ HG(n,N,M)`.
2968///
2969/// # Parameters
2970/// - Sample size: `n = 1,2,3,...,N`
2971/// - Population size: `N = 1,2,3,...`
2972/// - Number of successes in population: `M = 1,2,3,...,N`
2973/// # Support
2974/// - `x = 0,1,2,...,n`
2975/// - `x <= M`
2976/// - `n-x <= N-M`
2977/// # Example
2978/// Suppose `X ~ HG(n=20, N=100, M=50)`. Use
2979/// ```
2980/// use ruststat::HGDist;
2981/// let mut myhg = HGDist{n:20, N:100, M:50};
2982/// println!("P(X=6): {}", myhg.pmf(6));
2983/// println!("P(X<=6): {}", myhg.cdf(6));
2984/// println!("99th percentile: {}", myhg.per(0.99));
2985/// println!("Random draw: {}", myhg.ran());
2986/// println!("Random vector: {:?}", myhg.ranvec(5));
2987/// println!("Mean: {}", myhg.mean());
2988/// println!("Variance: {}", myhg.var());
2989/// println!("Standard deviation: {}", myhg.sd());
2990/// ```
2991#[allow(non_snake_case)]
2992pub struct HGDist {
2993    pub n: i32,
2994    pub N: i32,
2995    pub M: i32,
2996}
2997impl HGDist {
2998    pub fn pmf(&mut self, x: i32) -> f64 {
2999        return hg_pmf(x, self.n, self.N, self.M);
3000    }
3001    pub fn cdf(&mut self, x: i32) -> f64 {
3002        return hg_cdf(x, self.n, self.N, self.M);
3003    }
3004    pub fn per(&mut self, q: f64) -> i32 {
3005        return hg_per(q, self.n, self.N, self.M);
3006    }
3007    pub fn ran(&mut self) -> i32 {
3008        return hg_ran(self.n, self.N, self.M);
3009    }
3010    pub fn ranvec(&mut self, n: i32) -> Vec<i32> {
3011        return hg_ranvec(n, self.n, self.N, self.M);
3012    }
3013    pub fn mean(&mut self) -> f64 {
3014        return (self.n as f64) * (self.M as f64) / (self.N as f64);
3015    }
3016    pub fn var(&mut self) -> f64 {
3017        return (self.n as f64) *
3018            (self.M as f64) / (self.N as f64) *
3019            (1.0 - (self.M as f64) / (self.N as f64)) *
3020            (self.N as f64 - self.n as f64) / (self.N as f64 - 1.0);
3021    }
3022    pub fn sd(&mut self) -> f64 {
3023        return self.var().sqrt();
3024    }
3025}
3026
3027
3028/// Computes probability mass function (pmf) for `X ~ HG(n,N,M)`
3029/// where `X =` the number of successes.
3030///
3031/// # Parameters
3032/// - Sample size: `n = 1,2,3,...,N`
3033/// - Population size: `N = 1,2,3,...`
3034/// - Number of successes in population: `M = 1,2,3,...,N`
3035/// # Support
3036/// - `x = 0,1,2,...,n`
3037/// - `x <= M`
3038/// - `n-x <= N-M`
3039/// # Example
3040/// Suppose `X ~ HG(n=20,N=100,M=50)`. To compute `P(X = 7)`, use
3041/// ```
3042/// use ruststat::hg_pmf;
3043/// println!("P(X=x): {}", hg_pmf(7, 20, 100, 50));
3044/// ```
3045#[allow(non_snake_case)]
3046pub fn hg_pmf(x: i32, n: i32, N: i32, M: i32) -> f64 {
3047    if  n < 1 || N < 1 || M < 1 || M > N || n > N {
3048        println!("NAN produced. Error in function hg_pmf");
3049        return f64::NAN;
3050    }
3051    if x < 0 || x > n || x > M || (n-x) > (N-M) {
3052        return 0.0;
3053    }
3054
3055    return comb(M, x) * comb(N-M, n-x) / comb(N, n);
3056}
3057
3058
3059/// Computes cumulative distribution function (cdf) for `X ~ HG(n,N,M)`
3060/// where `X =` the number of successes.
3061///
3062/// # Parameters
3063/// - Sample size: `n = 1,2,3,...,N`
3064/// - Population size: `N = 1,2,3,...`
3065/// - Number of successes in population: `M = 1,2,3,...,N`
3066/// # Support
3067/// - `x = 0,1,2,...,n`
3068/// - `x <= M`
3069/// - `n-x <= N-M`
3070/// # Example
3071/// Suppose `X ~ HG(n=20,N=100,M=50)`. To compute `P(X <= 7)`, use
3072/// ```
3073/// use ruststat::hg_cdf;
3074/// println!("P(X<=x): {}", hg_cdf(7, 20, 100, 50));
3075/// ```
3076#[allow(non_snake_case)]
3077pub fn hg_cdf(x: i32, n: i32, N: i32, M: i32) -> f64 {
3078    if  n < 1 || N < 1 || M < 1 || M > N || n > N {
3079        println!("NAN produced. Error in function hg_cdf");
3080        return f64::NAN;
3081    }
3082    if x < 0 || x > M || (n-x) > (N-M) {
3083        return 0.0;
3084    }
3085    if x > n {
3086        return 1.0;
3087    }
3088
3089    let mut sum = 0.0;
3090    for i in 0..=x {
3091        sum += hg_pmf(i, n, N, M);
3092    }
3093    return sum;
3094}
3095
3096
3097/// Computes a percentile for `X ~ HG(n,N,M)`
3098/// where `X =` the number of successes.
3099///
3100/// # Note
3101/// Determines the smallest (integer) value of `x` such that `P(X <= x) >= q`.
3102/// # Parameters
3103/// - Sample size: `n = 1,2,3,...,N`
3104/// - Population size: `N = 1,2,3,...`
3105/// - Number of successes in population: `M = 1,2,3,...,N`
3106/// # Support
3107/// - `x = 0,1,2,...,n`
3108/// - `x <= M`
3109/// - `n-x <= N-M`
3110/// # Example
3111/// Suppose `X ~ HG(n=20, N=100, M=50)`. To find the 80th percentile, use `q=0.80` and
3112/// ```
3113/// use ruststat::hg_per;
3114/// println!("Percentile: {}", hg_per(0.8, 20, 100, 50));
3115/// ```
3116#[allow(non_snake_case)]
3117pub fn hg_per(q: f64, n: i32, N: i32, M: i32) -> i32 {
3118    let mut x = 0;
3119
3120    if  n < 1 || N < 1 || M < 1 ||
3121        M > N || n > N ||
3122        q < 0.0 || q > 1.0 {
3123        println!("NAN produced. Error in function hg_per");
3124        return f64::NAN as i32;
3125    }
3126    // if q == 0.0 {
3127    //     return 0;
3128    // }
3129    // if q == 1.0 {
3130    //     return n;
3131    // }
3132
3133    while hg_cdf(x, n, N, M) < q {
3134        x += 1;
3135    }
3136    return x;
3137}
3138
3139
3140/// Random draw from `X ~ HG(n, N, M)` distribution
3141/// where `X =` the number of successes.
3142///
3143/// # Parameters
3144/// - Sample size: `n = 1,2,3,...,N`
3145/// - Population size: `N = 1,2,3,...`
3146/// - Number of successes in population: `M = 1,2,3,...,N`
3147/// # Example
3148/// Suppose `X ~ HG(n=20, N=100, M=50)`. Use
3149/// ```
3150/// use ruststat::hg_ran;
3151/// println!("Random draw: {}", hg_ran(20, 100, 50));
3152/// ```
3153#[allow(non_snake_case)]
3154pub fn hg_ran(n: i32, N: i32, M: i32) -> i32 {
3155
3156    if  n < 1 || N < 1 || M < 1 ||
3157        M > N || n > N {
3158        println!("NAN produced. Error in function hg_ran");
3159        return f64::NAN as i32;
3160    }
3161
3162
3163    // use rand::seq::index::sample;
3164    // use rand::seq::SliceRandom;
3165    use rand::rng;
3166
3167    let mut rng = rng();
3168
3169    let popn = Vec::from_iter(1..=N);
3170    let sample = popn.choose_multiple(&mut rng, n as usize);
3171    // let sample = popn.choose_multiple(&mut rng, n as usize);
3172    let x = sample.filter(|&x| *x <= M).count();
3173    return x as i32;
3174    // println!("count <= M: {}", sample.filter(|&x| *x <= M).count());
3175
3176
3177    // let cdf = rand::thread_rng().gen();
3178    // let mut x = 0;
3179    //
3180    // while hg_cdf(x, n, N, M) < cdf {
3181    //     x += 1;
3182    // }
3183    // return x;
3184}
3185
3186
3187/// Save random draws from `X ~ HG(n,N,M)` distribution into a `Vec`
3188/// where `X =` the number of successes.
3189///
3190/// # Parameters
3191/// - Sample size: `n = 1,2,3,...,N`
3192/// - Population size: `N = 1,2,3,...`
3193/// - Number of successes in population: `M = 1,2,3,...,N`
3194/// # Example
3195/// Suppose `X ~ HG(n=20, N=100, M=50)`. Use
3196/// ```
3197/// use ruststat::hg_ranvec;
3198/// println!("Random Vec: {:?}", hg_ranvec(10, 20, 100, 50));
3199/// ```
3200#[allow(non_snake_case)]
3201pub fn hg_ranvec(nn: i32, n: i32, N: i32, M: i32) -> Vec<i32> {
3202    let mut xvec: Vec<i32> = Vec::new();
3203    for _ in 0..nn {
3204        xvec.push(hg_ran(n,N,M));
3205    }
3206    return xvec;
3207}
3208
3209
3210// ==========================================
3211// ==========================================
3212// Negative Binomial Distribution
3213// ==========================================
3214// ==========================================
3215
3216/// Struct for the negative binomial distribution `X ~ NB(r,p)` where
3217/// `X =` the number of failures prior to observing the `r`th success.
3218///
3219/// # Parameters
3220/// - `r = 1,2,3,...`
3221/// - `p` = probability of success (`0 < p <= 1`)
3222/// # Support
3223/// - `x = 0,1,2,...`
3224/// # Example
3225/// Suppose `X ~ NB(r=4,p=0.2)`. Use
3226/// ```
3227/// use ruststat::NBDist;
3228/// let mut mynb = NBDist{r:4, p:0.2};
3229/// println!("P(X=6): {}", mynb.pmf(6));
3230/// println!("P(X<=6): {}", mynb.cdf(6));
3231/// println!("99th percentile: {}", mynb.per(0.99));
3232/// println!("Random draw: {}", mynb.ran());
3233/// println!("Random vector: {:?}", mynb.ranvec(5));
3234/// println!("Mean: {}", mynb.mean());
3235/// println!("Variance: {}", mynb.var());
3236/// println!("Standard deviation: {}", mynb.sd());
3237/// ```
3238pub struct NBDist {
3239    pub r: i32,
3240    pub p: f64,
3241}
3242impl NBDist {
3243    pub fn pmf(&mut self, x: i32) -> f64 {
3244        return nb_pmf(x, self.r, self.p);
3245    }
3246    pub fn cdf(&mut self, x: i32) -> f64 {
3247        return nb_cdf(x, self.r, self.p);
3248    }
3249    pub fn per(&mut self, q: f64) -> i32 {
3250        return nb_per(q, self.r, self.p);
3251    }
3252    pub fn ran(&mut self) -> i32 {
3253        return nb_ran(self.r, self.p);
3254    }
3255    pub fn ranvec(&mut self, n: i32) -> Vec<i32> {
3256        return nb_ranvec(n, self.r, self.p);
3257    }
3258    pub fn mean(&mut self) -> f64 {
3259        return (self.r as f64) * (1.0 - self.p) / self.p;
3260    }
3261    pub fn var(&mut self) -> f64 {
3262        return (self.r as f64) * (1.0 - self.p) / self.p.powi(2);
3263    }
3264    pub fn sd(&mut self) -> f64 {
3265        return self.var().sqrt();
3266    }
3267}
3268
3269
3270/// Computes probability mass function (pmf) for `X ~ NB(r,p)`
3271/// where `X =` the number of failures prior to the `r`th success.
3272///
3273/// # Parameters
3274/// - `r = 1,2,...`
3275/// - `p` = probability of success (`0 < p <= 1`)
3276/// # Support
3277/// - `x = 0,1,2,...`
3278/// # Example
3279/// Suppose `X ~ NB(r=2,p=0.6)`. To compute `P(X = 3)`, use
3280/// ```
3281/// use ruststat::nb_pmf;
3282/// println!("P(X=x): {}", nb_pmf(3, 2, 0.6));
3283/// ```
3284pub fn nb_pmf(x: i32, r: i32, p: f64) -> f64 {
3285    if r < 1 || p <= 0.0 || p > 1.0  {
3286        println!("NAN produced. Error in function nb_pmf");
3287        return f64::NAN;
3288    }
3289    if x < 0 {
3290        return 0.0;
3291    }
3292    return comb(x+r-1, r-1) * p.powi(r) * (1.0-p).powi(x);
3293}
3294
3295
3296/// Computes cumulative distribution function (cdf) for `X ~ NB(r,p)`
3297/// where `X =` the number of failures prior to the `r`th success.
3298///
3299/// # Parameters
3300/// - `r = 1,2,...`
3301/// - `p` = probability of success (`0 <= p <= 1`)
3302/// # Support
3303/// - `x = 0,1,2,...`
3304/// # Example
3305/// Suppose `X ~ NB(r=2, p=0.6)`. To compute `P(X <= 3)`, use
3306/// ```
3307/// use ruststat::nb_cdf;
3308/// println!("P(X<=x): {}", nb_cdf(3, 2, 0.6));
3309/// ```
3310pub fn nb_cdf(x: i32, r: i32, p: f64) -> f64 {
3311    if r < 1 || p <= 0.0 || p > 1.0  {
3312        println!("NAN produced. Error in function nb_cdf");
3313        return f64::NAN;
3314    }
3315    if x < 0 {
3316        return 0.0;
3317    }
3318
3319    let mut sum = 0.0;
3320    for i in 0..=x {
3321        sum += nb_pmf(i, r, p);
3322    }
3323    return sum;
3324}
3325
3326
3327/// Computes a percentile for `X ~ NB(r,p)`
3328/// where `X =` the number of failures prior to the `r`th success.
3329///
3330/// # Note
3331/// Determines the smallest (integer) value of `x` such that `P(X <= x) >= q`.
3332/// # Parameters
3333/// - `r = 1,2,...`
3334/// - `p` = probability of success (`0 < p <= 1`)
3335/// # Support
3336/// - `x = 0,1,2,...`
3337/// # Example
3338/// Suppose `X ~ NB(r=2, p=0.6)`. To find the 80th percentile, use `q=0.80` and
3339/// ```
3340/// use ruststat::nb_per;
3341/// println!("Percentile: {}", nb_per(0.8, 2, 0.6));
3342/// ```
3343pub fn nb_per(q: f64, r: i32, p: f64) -> i32 {
3344    let mut x = 0;
3345
3346    if r < 0 || p <= 0.0 || p > 1.0 || q < 0.0 || q > 1.0 {
3347        println!("NAN produced. Error in function nb_per");
3348        return f64::NAN as i32;
3349    }
3350    if q == 0.0 {
3351        return 0;
3352    }
3353    if q == 1.0 {
3354        return i32::MAX;
3355    }
3356
3357    while nb_cdf(x, r, p) < q {
3358        x += 1;
3359    }
3360    return x;
3361}
3362
3363
3364/// Random draw from `X ~ NB(r, p)` distribution
3365/// where `X =` the number of failures prior to the `r`th success.
3366///
3367/// # Parameters
3368/// - `r = 1,2,...`
3369/// - `p` = probability of success (`0 < p <= 1`)
3370/// # Example
3371/// Suppose `X ~ NB(r=2, p=0.6)`. Use
3372/// ```
3373/// use ruststat::nb_ran;
3374/// println!("Random draw: {}", nb_ran(2, 0.6));
3375/// ```
3376pub fn nb_ran(r: i32, p: f64) -> i32 {
3377
3378    if r < 0 || p <= 0.0 || p > 1.0 {
3379        println!("NAN produced. Error in function nb_ran");
3380        return f64::NAN as i32;
3381    }
3382
3383    let mut geo_vec = Vec::new();
3384    for _ in 0..r {
3385        geo_vec.push(geo_ran(p));
3386    }
3387    return geo_vec.iter().sum();
3388    // let cdf = rand::thread_rng().gen();
3389    // let mut x = 0;
3390    //
3391    // while nb_cdf(x, r, p) < cdf {
3392    //     x += 1;
3393    // }
3394    // return x;
3395}
3396
3397
3398/// Save random draws from `X ~ NB(r,p)` distribution into a `Vec`
3399/// where `X =` the number of failures prior to the `r`th success.
3400///
3401/// # Parameters
3402/// - `r = 1,2,...`
3403/// - `p` = probability of success (`0 < p <= 1`)
3404/// # Example
3405/// Suppose `X ~ NB(r=2, p=0.6)`. Use
3406/// ```
3407/// use ruststat::nb_ranvec;
3408/// println!("Random Vec: {:?}", nb_ranvec(10, 2, 0.6));
3409/// ```
3410pub fn nb_ranvec(nn: i32, r: i32, p: f64) -> Vec<i32> {
3411    let mut xvec: Vec<i32> = Vec::new();
3412    for _ in 0..nn {
3413        xvec.push(nb_ran(r,p));
3414    }
3415    return xvec;
3416}
3417
3418
3419// ==========================================
3420// ==========================================
3421// Negative Binomial Distribution 2
3422// ==========================================
3423// ==========================================
3424
3425/// Struct for the negative binomial distribution `X ~ NB(r,p)` where
3426/// `X =` the trial on which the `r`th success is observed.
3427///
3428/// # Parameters
3429/// - `r = r,r+1,r+2,...`
3430/// - `p` = probability of success (`0 < p <= 1`)
3431/// # Support
3432/// - `x = r,r+1,r+2,...`
3433/// # Example
3434/// Suppose `X ~ NB(r=4,p=0.2)`. Use
3435/// ```
3436/// use ruststat::NB2Dist;
3437/// let mut mynb = NB2Dist{r:4, p:0.2};
3438/// println!("P(X=6): {}", mynb.pmf(6));
3439/// println!("P(X<=6): {}", mynb.cdf(6));
3440/// println!("99th percentile: {}", mynb.per(0.99));
3441/// println!("Random draw: {}", mynb.ran());
3442/// println!("Random vector: {:?}", mynb.ranvec(5));
3443/// println!("Mean: {}", mynb.mean());
3444/// println!("Variance: {}", mynb.var());
3445/// println!("Standard deviation: {}", mynb.sd());
3446/// ```
3447pub struct NB2Dist {
3448    pub r: i32,
3449    pub p: f64,
3450}
3451impl NB2Dist {
3452    pub fn pmf(&mut self, x: i32) -> f64 {
3453        return nb2_pmf(x, self.r, self.p);
3454    }
3455    pub fn cdf(&mut self, x: i32) -> f64 {
3456        return nb2_cdf(x, self.r, self.p);
3457    }
3458    pub fn per(&mut self, q: f64) -> i32 {
3459        return nb2_per(q, self.r, self.p);
3460    }
3461    pub fn ran(&mut self) -> i32 {
3462        return nb2_ran(self.r, self.p);
3463    }
3464    pub fn ranvec(&mut self, n: i32) -> Vec<i32> {
3465        return nb2_ranvec(n, self.r, self.p);
3466    }
3467    pub fn mean(&mut self) -> f64 {
3468        return (self.r as f64) / self.p;
3469    }
3470    pub fn var(&mut self) -> f64 {
3471        return (self.r as f64) * (1.0 - self.p) / self.p.powi(2);
3472    }
3473    pub fn sd(&mut self) -> f64 {
3474        return self.var().sqrt();
3475    }
3476}
3477
3478
3479/// Computes probability mass function (pmf) for `X ~ NB(r,p)`
3480/// where `X =` the trial on which the `r`th success is observed.
3481///
3482/// # Parameters
3483/// - `r = r,r+1,r+2,...`
3484/// - `p` = probability of success (`0 < p <= 1`)
3485/// # Support
3486/// - `x = r,r+1,r+2,...`
3487/// # Example
3488/// Suppose `X ~ NB(r=2,p=0.6)`. To compute `P(X = 3)`, use
3489/// ```
3490/// use ruststat::nb2_pmf;
3491/// println!("P(X=x): {}", nb2_pmf(3, 2, 0.6));
3492/// ```
3493pub fn nb2_pmf(x: i32, r: i32, p: f64) -> f64 {
3494    if  r < 1 || p <= 0.0 || p > 1.0 {
3495        println!("NAN produced. Error in function nb2_pmf");
3496        return f64::NAN;
3497    }
3498    if x < r {
3499        return 0.0;
3500    }
3501    return comb(x-1, r-1) * p.powi(r) * (1.0-p).powi(x-r);
3502}
3503
3504
3505/// Computes cumulative distribution function (cdf) for `X ~ NB(r,p)`
3506/// where `X =` the trial on which the `r`th success is observed.
3507///
3508/// # Parameters
3509/// - `r = r,r+1,r+2,...`
3510/// - `p` = probability of success (`0 <= p <= 1`)
3511/// # Support
3512/// - `x = r,r+1,r+2,...`
3513/// # Example
3514/// Suppose `X ~ NB(r=2, p=0.6)`. To compute `P(X <= 3)`, use
3515/// ```
3516/// use ruststat::nb2_cdf;
3517/// println!("P(X<=x): {}", nb2_cdf(3, 2, 0.6));
3518/// ```
3519pub fn nb2_cdf(x: i32, r: i32, p: f64) -> f64 {
3520    if  r < 1 || p <= 0.0 || p > 1.0 {
3521        println!("NAN produced. Error in function nb2_cdf");
3522        return f64::NAN;
3523    }
3524    if x < r {
3525        return 0.0;
3526    }
3527
3528    let mut sum = 0.0;
3529    for i in r..=x {
3530        sum += nb2_pmf(i, r, p);
3531    }
3532    return sum;
3533}
3534
3535
3536/// Computes a percentile for `X ~ NB(r,p)`
3537/// where `X =` the trial on which the `r`th success is observed.
3538///
3539/// # Note
3540/// Determines the smallest (integer) value of `x` such that `P(X <= x) >= q`.
3541/// # Parameters
3542/// - `r = r,r+1,r+2,...`
3543/// - `p` = probability of success (`0 < p <= 1`)
3544/// # Support
3545/// - `x = r,r+1,r+2,...`
3546/// # Example
3547/// Suppose `X ~ NB(r=2, p=0.6)`. To find the 80th percentile, use `q=0.80` and
3548/// ```
3549/// use ruststat::nb2_per;
3550/// println!("Percentile: {}", nb2_per(0.8, 2, 0.6));
3551/// ```
3552pub fn nb2_per(q: f64, r: i32, p: f64) -> i32 {
3553
3554    if  r < 1 || p <= 0.0 || p > 1.0 || q < 0.0 || q > 1.0 {
3555        println!("NAN produced. Error in function nb2_per");
3556        return f64::NAN as i32;
3557    }
3558    if q == 0.0 {
3559        return r;
3560    }
3561    if q == 1.0 {
3562        return f64::INFINITY as i32;
3563    }
3564
3565    let mut x = r;
3566    while nb2_cdf(x, r, p) < q {
3567        x += 1;
3568    }
3569    return x;
3570}
3571
3572
3573/// Random draw from `X ~ NB(r, p)` distribution
3574/// where `X =` the trial on which the `r`th success is observed.
3575///
3576/// # Parameters
3577/// - `r = r,r+1,r+2,...`
3578/// - `p` = probability of success (`0 < p <= 1`)
3579/// # Example
3580/// Suppose `X ~ NB(r=2, p=0.6)`. Use
3581/// ```
3582/// use ruststat::nb2_ran;
3583/// println!("Random draw: {}", nb2_ran(2, 0.6));
3584/// ```
3585pub fn nb2_ran(r: i32, p: f64) -> i32 {
3586
3587    if  r < 1 || p <= 0.0 || p > 1.0 {
3588        println!("NAN produced. Error in function nb2_ran");
3589        return f64::NAN as i32;
3590    }
3591
3592    let mut geo2_vec = Vec::new();
3593    for _ in 0..r {
3594        geo2_vec.push(geo2_ran(p));
3595    }
3596    return geo2_vec.iter().sum();
3597
3598    // let cdf = unif_ran(0.0, 1.0);
3599    // let mut x = r;
3600    //
3601    // while nb2_cdf(x, r, p) < cdf {
3602    //     x += 1;
3603    // }
3604    // return x;
3605}
3606
3607
3608/// Save random draws from `X ~ NB(r,p)` distribution into a `Vec`
3609/// where `X =` the trial on which the `r`th success is observed.
3610///
3611/// # Parameters
3612/// - `r = r,r+1,r+2,...`
3613/// - `p` = probability of success (`0 < p <= 1`)
3614/// # Example
3615/// Suppose `X ~ NB(r=2, p=0.6)`. Use
3616/// ```
3617/// use ruststat::nb2_ranvec;
3618/// println!("Random Vec: {:?}", nb2_ranvec(10, 2, 0.6));
3619/// ```
3620pub fn nb2_ranvec(nn: i32, r: i32, p: f64) -> Vec<i32> {
3621    let mut xvec: Vec<i32> = Vec::new();
3622    for _ in 0..nn {
3623        xvec.push(nb2_ran(r,p));
3624    }
3625    return xvec;
3626}
3627
3628
3629// ==========================================
3630// ==========================================
3631// Poisson Distribution
3632// ==========================================
3633// ==========================================
3634
3635/// Struct for the Poisson distribution `X ~ Pois(lambda)`.
3636///
3637/// # Parameters
3638/// - `lambda > 0`
3639/// # Support
3640/// - `x = 0,1,2,...`
3641/// # Example
3642/// Suppose `X ~ Pois(lambda=2.5)`. Use
3643/// ```
3644/// use ruststat::PoisDist;
3645/// let mut mypois = PoisDist{lambda:2.5};
3646/// println!("P(X=6): {}", mypois.pmf(6));
3647/// println!("P(X<=6): {}", mypois.cdf(6));
3648/// println!("99th percentile: {}", mypois.per(0.99));
3649/// println!("Random draw: {}", mypois.ran());
3650/// println!("Random vector: {:?}", mypois.ranvec(5));
3651/// println!("Mean: {}", mypois.mean());
3652/// println!("Variance: {}", mypois.var());
3653/// println!("Standard deviation: {}", mypois.sd());
3654/// ```
3655pub struct PoisDist {
3656    pub lambda: f64,
3657}
3658impl PoisDist {
3659    pub fn pmf(&mut self, x: i32) -> f64 {
3660        return pois_pmf(x, self.lambda);
3661    }
3662    pub fn cdf(&mut self, x: i32) -> f64 {
3663        return pois_cdf(x, self.lambda);
3664    }
3665    pub fn per(&mut self, q: f64) -> i32 {
3666        return pois_per(q, self.lambda);
3667    }
3668    pub fn ran(&mut self) -> i32 {
3669        return pois_ran(self.lambda);
3670    }
3671    pub fn ranvec(&mut self, n: i32) -> Vec<i32> {
3672        return pois_ranvec(n, self.lambda);
3673    }
3674    pub fn mean(&mut self) -> f64 {
3675        return self.lambda;
3676    }
3677    pub fn var(&mut self) -> f64 {
3678        return self.lambda;
3679    }
3680    pub fn sd(&mut self) -> f64 {
3681        return self.var().sqrt();
3682    }
3683}
3684
3685
3686/// Computes probability mass function (pmf) for `X ~ Pois(lambda).`
3687///
3688/// # Parameters
3689/// - `lambda > 0`
3690/// # Support
3691/// - `x = 0,1,2,...`
3692/// # Example
3693/// Suppose `X ~ Pois(lambda=2.5)`. To compute `P(X = 4)`, use
3694/// ```
3695/// use ruststat::pois_pmf;
3696/// println!("P(X=x): {}", pois_pmf(4, 2.5));
3697/// ```
3698pub fn pois_pmf(x: i32, lambda: f64) -> f64 {
3699    if lambda <= 0.0 {
3700        println!("NAN produced. Error in function pois_pmf");
3701        return f64::NAN;
3702    }
3703    if x < 0 {
3704        return 0.0;
3705    }
3706    return (-lambda).exp() * lambda.powi(x) / (fact_i(x) as f64);
3707}
3708
3709
3710/// Computes cumulative distriubtion function (cdf) for `X ~ Pois(lambda).`
3711///
3712/// # Parameters
3713/// - `lambda > 0`
3714/// # Support
3715/// - `x = 0,1,2,...`
3716/// # Example
3717/// Suppose `X ~ Pois(lambda=2.5)`. To compute `P(X <= 4)`, use
3718/// ```
3719/// use ruststat::pois_cdf;
3720/// println!("P(X<=x): {}", pois_cdf(4, 2.5));
3721/// ```
3722// pub fn pois_cdf(x: i32, lambda: f64) -> f64 {
3723//     if lambda <= 0.0 || x < 0 {
3724//         println!("NAN produced. Error in function pois_cdf");
3725//         return f64::NAN;
3726//     }
3727//     let mut sum = 0.0;
3728//     for i in 0..=x {
3729//         sum += pois_pmf(i, lambda);
3730//     }
3731//     return sum;
3732// }
3733pub fn pois_cdf(x: i32, lambda: f64) -> f64 {
3734    if lambda <= 0.0 {
3735        println!("NAN produced. Error in function pois_cdf");
3736        return f64::NAN;
3737    }
3738    if x < 0 {
3739        return 0.0;
3740    }
3741    return gammq(lambda, (x+1) as f64);
3742}
3743
3744
3745/// Computes a percentile for `X ~ Pois(lambda)`.
3746///
3747/// # Note
3748/// Determines the smallest (integer) value of `x` such that `P(X <= x) >= q`.
3749/// # Parameters
3750/// - `lambda > 0`
3751/// # Support
3752/// - `x = 0,1,2,...`
3753/// # Example
3754/// Suppose `X ~ Pois(lambda=2.5)`. To find the 80th percentile, use `q=0.80` and
3755/// ```
3756/// use ruststat::pois_per;
3757/// println!("Percentile: {}", pois_per(2.5, 0.8));
3758/// ```
3759pub fn pois_per(q: f64, lambda: f64) -> i32 {
3760    let mut x = 0;
3761
3762    if lambda <= 0.0 || q < 0.0 || q > 1.0 {
3763        println!("NAN produced. Error in function pois_per");
3764        return f64::NAN as i32;
3765    }
3766    if q == 0.0 {
3767        return 0;
3768    }
3769    if q == 1.0 {
3770        return i32::MAX;
3771    }
3772
3773    while pois_cdf(x, lambda) < q {
3774        x += 1;
3775    }
3776    return x;
3777}
3778
3779
3780/// Random draw from `X ~ Pois(r, p)` distribution.
3781/// Sheldon Ross, Simulation, 2003
3782///
3783/// # Parameters
3784/// - `lambda > 0`
3785/// # Example
3786/// Suppose `X ~ Pois(lambda=2.5)`. Use
3787/// ```
3788/// use ruststat::pois_ran;
3789/// println!("Random draw: {}", pois_ran(2.5));
3790/// ```
3791pub fn pois_ran(lambda: f64) -> i32 {
3792
3793    if lambda <= 0.0 {
3794        println!("NAN produced. Error in function pois_ran");
3795        return f64::NAN as i32;
3796    }
3797
3798    let u = unif_ran(0.0, 1.0);
3799    let mut i = 0;
3800    let mut p = (-lambda).exp();
3801    let mut f = p;
3802    loop {
3803        if u < f {
3804            return i;
3805        }
3806        p = lambda*p / (i+1) as f64;
3807        f = f + p;
3808        i = i + 1;
3809    }
3810    // return 0;
3811    // let exp_lambda = (-lambda).exp(); //constant for terminating loop
3812    // let (mut u,mut prod,mut r): (f64, f64, i32);
3813    //
3814    // r = -1;
3815    // prod = 1.0;
3816    //
3817    // while (prod > exp_lambda) {
3818    //     u = unif_ran(0.0, 1.0); //generate uniform variable
3819    //     prod = prod * u; //update product
3820    //     r += 1; //increase Poisson variable
3821    // }
3822    //
3823    // return r;
3824
3825    // let cdf = unif_ran(0.0, 1.0);
3826    // let mut x = 0;
3827    //
3828    // while pois_cdf(x, lambda) < cdf {
3829    //     x += 1;
3830    // }
3831    // return x;
3832}
3833
3834
3835/// Save random draws from `X ~ Pois(lambda)` distribution into a `Vec`
3836///
3837/// # Parameters
3838/// - `lambda > 0`
3839/// # Example
3840/// Suppose `X ~ Pois(lambda=2.5)`. Use
3841/// ```
3842/// use ruststat::pois_ranvec;
3843/// println!("Random Vec: {:?}", pois_ranvec(10, 2.5));
3844/// ```
3845pub fn pois_ranvec(nn: i32, lambda: f64) -> Vec<i32> {
3846    let mut xvec: Vec<i32> = Vec::new();
3847    for _ in 0..nn {
3848        xvec.push(pois_ran(lambda));
3849    }
3850    return xvec;
3851}
3852
3853
3854
3855// ===========================================================================
3856// ===========================================================================
3857// Special Functions
3858// ===========================================================================
3859// ===========================================================================
3860
3861/// Incomplete beta function.
3862///
3863/// # Parameters
3864/// - `a > 0`
3865/// - `b > 0`
3866/// - `0 < x < 1`
3867/// # Example
3868/// Suppose `X ~ Beta(alpha=0.5, beta=2.0)`.
3869/// ```
3870/// use ruststat::betai;
3871/// println!("Incomplete beta function: {}", betai(0.7, 0.5, 2.0));
3872/// ```
3873pub fn betai(x: f64, a: f64, b: f64) -> f64 {
3874
3875    let bt: f64;
3876
3877    if x < 0.0 || x > 1.0 {
3878        println!("Bad x in function betai");
3879        return f64::NAN;
3880    }
3881    if x == 0.0 || x == 1.0 {
3882        bt=0.0;
3883    }
3884    else {
3885        bt=(gammaln(a+b)-gammaln(a)-gammaln(b) +
3886            a*x.ln() +
3887            b*(1.0-x).ln()).exp();
3888    }
3889    return if x < ((a + 1.0) / (a + b + 2.0)) {
3890        bt * betacf(x, a, b) / a
3891    } else {
3892        1.0 - bt * betacf(1.0 - x, b, a) / b
3893    }
3894}
3895
3896
3897fn betacf(x: f64, a: f64, b: f64) -> f64 {
3898    let imax = 100;
3899    let eps = 3.0e-7;
3900    let fpmin = 1.0e-30;
3901
3902    let mut m2: i32;
3903    let mut aa: f64;
3904    let mut c: f64;
3905    let mut d: f64;
3906    let mut del: f64;
3907    let mut h: f64;
3908    let qab: f64;
3909    let qam: f64;
3910    let qap: f64;
3911
3912    qab=a+b;
3913    qap=a+1.0;
3914    qam=a-1.0;
3915    c=1.0;
3916    d=1.0-qab*x/qap;
3917    if d.abs() < fpmin {
3918        d=fpmin;
3919    }
3920    d=1.0/d;
3921    h=d;
3922    for m in 1..=imax {
3923        m2=2*m;
3924        aa=(m as f64)*(b-m as f64)*x/((qam+m2 as f64)*(a+m2 as f64));
3925        d=1.0+aa*d;
3926        if d.abs() < fpmin {
3927            d=fpmin;
3928        }
3929        c=1.0+aa/c;
3930        if c.abs() < fpmin {
3931            c=fpmin;
3932        }
3933        d=1.0/d;
3934        h *= d*c;
3935        aa = -(a+m as f64)*(qab+m as f64)*x/((a+m2 as f64)*(qap+m2 as f64));
3936        d=1.0+aa*d;
3937        if d.abs() < fpmin {
3938            d=fpmin;
3939        }
3940        c=1.0+aa/c;
3941        if c.abs() < fpmin {
3942            c=fpmin;
3943        }
3944        d=1.0/d;
3945        del=d*c;
3946        h *= del;
3947        if (del-1.0).abs() < eps {
3948            break;
3949        }
3950    }
3951    // if (m > MAXIT) nrerror("a or b too big, or MAXIT too small in betacf");
3952    return h;
3953}
3954
3955
3956/// Log gamma function
3957/// - `x > 0`
3958pub fn gammaln(x: f64) -> f64 {
3959    let cof = vec![57.1562356658629235,-59.5979603554754912,
3960                   14.1360979747417471,-0.491913816097620199,0.339946499848118887e-4,
3961                   0.465236289270485756e-4,-0.983744753048795646e-4,0.158088703224912494e-3,
3962                   -0.210264441724104883e-3,0.217439618115212643e-3,-0.164318106536763890e-3,
3963                   0.844182239838527433e-4,-0.261908384015814087e-4,0.368991826595316234e-5];
3964
3965    if x <= 0.0 {
3966        println!("Bad argument in gammaln; returning f64::NAN");
3967        return f64::NAN;
3968        // panic!("bad ard in gammaln");
3969    }
3970
3971    let mut y= x;
3972    let z = x;
3973
3974    let mut tmp = z + 5.24218750000000000;
3975    tmp = (z + 0.5) * tmp.ln() - tmp;
3976    let mut ser = 0.999999999999997092;
3977    for j in 0..14 {
3978        ser += cof[j] / { y += 1.0; y};
3979    }
3980    return tmp + (2.5066282746310005 * ser / z).ln();
3981}
3982
3983
3984/// Gamma function
3985/// - `x > 0`
3986pub fn gamma(x: f64) -> f64 {
3987    return gammaln(x).exp();
3988}
3989
3990
3991/// Factorial (`i32`).
3992/// - `x = 1,2,3,...`
3993pub fn fact_i(x: i32) -> i32 {
3994    return if x > 1 {
3995        x * fact_i(x - 1)
3996    } else {
3997        1
3998    }
3999}
4000
4001
4002/// Log factorial (`i32`).
4003/// - `x = 1,2,3,...`
4004pub fn factln_i(x: i32) -> f64 {
4005    return if x > 1 {
4006        (x as f64).ln() + factln_i(x - 1)
4007    } else {
4008        0.0
4009    }
4010}
4011
4012
4013/// Generalized factorial (`f64`).
4014/// - `x > 0`
4015pub fn fact_f(x: f64) -> f64 {
4016    return if x > 1.0 {
4017        x * fact_f(x - 1.0)
4018    } else {
4019        x * gamma(x)
4020    }
4021}
4022
4023
4024/// Log Generalized factorial (`f64`).
4025/// - `x > 0`
4026pub fn factln_f(x: f64) -> f64 {
4027    return if x > 1.0 {
4028        x.ln() + fact_f(x - 1.0).ln()
4029    } else {
4030        x + gammaln(x)
4031    }
4032}
4033
4034
4035/// Combination
4036/// - `n = 0,1,2,...`
4037/// - `x = 0,1,2,...`
4038/// - `n >= x`
4039pub fn comb(n: i32, x: i32) -> f64 {
4040    return (0.5 + (factln_i(n) - factln_i(x) - factln_i(n-x)).exp()).floor();
4041}
4042
4043
4044/// Computes beta function.
4045/// - `a > 0`
4046/// - `b > 0`
4047pub fn beta_fn(a: f64, b:f64) -> f64 {
4048    return (gammaln(a) + gammaln(b) - gammaln(a+b)).exp();
4049}
4050
4051
4052/// Incomplete gamma function, series representation
4053pub fn gser(x: f64, a: f64) -> f64 {
4054    let imax = 100;
4055    let eps = 3.0e-7;
4056    // let fpmin = 1.0e-30;
4057    let gln = gammaln(a);
4058
4059    if x <= 0.0 {
4060        if x < 0.0 {
4061            println!("x less than 0 in routine gser");
4062        }
4063        return 0.0;
4064    }
4065    else {
4066        let mut ap = a;
4067        let mut del = 1.0 / a;
4068        let mut sum = 1.0 / a;
4069
4070        for _ in 1..imax {
4071            ap = ap + 1.0;
4072            del = del * x / ap;
4073            sum = sum + del;
4074            if del.abs() < sum.abs() * eps {
4075                return sum * (-x + a * x.ln() - gln).exp();
4076            }
4077        }
4078        println!("a too large, ITMAX too small in routine gser");
4079    }
4080    return 0.0;
4081}
4082
4083
4084/// Incomplete gamma function, continued fraction representation
4085pub fn gcf(x: f64, a: f64) -> f64 {
4086    let imax = 100;
4087    let eps = 3.0e-7;
4088    let fpmin = 1.0e-30;
4089
4090    let gln = gammaln(a);
4091    let mut b= x + 1.0 - a;
4092    let mut c = 1.0 / fpmin;
4093    let mut d= 1.0 / b;
4094    let mut h= d;
4095
4096    let mut an: f64;
4097    let mut del: f64;
4098
4099    for i in 1..=imax {
4100        an = -(i as f64) * (i as f64 - a);
4101        b += 2.0;
4102        d = an * d + b;
4103        if d.abs() < fpmin {
4104            d = fpmin;
4105        }
4106        c = b + an / c;
4107        if c.abs() < fpmin {
4108            c=fpmin;
4109        }
4110        d = 1.0 / d;
4111        del = d * c;
4112        h *= del;
4113        if (del-1.0).abs() < eps {
4114            break;
4115        }
4116    }
4117    // if (i > imax) {
4118    //     println!("a too large, ITMAX too small in gcf");
4119    // }
4120
4121    return (-x + a * x.ln() - gln).exp() * h;
4122}
4123
4124
4125/// Incomplete gamma function `P(x,a)`
4126pub fn gammp(x: f64, a: f64) -> f64 {
4127    if x < 0.0 || a <= 0.0 {
4128        println ! ("Invalid arguments in routine gammp");
4129    }
4130    return if x < (a + 1.0) {
4131        gser(x, a)
4132    } else {
4133        1.0 - gcf(x, a)
4134    }
4135}
4136
4137
4138/// Complmentary incomplete gamma function `Q(x,a)`
4139pub fn gammq(x: f64, a: f64) -> f64 {
4140    if x < 0.0 || a <= 0.0 {
4141        println!("Invalid arguments in routine gammq");
4142    }
4143    return if x == 0.0 {
4144        1.0
4145    } else if a >= 100.0 {
4146        gammapprox(x, a)
4147    } else if x < (a + 1.0) {
4148        1.0 - gser(x, a)
4149    } else {
4150        gcf(x, a)
4151    }
4152}
4153
4154
4155/// Incomplete gamma function, quadrature `P(x,a)`
4156pub fn gammapprox(x: f64, a: f64) -> f64 {
4157
4158    const Y_VEC: [f64; 18] = [
4159        0.0021695375159141994, 0.011413521097787704,0.027972308950302116,
4160        0.051727015600492421, 0.082502225484340941, 0.12007019910960293,
4161        0.16415283300752470, 0.21442376986779355, 0.27051082840644336,
4162        0.33199876341447887, 0.39843234186401943, 0.46931971407375483,
4163        0.54413605556657973, 0.62232745288031077, 0.70331500465597174,
4164        0.78649910768313447, 0.87126389619061517, 0.95698180152629142];
4165    const W_VEC: [f64; 18] = [
4166        0.0055657196642445571, 0.012915947284065419, 0.020181515297735382,
4167        0.027298621498568734, 0.034213810770299537,0.040875750923643261,
4168        0.047235083490265582, 0.053244713977759692,0.058860144245324798,
4169        0.064039797355015485, 0.068745323835736408,0.072941885005653087,
4170        0.076598410645870640, 0.079687828912071670,0.082187266704339706,
4171        0.084078218979661945, 0.085346685739338721,0.085983275670394821];
4172
4173    let (xu,mut t,mut sum,ans,a1,lna1,sqrta1): (f64,f64,f64,f64,f64,f64,f64);
4174    a1 = a-1.0;
4175    lna1 = a1.ln();
4176    sqrta1 = a1.sqrt();
4177    if x > a1 {
4178        xu = f64::max(a1 + 11.5*sqrta1, x + 6.0*sqrta1);
4179    }
4180    else {
4181        xu = f64::max(0.0,f64::min(a1 - 7.5*sqrta1, x - 5.0*sqrta1));
4182    }
4183    sum = 0.0;
4184    for j in 0..18 { //Gauss-Legendre.
4185        t = x + (xu-x)*Y_VEC[j];
4186        sum += W_VEC[j]*(-(t-a1)+a1*(t.ln()-lna1)).exp();
4187    }
4188    ans = sum*(xu-x)*(a1*(a1.ln()-1.0)-gammaln(a)).exp();
4189
4190    return if ans >= 0.0 {
4191        ans
4192    } else {
4193        1.0 + ans
4194    }
4195}
4196
4197
4198
4199/// Error function (gammp implementation) `Erf(x)`
4200pub fn erf2(x: f64) -> f64 {
4201    return if x < 0.0 {
4202        -gammp(x * x, 0.5)
4203    } else {
4204        gammp(x * x, 0.5)
4205    }
4206}
4207
4208
4209
4210/// Inverse of incomplete beta function
4211/// - `0 < p < 1`
4212/// - `alpha > 0`
4213/// - `beta > 0`
4214pub fn betai_inv(p: f64, a:f64, b: f64) -> f64 {
4215    let eps = 1.0e-8;
4216    let (pp,mut t,mut u,mut err,mut x,al,h,w,afac,a1,b1,lna,lnb):
4217        (f64,f64,f64,f64,f64,f64,f64,f64,f64,f64,f64,f64,f64);
4218    a1=a-1.0;
4219    b1=b-1.0;
4220
4221    if p <= 0.0 {
4222        return 0.;
4223    }
4224    else if p >= 1.0 {
4225        return 1.0;
4226    }
4227    else if a >= 1.0 && b >= 1.0 {
4228        if p < 0.5 {
4229            pp = p
4230        }
4231        else {
4232            pp = 1.0 - p;
4233        }
4234        t = (-2.0*pp.ln()).sqrt();
4235        x = (2.30753 + t*0.27061) / (1.0 + t*(0.99229 + t*0.04481)) - t;
4236        if p < 0.5 {
4237            x = -x;
4238        }
4239        al = (x.powi(2)-3.0)/6.0;
4240        h = 2.0 / (1.0/(2.0*a-1.0)+1.0/(2.0*b-1.0));
4241        w = (x*(al+h).sqrt()/h)-(1.0/(2.0*b-1.0)-1.0/(2.0*a-1.0))*(al+5.0/6.0-2.0/(3.0*h));
4242        x = a/(a+b*(2.0*w).exp());
4243    }
4244    else {
4245        lna = (a/(a+b)).ln();
4246        lnb = (b/(a+b)).ln();
4247        t = (a*lna).exp()/a;
4248        u = (b*lnb).exp()/b;
4249        w = t + u;
4250        if p < t/w  {
4251            x = (a*w*p).powf(1.0/a);
4252        }
4253        else {
4254            x = 1.0 - (b*w*(1.-p)).powf(1.0/b);
4255        }
4256    }
4257
4258    afac = -gammaln(a)-gammaln(b)+gammaln(a+b);
4259    for j in 0..10 {
4260        if x == 0.0 || x == 1.0 {
4261            return x;
4262        }
4263        err = betai(x, a, b) - p;
4264        t = (a1 * x.ln() + b1 * (1.0 - x).ln() + afac).exp();
4265        u = err / t;
4266        t = u / (1.0 - 0.5 * f64::min(1.0, u * (a1 / x - b1 / (1.0 - x))));
4267        x -= t;
4268        // x -= (t = u / (1. - 0.5 * MIN(1., u * (a1 / x - b1 / (1. - x)))));
4269        if x <= 0.0 {
4270            x = 0.5 * (x + t);
4271        }
4272        if x >= 1.0 {
4273            x = 0.5 * (x + t + 1.0);
4274        }
4275        if t.abs() < eps*x && j>0 {
4276            break;
4277        }
4278    }
4279
4280    return x;
4281}
4282
4283
4284
4285
4286/// Inverse of incomplete gamma function
4287/// - `0 < p < 1`
4288/// - `alpha > 0`
4289pub fn gammai_inv(p: f64, alpha:f64) -> f64 {
4290    let (mut x,mut err,mut t,mut u,pp,lna1,afac,a1): (f64,f64,f64,f64,f64,f64,f64,f64);
4291    a1 = alpha-1.0;
4292
4293    let eps = 1.0e-8; // Accuracy is the square of eps.
4294    let gln = gammaln(alpha);
4295
4296    if alpha <= 0.0 {
4297        println!("a must be pos in invgammap");
4298    }
4299    if p >= 1.0 {
4300        return f64::max(100.0,alpha + 100.0*alpha.sqrt());
4301    }
4302    if p <= 0.0 {
4303        return 0.0;
4304    }
4305    lna1 = a1.ln();
4306    afac = (a1*(lna1-1.0)-gln).exp();
4307    if alpha > 1.0 {
4308        if p < 0.5 {
4309            pp = p;
4310        }
4311        else {
4312            pp = 1.0 - p;
4313        }
4314        t = (-2.0*pp.ln()).sqrt();
4315        x = (2.30753+t*0.27061) /
4316            (1.0+t*(0.99229+t*0.04481)) - t;
4317        if p < 0.5 {
4318            x = -x;
4319        }
4320        x = f64::max(1.0e-3,alpha*(1.-1./(9.*alpha)-x/(3.*alpha.sqrt()).powi(3)));
4321    }
4322    else {
4323        t = 1.0 - alpha*(0.253+alpha*0.12);
4324        if p < t {
4325            x = (p/t).powf(1.0/alpha);
4326        }
4327        else {
4328            x = 1.0-(1.0-(p-t)/(1.0-t)).ln();
4329        }
4330    }
4331
4332    for _ in 0..12 {
4333        if x <= 0.0 {
4334            return 0.0;
4335        }
4336        err = gammp(x,alpha) - p;
4337        if alpha > 1.0 {
4338            t = afac*(-(x-a1)+a1*(x.ln()-lna1)).exp();
4339        }
4340        else {
4341            t = (-x+a1*x.ln()-gln).exp();
4342        }
4343        u = err/t;
4344        t = u/(1.0-0.5*f64::min(1.0,u*((alpha-1.0)/x - 1.0)));
4345        x -= t; //Halley’s method.
4346        if x <= 0.0 {
4347            x = 0.5*(x + t);
4348        } //Halve old value if x tries to go negative.
4349        if t.abs() < eps *x {
4350            break;
4351        }
4352    }
4353
4354    return x;
4355}
4356
4357
4358
4359
4360
4361/// Chebyshev coefficients
4362fn erfc_cheb(z: f64) -> f64 {
4363
4364    const NCOEF: usize = 28;
4365    const COEF: [f64; 28] = [
4366        -1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2, -9.561514786808631e-3,
4367        -9.46595344482036e-4, 3.66839497852761e-4, 4.2523324806907e-5, -2.0278578112534e-5,
4368        -1.624290004647e-6, 1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8,
4369        6.529054439e-9, 5.059343495e-9, -9.91364156e-10, -2.27365122e-10,
4370        9.6467911e-11, 2.394038e-12, -6.886027e-12, 8.94487e-13,
4371        3.13092e-13, -1.12708e-13, 3.81e-16, 7.106e-15,
4372        -1.523e-15, -9.4e-17, 1.21e-16,-2.8e-17 ];
4373
4374    let (mut d, mut dd, t, ty, mut tmp) : (f64, f64, f64, f64, f64);
4375    d = 0.0;
4376    dd = 0.0;
4377
4378    assert!(z >= 0f64, "erfccheb requires nonnegative argument");
4379    t = 2.0 / (2.0 + z);
4380    ty = 4.0 * t - 2.0;
4381    for j in (1..NCOEF-1).rev() {
4382        tmp = d;
4383        d = ty * d - dd + COEF[j];
4384        dd = tmp;
4385    }
4386    return t * (-z.powi(2) + 0.5 * (COEF[0] + ty * d) - dd).exp();
4387}
4388
4389
4390/// Error function (Chebyshev implementation)
4391pub fn erf(x: f64) -> f64 {
4392    return if x >= 0.0 {
4393        1.0 - erfc_cheb(x)
4394    } else {
4395        erfc_cheb(-x) - 1.0
4396    }
4397}
4398
4399/// Complementary error function
4400pub fn erfc(x: f64) -> f64 {
4401    return if x >= 0.0 {
4402        erfc_cheb(x)
4403    } else {
4404        2.0 - erfc_cheb(-x)
4405    }
4406}
4407
4408/// Inverse of complementary error function
4409pub fn erfc_inv(p: f64) -> f64 {
4410
4411    let (pp, t, mut x): (f64, f64, f64);
4412
4413    // Return arbitrary large pos or neg value
4414    if p >= 2.0 {
4415        return -100.0;
4416    }
4417    else if p <= 0.0 {
4418        return 100.0;
4419    }
4420
4421    if p < 1.0 {
4422        pp = p
4423    }
4424    else {
4425        pp = 2.0 - p;
4426    }
4427
4428    t = (-2.0 * (pp / 2.0).ln()).sqrt();
4429    x = -std::f64::consts::FRAC_1_SQRT_2 * ((2.30753 + t * 0.27061) /
4430        (1f64 + t * (0.99229 + t * 0.04481)) - t);
4431    for _ in 0..2 {
4432        let err = erfc(x) - pp;
4433        x += err / (std::f64::consts::FRAC_2_SQRT_PI * (-x.powi(2)).exp() - x * err);
4434    }
4435    return if p < 1.0 {
4436        x
4437    } else {
4438        -x
4439    }
4440}
4441
4442/// Inverse of error function
4443pub fn erf_inv(p: f64) -> f64 {
4444    return erfc_inv(1.0 - p);
4445}
4446
4447
4448
4449
4450
4451// const NN: usize = 10; // number of terms in the Chebyshev series
4452
4453
4454
4455
4456
4457
4458///////////////////////////////
4459// Depreciated root finder code
4460///////////////////////////////
4461// let f = |x| { beta_cdf(x,alpha,beta) - q };
4462// let eps = 1.0e-15;
4463// let mut convergency = SimpleConvergency { eps, max_iter:30 };
4464//
4465// let percentile = find_root_secant(0.8, 0.999, &f, &mut convergency);
4466//
4467// if q < 0.0 || q > 1.0 || alpha <= 0.0 || beta <= 0.0 || percentile.is_err() {
4468//     println!("Error in function gamma_percentile");
4469//     return f64::NAN;
4470// }
4471//
4472// return percentile.unwrap();
4473
4474
4475
4476#[cfg(test)]
4477mod tests {
4478    use super::*;
4479
4480
4481#[test]
4482    pub fn it_works() {
4483        // let result = add(2, 2);
4484        // assert_eq!(result, 4);
4485        println!("It works!!");
4486
4487        println!("\nBeta");
4488        println!("pdf: {}", beta_pdf(0.7,0.5,1.5));
4489        println!("cdf: {}", beta_cdf(0.7,0.5,1.5));
4490        println!("per: {}", beta_per(0.1,0.5,1.5));
4491        println!("ran: {}", beta_ran(0.5,1.5));
4492        println!("ran_vec: {:?}", beta_ranvec(3,0.5, 1.5));
4493        let mut mybeta = BetaDist{alpha:0.5, beta:1.5};
4494        println!("pdf: {}", mybeta.pdf(0.7));
4495        println!("cdf: {}", mybeta.cdf(0.7));
4496        println!("per: {}", mybeta.per(0.1));
4497        println!("ran: {}", mybeta.ran());
4498        println!("ranvec: {:?}", mybeta.ranvec(5));
4499        println!("mean: {}", mybeta.mean());
4500        println!("var: {}", mybeta.var());
4501        println!("sd: {}", mybeta.sd());
4502        println!("---------------------");
4503
4504        println!("\nChi-Square");
4505        println!("pdf: {}", chisq_pdf(0.7,1.5));
4506        println!("cdf: {}", chisq_cdf(0.7,1.5));
4507        println!("per: {}", chisq_per(0.1,1.5));
4508        println!("ran: {}", chisq_ran(1.5));
4509        println!("ran_vec: {:?}", chisq_ranvec(3,1.5));
4510        let mut mychisq = ChiSqDist{nu:1.5};
4511        println!("pdf: {}", mychisq.pdf(0.7));
4512        println!("cdf: {}", mychisq.cdf(0.7));
4513        println!("per: {}", mychisq.per(0.1));
4514        println!("ran: {}", mychisq.ran());
4515        println!("ranvec: {:?}", mychisq.ranvec(5));
4516        println!("mean: {}", mychisq.mean());
4517        println!("var: {}", mychisq.var());
4518        println!("sd: {}", mychisq.sd());
4519        println!("---------------------");
4520
4521        println!("\nExp");
4522        println!("pdf: {}", exp_pdf(0.7,1.5));
4523        println!("cdf: {}", exp_cdf(0.7,1.5));
4524        println!("per: {}", exp_per(0.1,1.5));
4525        println!("ran: {}", exp_ran(1.5));
4526        println!("ran_vec: {:?}", exp_ranvec(3,1.5));
4527        let mut myexp = ExpDist{lambda:1.5};
4528        println!("pdf: {}", myexp.pdf(0.7));
4529        println!("cdf: {}", myexp.cdf(0.7));
4530        println!("per: {}", myexp.per(0.1));
4531        println!("ran: {}", myexp.ran());
4532        println!("ranvec: {:?}", myexp.ranvec(5));
4533        println!("mean: {}", myexp.mean());
4534        println!("var: {}", myexp.var());
4535        println!("sd: {}", myexp.sd());
4536        println!("---------------------");
4537
4538        println!("\nF Dist");
4539        println!("pdf: {}", f_pdf(0.7,1.5, 4.5));
4540        println!("cdf: {}", f_cdf(0.7,1.5, 4.5));
4541        println!("per: {}", f_per(0.1,1.5, 4.5));
4542        println!("ran: {}", f_ran(1.5, 4.5));
4543        println!("ran_vec: {:?}", f_ranvec(3,1.5, 4.5));
4544        let mut mydist = FDist{nu1:1.5, nu2:4.5};
4545        println!("pdf: {}", mydist.pdf(0.7));
4546        println!("cdf: {}", mydist.cdf(0.7));
4547        println!("per: {}", mydist.per(0.1));
4548        println!("ran: {}", mydist.ran());
4549        println!("ranvec: {:?}", mydist.ranvec(5));
4550        println!("mean: {}", mydist.mean());
4551        println!("var: {}", mydist.var());
4552        println!("sd: {}", mydist.sd());
4553        println!("---------------------");
4554
4555        println!("\nGamma Dist");
4556        println!("pdf: {}", gamma_pdf(0.7,1.5, 4.5));
4557        println!("cdf: {}", gamma_cdf(0.7,1.5, 4.5));
4558        println!("per: {}", gamma_per(0.1,1.5, 4.5));
4559        println!("ran: {}", gamma_ran(1.5, 4.5));
4560        println!("ran_vec: {:?}", gamma_ranvec(3,1.5, 4.5));
4561        let mut mydist = GammaDist{alpha:1.5, beta:4.5};
4562        println!("pdf: {}", mydist.pdf(0.7));
4563        println!("cdf: {}", mydist.cdf(0.7));
4564        println!("per: {}", mydist.per(0.99));
4565        println!("ran: {}", mydist.ran());
4566        println!("ranvec: {:?}", mydist.ranvec(5));
4567        println!("mean: {}", mydist.mean());
4568        println!("var: {}", mydist.var());
4569        println!("sd: {}", mydist.sd());
4570        println!("---------------------");
4571
4572        println!("\nLog-Normal");
4573        println!("pdf: {}", lognormal_pdf(0.7,1.5, 4.5));
4574        println!("cdf: {}", lognormal_cdf(0.7,1.5, 4.5));
4575        println!("per: {}", lognormal_per(0.1,1.5, 4.5));
4576        println!("ran: {}", lognormal_ran(1.5, 4.5));
4577        println!("ran_vec: {:?}", lognormal_ranvec(3,1.5, 5.5));
4578        let mut mydist = LogNormalDist{mu:1.5, sigma:4.5};
4579        println!("pdf: {}", mydist.pdf(0.7));
4580        println!("cdf: {}", mydist.cdf(0.7));
4581        println!("per: {}", mydist.per(0.99));
4582        println!("ran: {}", mydist.ran());
4583        println!("ranvec: {:?}", mydist.ranvec(5));
4584        println!("mean: {}", mydist.mean());
4585        println!("var: {}", mydist.var());
4586        println!("sd: {}", mydist.sd());
4587        println!("---------------------");
4588
4589        println!("\nNormal");
4590        println!("pdf: {}", normal_pdf(0.7,1.5, 4.5));
4591        println!("cdf: {}", normal_cdf(0.7,1.5, 4.5));
4592        println!("per: {}", normal_per(0.1,1.5, 4.5));
4593        println!("ran: {}", normal_ran(1.5, 4.5));
4594        println!("ran_vec: {:?}", normal_ranvec(3,1.5, 4.5));
4595        let mut mydist = NormalDist{mu:1.5, sigma:4.5};
4596        println!("pdf: {}", mydist.pdf(0.7));
4597        println!("cdf: {}", mydist.cdf(0.7));
4598        println!("per: {}", mydist.per(0.99));
4599        println!("ran: {}", mydist.ran());
4600        println!("ranvec: {:?}", mydist.ranvec(5));
4601        println!("mean: {}", mydist.mean());
4602        println!("var: {}", mydist.var());
4603        println!("sd: {}", mydist.sd());
4604        println!("---------------------");
4605
4606        println!("\nt Dist");
4607        println!("pdf: {}", t_pdf(0.7,4.5));
4608        println!("cdf: {}", t_cdf(0.7,4.5));
4609        println!("per: {}", t_per(0.1,4.5));
4610        println!("ran: {}", t_ran(4.5));
4611        println!("ran_vec: {:?}", t_ranvec(3,4.5));
4612        let mut mydist = TDist{nu:4.5};
4613        println!("pdf: {}", mydist.pdf(0.7));
4614        println!("cdf: {}", mydist.cdf(0.7));
4615        println!("per: {}", mydist.per(0.99));
4616        println!("ran: {}", mydist.ran());
4617        println!("ranvec: {:?}", mydist.ranvec(5));
4618        println!("mean: {}", mydist.mean());
4619        println!("var: {}", mydist.var());
4620        println!("sd: {}", mydist.sd());
4621        println!("---------------------");
4622
4623        println!("\nUhif");
4624        println!("pdf: {}", unif_pdf(1.7,1.5, 4.5));
4625        println!("cdf: {}", unif_cdf(1.7,1.5, 4.5));
4626        println!("per: {}", unif_per(0.1,1.5, 4.5));
4627        println!("ran: {}", unif_ran(1.5, 4.5));
4628        println!("ran_vec: {:?}", unif_ranvec(3,1.5, 4.5));
4629        let mut mydist = UnifDist{a:1.5, b:4.5};
4630        println!("pdf: {}", mydist.pdf(0.7));
4631        println!("cdf: {}", mydist.cdf(0.7));
4632        println!("per: {}", mydist.per(0.99));
4633        println!("ran: {}", mydist.ran());
4634        println!("ranvec: {:?}", mydist.ranvec(5));
4635        println!("mean: {}", mydist.mean());
4636        println!("var: {}", mydist.var());
4637        println!("sd: {}", mydist.sd());
4638        println!("---------------------");
4639
4640        println!("\nBinomial");
4641        println!("bin_pmf: {}", bin_pmf(99,100,0.9));
4642        println!("bin_cdf: {}", bin_cdf(99,100,0.9));
4643        println!("bin_per: {}", bin_per(1.0,100,0.9));
4644        println!("bin_ran: {}", bin_ran(100,0.9));
4645        println!("ran_vec: {:?}", bin_ranvec(3,100, 0.9));
4646        let mut mybin = BinDist{n:100, p:0.9};
4647        println!("bin pmf: {}", mybin.pmf(80));
4648        println!("bin cdf: {}", mybin.cdf(80));
4649        println!("bin per: {}", mybin.per(0.99));
4650        println!("bin ran: {}", mybin.ran());
4651        println!("ranvec: {:?}", mybin.ranvec(5));
4652        println!("bin mean: {}", mybin.mean());
4653        println!("bin var: {}", mybin.var());
4654        println!("bin sd: {}", mybin.sd());
4655
4656        println!("\nGeo");
4657        println!("geo_pmf: {}", geo_pmf(0,0.05));
4658        println!("geo_cdf: {}", geo_cdf(0,0.05));
4659        println!("geo_per: {}", geo_per(1.0,0.05));
4660        println!("geo_ran: {}", geo_ran(0.05));
4661        println!("ran_vec: {:?}", geo_ranvec(3,0.05));
4662        let mut mygeo = GeoDist{p:0.05};
4663        println!("geo pmf: {}", mygeo.pmf(2));
4664        println!("geo cdf: {}", mygeo.cdf(2));
4665        println!("geo per: {}", mygeo.per(0.99));
4666        println!("geo ran: {}", mygeo.ran());
4667        println!("ranvec: {:?}", mygeo.ranvec(5));
4668        println!("geo mean: {}", mygeo.mean());
4669        println!("geo var: {}", mygeo.var());
4670        println!("geo sd: {}", mygeo.sd());
4671
4672
4673        println!("\nGeo2");
4674        println!("geo2_pmf: {}", geo2_pmf(1,0.05));
4675        println!("geo2_cdf: {}", geo2_cdf(1,0.05));
4676        println!("geo2_per: {}", geo2_per(0.99,0.05));
4677        println!("geo2_ran: {}", geo2_ran(0.05));
4678        println!("ran_vec: {:?}", geo2_ranvec(3,0.05));
4679        let mut mygeo2 = Geo2Dist{p:0.05};
4680        println!("geo2 pmf: {}", mygeo2.pmf(2));
4681        println!("geo2 cdf: {}", mygeo2.cdf(2));
4682        println!("geo2 per: {}", mygeo2.per(0.99));
4683        println!("geo2 ran: {}", mygeo2.ran());
4684        println!("ranvec: {:?}", mygeo2.ranvec(5));
4685        println!("geo2 mean: {}", mygeo2.mean());
4686        println!("geo2 var: {}", mygeo2.var());
4687        println!("geo2 sd: {}", mygeo2.sd());
4688
4689
4690        println!("\nHG");
4691        println!("hg_pmf: {}", hg_pmf(80,100,1000, 900));
4692        println!("hg_cdf: {}", hg_cdf(80,100,1000, 900));
4693        println!("hg_per: {}", hg_per(0.26,100,1000, 900));
4694        println!("hg_ran: {}", hg_ran(100,1000, 900));
4695        println!("ran_vec: {:?}", hg_ranvec(3,100, 1000, 900));
4696        let mut myhg = HGDist{n:100, N:1000, M:900};
4697        println!("hg pmf: {}", myhg.pmf(80));
4698        println!("hg cdf: {}", myhg.cdf(80));
4699        println!("hg per: {}", myhg.per(0.26));
4700        println!("hg ran: {}", myhg.ran());
4701        println!("ranvec: {:?}", myhg.ranvec(5));
4702        println!("hg mean: {}", myhg.mean());
4703        println!("hg var: {}", myhg.var());
4704        println!("hg sd: {}", myhg.sd());
4705
4706
4707        println!("\nNB");
4708        println!("NB_pmf: {}", nb_pmf(10,5, 0.1));
4709        println!("NB_cdf: {}", nb_cdf(10,5, 0.1));
4710        println!("NB_per: {}", nb_per(0.0,5, 0.1));
4711        println!("NB_ran: {}", nb_ran(5, 0.1));
4712        println!("ran_vec: {:?}", nb_ranvec(3,5, 0.1));
4713        let mut mynb = NBDist{r: 5, p:0.1};
4714        println!("NB pmf: {}", mynb.pmf(2));
4715        println!("NB cdf: {}", mynb.cdf(2));
4716        println!("NB per: {}", mynb.per(0.99));
4717        println!("NB ran: {}", mynb.ran());
4718        println!("ranvec: {:?}", mynb.ranvec(5));
4719        println!("NB mean: {}", mynb.mean());
4720        println!("NB var: {}", mynb.var());
4721        println!("NB sd: {}", mynb.sd());
4722
4723
4724        println!("\nNB2");
4725        println!("NB2_pmf: {}", nb2_pmf(10,5, 0.1));
4726        println!("NB2_cdf: {}", nb2_cdf(10,5, 0.1));
4727        println!("NB2_per: {}", nb2_per(1.0,5, 0.1));
4728        println!("NB2_ran: {}", nb2_ran(5, 0.1));
4729        println!("ran_vec: {:?}", nb2_ranvec(3,5, 0.1));
4730        let mut mynb2 = NB2Dist{r: 5, p:0.1};
4731        println!("NB2 pmf: {}", mynb2.pmf(2));
4732        println!("NB2 cdf: {}", mynb2.cdf(2));
4733        println!("NB2 per: {}", mynb2.per(0.99));
4734        println!("NB2 ran: {}", mynb2.ran());
4735        println!("ranvec: {:?}", mynb2.ranvec(5));
4736        println!("NB2 mean: {}", mynb2.mean());
4737        println!("NB2 var: {}", mynb2.var());
4738        println!("NB2 sd: {}", mynb2.sd());
4739
4740
4741        println!("\nPois");
4742        println!("pois_pmf: {}", pois_pmf(3,2.0));
4743        println!("pois_cdf: {}", pois_cdf(3,2.0));
4744        println!("pois_per: {}", pois_per(1.0,2.0));
4745        println!("pois_ran: {}", pois_ran(2.0));
4746        println!("ran_vec: {:?}", pois_ranvec(3,2.0));
4747        let mut mypois = PoisDist{lambda: 2.0};
4748        println!("pois pmf: {}", mypois.pmf(3));
4749        println!("pois cdf: {}", mypois.cdf(3));
4750        println!("pois per: {}", mypois.per(0.26));
4751        println!("pois ran: {}", mypois.ran());
4752        println!("ranvec: {:?}", mypois.ranvec(5));
4753        println!("pois mean: {}", mypois.mean());
4754        println!("pois var: {}", mypois.var());
4755        println!("pois sd: {}", mypois.sd());
4756
4757
4758        // use t_ran;
4759        // let mut vec = Vec::new();
4760        //
4761        // let iter: usize = 1000000;
4762        // for _ in 0..iter {
4763        //     vec.push(t_ran(3.0));
4764        // }
4765        //
4766        // let mut mean: f64 = vec.iter().sum();
4767        // mean = mean / (iter as f64);
4768        //
4769        // let mut var: f64 = vec.iter().map(|x| (x-mean).powi(2) ).sum();
4770        // var = var / ((iter - 1) as f64);
4771        //
4772        // println!("Mean: {}", mean);
4773        // println!("Var: {}", var);
4774
4775
4776        use crate::erf;
4777        println!("\nerf: {}", erf(1.0));
4778        use crate::erf2;
4779        println!("erf2: {}", erf2(1.0));
4780    }
4781}