Add rand_distr crate
The lib.rs file has been adjusted significantly; all other contents are copied from rand with minimal fixes.
This commit is contained in:
@@ -34,6 +34,7 @@ stdweb = ["rand_os/stdweb"]
|
||||
[workspace]
|
||||
members = [
|
||||
"rand_core",
|
||||
"rand_distr",
|
||||
"rand_jitter",
|
||||
"rand_os",
|
||||
"rand_isaac",
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.1.0] - ??
|
||||
Initial release.
|
||||
@@ -0,0 +1,12 @@
|
||||
Copyrights in the Rand project are retained by their contributors. No
|
||||
copyright assignment is required to contribute to the Rand project.
|
||||
|
||||
For full authorship information, see the version control history.
|
||||
|
||||
Except as otherwise noted (below and/or in individual files), Rand is
|
||||
licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
|
||||
<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
|
||||
|
||||
The Rand project includes code from the Rust project
|
||||
published under these same licenses.
|
||||
@@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "rand_distr"
|
||||
version = "0.1.0"
|
||||
authors = ["The Rand Project Developers"]
|
||||
license = "MIT/Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/rust-random/rand"
|
||||
documentation = "https://rust-random.github.io/rand/rand_distr/"
|
||||
homepage = "https://crates.io/crates/rand_distr"
|
||||
description = """
|
||||
Sampling from random number distributions
|
||||
"""
|
||||
keywords = ["random", "rng", "distribution", "probability"]
|
||||
categories = ["algorithms"]
|
||||
edition = "2018"
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "rust-random/rand" }
|
||||
appveyor = { repository = "rust-random/rand" }
|
||||
|
||||
[dependencies]
|
||||
rand = { path = "..", version = ">=0.5, <=0.7" }
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,25 @@
|
||||
Copyright 2018 Developers of the Rand project
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,41 @@
|
||||
# rand_distr
|
||||
|
||||
[](https://travis-ci.org/rust-random/rand)
|
||||
[](https://ci.appveyor.com/project/rust-random/rand)
|
||||
[](https://crates.io/crates/rand_distr)
|
||||
[[](https://rust-random.github.io/book/)
|
||||
[](https://rust-random.github.io/rand/rand_distr)
|
||||
[](https://docs.rs/rand_distr)
|
||||
[](https://github.com/rust-random/rand#rust-version-requirements)
|
||||
|
||||
Implements a full suite of random number distributions sampling routines.
|
||||
|
||||
This crate is a super-set of the [rand::distributions] module, including support
|
||||
for sampling from Beta, Cauchy, ChiSquared, Dirichlet, exponential, Fisher F,
|
||||
Gamma, Log-normal, Normal, Pareto, Poisson, StudentT, Triangular, Circle,
|
||||
Sphere and Weibull distributions.
|
||||
|
||||
It is worth mentioning the [statrs] crate which provides similar functionality
|
||||
along with various support functions, including PDF and CDF computation. In
|
||||
contrast, this `rand_distr` crate focusses on sampling from distributions.
|
||||
|
||||
Unlike most Rand crates, `rand_distr` does not currently support `no_std`.
|
||||
|
||||
Links:
|
||||
|
||||
- [API documentation (master)](https://rust-random.github.io/rand/rand_distr)
|
||||
- [API documentation (docs.rs)](https://docs.rs/rand_distr)
|
||||
- [Changelog](CHANGELOG.md)
|
||||
- [The Rand project](https://github.com/rust-random/rand)
|
||||
|
||||
|
||||
[statrs]: https://github.com/boxtown/statrs
|
||||
[rand::distributions]: https://rust-random.github.io/rand/rand/distributions/index.html
|
||||
|
||||
## License
|
||||
|
||||
`rand_distr` is distributed under the terms of both the MIT license and the
|
||||
Apache License (Version 2.0).
|
||||
|
||||
See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
|
||||
[COPYRIGHT](COPYRIGHT) for details.
|
||||
@@ -0,0 +1,190 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
// Copyright 2016-2017 The Rust Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The binomial distribution.
|
||||
|
||||
use rand::Rng;
|
||||
use crate::{Distribution, Cauchy};
|
||||
use crate::utils::log_gamma;
|
||||
|
||||
/// The binomial distribution `Binomial(n, p)`.
|
||||
///
|
||||
/// This distribution has density function:
|
||||
/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{Binomial, Distribution};
|
||||
///
|
||||
/// let bin = Binomial::new(20, 0.3);
|
||||
/// let v = bin.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a binomial distribution", v);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Binomial {
|
||||
/// Number of trials.
|
||||
n: u64,
|
||||
/// Probability of success.
|
||||
p: f64,
|
||||
}
|
||||
|
||||
impl Binomial {
|
||||
/// Construct a new `Binomial` with the given shape parameters `n` (number
|
||||
/// of trials) and `p` (probability of success).
|
||||
///
|
||||
/// Panics if `p < 0` or `p > 1`.
|
||||
pub fn new(n: u64, p: f64) -> Binomial {
|
||||
assert!(p >= 0.0, "Binomial::new called with p < 0");
|
||||
assert!(p <= 1.0, "Binomial::new called with p > 1");
|
||||
Binomial { n, p }
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<u64> for Binomial {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
|
||||
// Handle these values directly.
|
||||
if self.p == 0.0 {
|
||||
return 0;
|
||||
} else if self.p == 1.0 {
|
||||
return self.n;
|
||||
}
|
||||
|
||||
// binomial distribution is symmetrical with respect to p -> 1-p, k -> n-k
|
||||
// switch p so that it is less than 0.5 - this allows for lower expected values
|
||||
// we will just invert the result at the end
|
||||
let p = if self.p <= 0.5 {
|
||||
self.p
|
||||
} else {
|
||||
1.0 - self.p
|
||||
};
|
||||
|
||||
let result;
|
||||
|
||||
// For small n * min(p, 1 - p), the BINV algorithm based on the inverse
|
||||
// transformation of the binomial distribution is more efficient:
|
||||
//
|
||||
// Voratas Kachitvichyanukul and Bruce W. Schmeiser. 1988. Binomial
|
||||
// random variate generation. Commun. ACM 31, 2 (February 1988),
|
||||
// 216-222. http://dx.doi.org/10.1145/42372.42381
|
||||
if (self.n as f64) * p < 10. && self.n <= (::std::i32::MAX as u64) {
|
||||
let q = 1. - p;
|
||||
let s = p / q;
|
||||
let a = ((self.n + 1) as f64) * s;
|
||||
let mut r = q.powi(self.n as i32);
|
||||
let mut u: f64 = rng.gen();
|
||||
let mut x = 0;
|
||||
while u > r as f64 {
|
||||
u -= r;
|
||||
x += 1;
|
||||
r *= a / (x as f64) - s;
|
||||
}
|
||||
result = x;
|
||||
} else {
|
||||
// FIXME: Using the BTPE algorithm is probably faster.
|
||||
|
||||
// prepare some cached values
|
||||
let float_n = self.n as f64;
|
||||
let ln_fact_n = log_gamma(float_n + 1.0);
|
||||
let pc = 1.0 - p;
|
||||
let log_p = p.ln();
|
||||
let log_pc = pc.ln();
|
||||
let expected = self.n as f64 * p;
|
||||
let sq = (expected * (2.0 * pc)).sqrt();
|
||||
let mut lresult;
|
||||
|
||||
// we use the Cauchy distribution as the comparison distribution
|
||||
// f(x) ~ 1/(1+x^2)
|
||||
let cauchy = Cauchy::new(0.0, 1.0);
|
||||
loop {
|
||||
let mut comp_dev: f64;
|
||||
loop {
|
||||
// draw from the Cauchy distribution
|
||||
comp_dev = rng.sample(cauchy);
|
||||
// shift the peak of the comparison ditribution
|
||||
lresult = expected + sq * comp_dev;
|
||||
// repeat the drawing until we are in the range of possible values
|
||||
if lresult >= 0.0 && lresult < float_n + 1.0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// the result should be discrete
|
||||
lresult = lresult.floor();
|
||||
|
||||
let log_binomial_dist = ln_fact_n - log_gamma(lresult+1.0) -
|
||||
log_gamma(float_n - lresult + 1.0) + lresult*log_p + (float_n - lresult)*log_pc;
|
||||
// this is the binomial probability divided by the comparison probability
|
||||
// we will generate a uniform random value and if it is larger than this,
|
||||
// we interpret it as a value falling out of the distribution and repeat
|
||||
let comparison_coeff = (log_binomial_dist.exp() * sq) * (1.2 * (1.0 + comp_dev*comp_dev));
|
||||
|
||||
if comparison_coeff >= rng.gen() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = lresult as u64;
|
||||
}
|
||||
|
||||
// invert the result for p < 0.5
|
||||
if p != self.p {
|
||||
self.n - result
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::Rng;
|
||||
use crate::Distribution;
|
||||
use super::Binomial;
|
||||
|
||||
fn test_binomial_mean_and_variance<R: Rng>(n: u64, p: f64, rng: &mut R) {
|
||||
let binomial = Binomial::new(n, p);
|
||||
|
||||
let expected_mean = n as f64 * p;
|
||||
let expected_variance = n as f64 * p * (1.0 - p);
|
||||
|
||||
let mut results = [0.0; 1000];
|
||||
for i in results.iter_mut() { *i = binomial.sample(rng) as f64; }
|
||||
|
||||
let mean = results.iter().sum::<f64>() / results.len() as f64;
|
||||
assert!((mean as f64 - expected_mean).abs() < expected_mean / 50.0);
|
||||
|
||||
let variance =
|
||||
results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>()
|
||||
/ results.len() as f64;
|
||||
assert!((variance - expected_variance).abs() < expected_variance / 10.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_binomial() {
|
||||
let mut rng = crate::test::rng(351);
|
||||
test_binomial_mean_and_variance(150, 0.1, &mut rng);
|
||||
test_binomial_mean_and_variance(70, 0.6, &mut rng);
|
||||
test_binomial_mean_and_variance(40, 0.5, &mut rng);
|
||||
test_binomial_mean_and_variance(20, 0.7, &mut rng);
|
||||
test_binomial_mean_and_variance(20, 0.5, &mut rng);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_binomial_end_points() {
|
||||
let mut rng = crate::test::rng(352);
|
||||
assert_eq!(rng.sample(Binomial::new(20, 0.0)), 0);
|
||||
assert_eq!(rng.sample(Binomial::new(20, 1.0)), 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_binomial_invalid_lambda_neg() {
|
||||
Binomial::new(20, -10.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
// Copyright 2016-2017 The Rust Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The Cauchy distribution.
|
||||
|
||||
use rand::Rng;
|
||||
use crate::Distribution;
|
||||
use std::f64::consts::PI;
|
||||
|
||||
/// The Cauchy distribution `Cauchy(median, scale)`.
|
||||
///
|
||||
/// This distribution has a density function:
|
||||
/// `f(x) = 1 / (pi * scale * (1 + ((x - median) / scale)^2))`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{Cauchy, Distribution};
|
||||
///
|
||||
/// let cau = Cauchy::new(2.0, 5.0);
|
||||
/// let v = cau.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a Cauchy(2, 5) distribution", v);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Cauchy {
|
||||
median: f64,
|
||||
scale: f64
|
||||
}
|
||||
|
||||
impl Cauchy {
|
||||
/// Construct a new `Cauchy` with the given shape parameters
|
||||
/// `median` the peak location and `scale` the scale factor.
|
||||
/// Panics if `scale <= 0`.
|
||||
pub fn new(median: f64, scale: f64) -> Cauchy {
|
||||
assert!(scale > 0.0, "Cauchy::new called with scale factor <= 0");
|
||||
Cauchy {
|
||||
median,
|
||||
scale
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<f64> for Cauchy {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
// sample from [0, 1)
|
||||
let x = rng.gen::<f64>();
|
||||
// get standard cauchy random number
|
||||
// note that π/2 is not exactly representable, even if x=0.5 the result is finite
|
||||
let comp_dev = (PI * x).tan();
|
||||
// shift and scale according to parameters
|
||||
let result = self.median + self.scale * comp_dev;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::Distribution;
|
||||
use super::Cauchy;
|
||||
|
||||
fn median(mut numbers: &mut [f64]) -> f64 {
|
||||
sort(&mut numbers);
|
||||
let mid = numbers.len() / 2;
|
||||
numbers[mid]
|
||||
}
|
||||
|
||||
fn sort(numbers: &mut [f64]) {
|
||||
numbers.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cauchy_median() {
|
||||
let cauchy = Cauchy::new(10.0, 5.0);
|
||||
let mut rng = crate::test::rng(123);
|
||||
let mut numbers: [f64; 1000] = [0.0; 1000];
|
||||
for i in 0..1000 {
|
||||
numbers[i] = cauchy.sample(&mut rng);
|
||||
}
|
||||
let median = median(&mut numbers);
|
||||
println!("Cauchy median: {}", median);
|
||||
assert!((median - 10.0).abs() < 0.5); // not 100% certain, but probable enough
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cauchy_mean() {
|
||||
let cauchy = Cauchy::new(10.0, 5.0);
|
||||
let mut rng = crate::test::rng(123);
|
||||
let mut sum = 0.0;
|
||||
for _ in 0..1000 {
|
||||
sum += cauchy.sample(&mut rng);
|
||||
}
|
||||
let mean = sum / 1000.0;
|
||||
println!("Cauchy mean: {}", mean);
|
||||
// for a Cauchy distribution the mean should not converge
|
||||
assert!((mean - 10.0).abs() > 0.5); // not 100% certain, but probable enough
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_cauchy_invalid_scale_zero() {
|
||||
Cauchy::new(0.0, 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_cauchy_invalid_scale_neg() {
|
||||
Cauchy::new(0.0, -10.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
// Copyright 2013 The Rust Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The dirichlet distribution.
|
||||
|
||||
use rand::Rng;
|
||||
use crate::Distribution;
|
||||
use crate::gamma::Gamma;
|
||||
|
||||
/// The dirichelet distribution `Dirichlet(alpha)`.
|
||||
///
|
||||
/// The Dirichlet distribution is a family of continuous multivariate
|
||||
/// probability distributions parameterized by a vector alpha of positive reals.
|
||||
/// It is a multivariate generalization of the beta distribution.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand::prelude::*;
|
||||
/// use rand_distr::Dirichlet;
|
||||
///
|
||||
/// let dirichlet = Dirichlet::new(vec![1.0, 2.0, 3.0]);
|
||||
/// let samples = dirichlet.sample(&mut rand::thread_rng());
|
||||
/// println!("{:?} is from a Dirichlet([1.0, 2.0, 3.0]) distribution", samples);
|
||||
/// ```
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Dirichlet {
|
||||
/// Concentration parameters (alpha)
|
||||
alpha: Vec<f64>,
|
||||
}
|
||||
|
||||
impl Dirichlet {
|
||||
/// Construct a new `Dirichlet` with the given alpha parameter `alpha`.
|
||||
///
|
||||
/// # Panics
|
||||
/// - if `alpha.len() < 2`
|
||||
///
|
||||
#[inline]
|
||||
pub fn new<V: Into<Vec<f64>>>(alpha: V) -> Dirichlet {
|
||||
let a = alpha.into();
|
||||
assert!(a.len() > 1);
|
||||
for i in 0..a.len() {
|
||||
assert!(a[i] > 0.0);
|
||||
}
|
||||
|
||||
Dirichlet { alpha: a }
|
||||
}
|
||||
|
||||
/// Construct a new `Dirichlet` with the given shape parameter `alpha` and `size`.
|
||||
///
|
||||
/// # Panics
|
||||
/// - if `alpha <= 0.0`
|
||||
/// - if `size < 2`
|
||||
///
|
||||
#[inline]
|
||||
pub fn new_with_param(alpha: f64, size: usize) -> Dirichlet {
|
||||
assert!(alpha > 0.0);
|
||||
assert!(size > 1);
|
||||
Dirichlet {
|
||||
alpha: vec![alpha; size],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<Vec<f64>> for Dirichlet {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec<f64> {
|
||||
let n = self.alpha.len();
|
||||
let mut samples = vec![0.0f64; n];
|
||||
let mut sum = 0.0f64;
|
||||
|
||||
for i in 0..n {
|
||||
let g = Gamma::new(self.alpha[i], 1.0);
|
||||
samples[i] = g.sample(rng);
|
||||
sum += samples[i];
|
||||
}
|
||||
let invacc = 1.0 / sum;
|
||||
for i in 0..n {
|
||||
samples[i] *= invacc;
|
||||
}
|
||||
samples
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Dirichlet;
|
||||
use crate::Distribution;
|
||||
|
||||
#[test]
|
||||
fn test_dirichlet() {
|
||||
let d = Dirichlet::new(vec![1.0, 2.0, 3.0]);
|
||||
let mut rng = crate::test::rng(221);
|
||||
let samples = d.sample(&mut rng);
|
||||
let _: Vec<f64> = samples
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
assert!(x > 0.0);
|
||||
x
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dirichlet_with_param() {
|
||||
let alpha = 0.5f64;
|
||||
let size = 2;
|
||||
let d = Dirichlet::new_with_param(alpha, size);
|
||||
let mut rng = crate::test::rng(221);
|
||||
let samples = d.sample(&mut rng);
|
||||
let _: Vec<f64> = samples
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
assert!(x > 0.0);
|
||||
x
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_dirichlet_invalid_length() {
|
||||
Dirichlet::new_with_param(0.5f64, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_dirichlet_invalid_alpha() {
|
||||
Dirichlet::new_with_param(0.0f64, 2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
// Copyright 2013 The Rust Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The exponential distribution.
|
||||
|
||||
use rand::Rng;
|
||||
use crate::{ziggurat_tables, Distribution};
|
||||
use crate::utils::ziggurat;
|
||||
|
||||
/// Samples floating-point numbers according to the exponential distribution,
|
||||
/// with rate parameter `λ = 1`. This is equivalent to `Exp::new(1.0)` or
|
||||
/// sampling with `-rng.gen::<f64>().ln()`, but faster.
|
||||
///
|
||||
/// See `Exp` for the general exponential distribution.
|
||||
///
|
||||
/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method. The exact
|
||||
/// description in the paper was adjusted to use tables for the exponential
|
||||
/// distribution rather than normal.
|
||||
///
|
||||
/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
|
||||
/// Generate Normal Random Samples*](
|
||||
/// https://www.doornik.com/research/ziggurat.pdf).
|
||||
/// Nuffield College, Oxford
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use rand::prelude::*;
|
||||
/// use rand_distr::Exp1;
|
||||
///
|
||||
/// let val: f64 = SmallRng::from_entropy().sample(Exp1);
|
||||
/// println!("{}", val);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Exp1;
|
||||
|
||||
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
|
||||
impl Distribution<f64> for Exp1 {
|
||||
#[inline]
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
#[inline]
|
||||
fn pdf(x: f64) -> f64 {
|
||||
(-x).exp()
|
||||
}
|
||||
#[inline]
|
||||
fn zero_case<R: Rng + ?Sized>(rng: &mut R, _u: f64) -> f64 {
|
||||
ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
|
||||
}
|
||||
|
||||
ziggurat(rng, false,
|
||||
&ziggurat_tables::ZIG_EXP_X,
|
||||
&ziggurat_tables::ZIG_EXP_F,
|
||||
pdf, zero_case)
|
||||
}
|
||||
}
|
||||
|
||||
/// The exponential distribution `Exp(lambda)`.
|
||||
///
|
||||
/// This distribution has density function: `f(x) = lambda * exp(-lambda * x)`
|
||||
/// for `x > 0`.
|
||||
///
|
||||
/// Note that [`Exp1`][crate::Exp1] is an optimised implementation for `lambda = 1`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{Exp, Distribution};
|
||||
///
|
||||
/// let exp = Exp::new(2.0);
|
||||
/// let v = exp.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a Exp(2) distribution", v);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Exp {
|
||||
/// `lambda` stored as `1/lambda`, since this is what we scale by.
|
||||
lambda_inverse: f64
|
||||
}
|
||||
|
||||
impl Exp {
|
||||
/// Construct a new `Exp` with the given shape parameter
|
||||
/// `lambda`. Panics if `lambda <= 0`.
|
||||
#[inline]
|
||||
pub fn new(lambda: f64) -> Exp {
|
||||
assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0");
|
||||
Exp { lambda_inverse: 1.0 / lambda }
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<f64> for Exp {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
let n: f64 = rng.sample(Exp1);
|
||||
n * self.lambda_inverse
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::Distribution;
|
||||
use super::Exp;
|
||||
|
||||
#[test]
|
||||
fn test_exp() {
|
||||
let exp = Exp::new(10.0);
|
||||
let mut rng = crate::test::rng(221);
|
||||
for _ in 0..1000 {
|
||||
assert!(exp.sample(&mut rng) >= 0.0);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_exp_invalid_lambda_zero() {
|
||||
Exp::new(0.0);
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_exp_invalid_lambda_neg() {
|
||||
Exp::new(-10.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,413 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
// Copyright 2013 The Rust Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The Gamma and derived distributions.
|
||||
|
||||
use self::GammaRepr::*;
|
||||
use self::ChiSquaredRepr::*;
|
||||
|
||||
use rand::Rng;
|
||||
use crate::normal::StandardNormal;
|
||||
use crate::{Distribution, Exp, Open01};
|
||||
|
||||
/// The Gamma distribution `Gamma(shape, scale)` distribution.
|
||||
///
|
||||
/// The density function of this distribution is
|
||||
///
|
||||
/// ```text
|
||||
/// f(x) = x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
|
||||
/// ```
|
||||
///
|
||||
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
|
||||
/// scale and both `k` and `θ` are strictly positive.
|
||||
///
|
||||
/// The algorithm used is that described by Marsaglia & Tsang 2000[^1],
|
||||
/// falling back to directly sampling from an Exponential for `shape
|
||||
/// == 1`, and using the boosting technique described in that paper for
|
||||
/// `shape < 1`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{Distribution, Gamma};
|
||||
///
|
||||
/// let gamma = Gamma::new(2.0, 5.0);
|
||||
/// let v = gamma.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a Gamma(2, 5) distribution", v);
|
||||
/// ```
|
||||
///
|
||||
/// [^1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method for
|
||||
/// Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
|
||||
/// (September 2000), 363-372.
|
||||
/// DOI:[10.1145/358407.358414](https://doi.acm.org/10.1145/358407.358414)
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Gamma {
|
||||
repr: GammaRepr,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum GammaRepr {
|
||||
Large(GammaLargeShape),
|
||||
One(Exp),
|
||||
Small(GammaSmallShape)
|
||||
}
|
||||
|
||||
// These two helpers could be made public, but saving the
|
||||
// match-on-Gamma-enum branch from using them directly (e.g. if one
|
||||
// knows that the shape is always > 1) doesn't appear to be much
|
||||
// faster.
|
||||
|
||||
/// Gamma distribution where the shape parameter is less than 1.
|
||||
///
|
||||
/// Note, samples from this require a compulsory floating-point `pow`
|
||||
/// call, which makes it significantly slower than sampling from a
|
||||
/// gamma distribution where the shape parameter is greater than or
|
||||
/// equal to 1.
|
||||
///
|
||||
/// See `Gamma` for sampling from a Gamma distribution with general
|
||||
/// shape parameters.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct GammaSmallShape {
|
||||
inv_shape: f64,
|
||||
large_shape: GammaLargeShape
|
||||
}
|
||||
|
||||
/// Gamma distribution where the shape parameter is larger than 1.
|
||||
///
|
||||
/// See `Gamma` for sampling from a Gamma distribution with general
|
||||
/// shape parameters.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct GammaLargeShape {
|
||||
scale: f64,
|
||||
c: f64,
|
||||
d: f64
|
||||
}
|
||||
|
||||
impl Gamma {
|
||||
/// Construct an object representing the `Gamma(shape, scale)`
|
||||
/// distribution.
|
||||
///
|
||||
/// Panics if `shape <= 0` or `scale <= 0`.
|
||||
#[inline]
|
||||
pub fn new(shape: f64, scale: f64) -> Gamma {
|
||||
assert!(shape > 0.0, "Gamma::new called with shape <= 0");
|
||||
assert!(scale > 0.0, "Gamma::new called with scale <= 0");
|
||||
|
||||
let repr = if shape == 1.0 {
|
||||
One(Exp::new(1.0 / scale))
|
||||
} else if shape < 1.0 {
|
||||
Small(GammaSmallShape::new_raw(shape, scale))
|
||||
} else {
|
||||
Large(GammaLargeShape::new_raw(shape, scale))
|
||||
};
|
||||
Gamma { repr }
|
||||
}
|
||||
}
|
||||
|
||||
impl GammaSmallShape {
|
||||
fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
|
||||
GammaSmallShape {
|
||||
inv_shape: 1. / shape,
|
||||
large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GammaLargeShape {
|
||||
fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
|
||||
let d = shape - 1. / 3.;
|
||||
GammaLargeShape {
|
||||
scale,
|
||||
c: 1. / (9. * d).sqrt(),
|
||||
d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<f64> for Gamma {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
match self.repr {
|
||||
Small(ref g) => g.sample(rng),
|
||||
One(ref g) => g.sample(rng),
|
||||
Large(ref g) => g.sample(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Distribution<f64> for GammaSmallShape {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
let u: f64 = rng.sample(Open01);
|
||||
|
||||
self.large_shape.sample(rng) * u.powf(self.inv_shape)
|
||||
}
|
||||
}
|
||||
impl Distribution<f64> for GammaLargeShape {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
loop {
|
||||
let x = rng.sample(StandardNormal);
|
||||
let v_cbrt = 1.0 + self.c * x;
|
||||
if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
|
||||
continue
|
||||
}
|
||||
|
||||
let v = v_cbrt * v_cbrt * v_cbrt;
|
||||
let u: f64 = rng.sample(Open01);
|
||||
|
||||
let x_sqr = x * x;
|
||||
if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
|
||||
u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) {
|
||||
return self.d * v * self.scale
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
|
||||
/// freedom.
|
||||
///
|
||||
/// For `k > 0` integral, this distribution is the sum of the squares
|
||||
/// of `k` independent standard normal random variables. For other
|
||||
/// `k`, this uses the equivalent characterisation
|
||||
/// `χ²(k) = Gamma(k/2, 2)`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{ChiSquared, Distribution};
|
||||
///
|
||||
/// let chi = ChiSquared::new(11.0);
|
||||
/// let v = chi.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a χ²(11) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ChiSquared {
|
||||
repr: ChiSquaredRepr,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum ChiSquaredRepr {
|
||||
// k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
|
||||
// e.g. when alpha = 1/2 as it would be for this case, so special-
|
||||
// casing and using the definition of N(0,1)^2 is faster.
|
||||
DoFExactlyOne,
|
||||
DoFAnythingElse(Gamma),
|
||||
}
|
||||
|
||||
impl ChiSquared {
|
||||
/// Create a new chi-squared distribution with degrees-of-freedom
|
||||
/// `k`. Panics if `k < 0`.
|
||||
pub fn new(k: f64) -> ChiSquared {
|
||||
let repr = if k == 1.0 {
|
||||
DoFExactlyOne
|
||||
} else {
|
||||
assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
|
||||
DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
|
||||
};
|
||||
ChiSquared { repr }
|
||||
}
|
||||
}
|
||||
impl Distribution<f64> for ChiSquared {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
match self.repr {
|
||||
DoFExactlyOne => {
|
||||
// k == 1 => N(0,1)^2
|
||||
let norm = rng.sample(StandardNormal);
|
||||
norm * norm
|
||||
}
|
||||
DoFAnythingElse(ref g) => g.sample(rng)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The Fisher F distribution `F(m, n)`.
|
||||
///
|
||||
/// This distribution is equivalent to the ratio of two normalised
|
||||
/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
|
||||
/// (χ²(n)/n)`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{FisherF, Distribution};
|
||||
///
|
||||
/// let f = FisherF::new(2.0, 32.0);
|
||||
/// let v = f.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from an F(2, 32) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct FisherF {
|
||||
numer: ChiSquared,
|
||||
denom: ChiSquared,
|
||||
// denom_dof / numer_dof so that this can just be a straight
|
||||
// multiplication, rather than a division.
|
||||
dof_ratio: f64,
|
||||
}
|
||||
|
||||
impl FisherF {
|
||||
/// Create a new `FisherF` distribution, with the given
|
||||
/// parameter. Panics if either `m` or `n` are not positive.
|
||||
pub fn new(m: f64, n: f64) -> FisherF {
|
||||
assert!(m > 0.0, "FisherF::new called with `m < 0`");
|
||||
assert!(n > 0.0, "FisherF::new called with `n < 0`");
|
||||
|
||||
FisherF {
|
||||
numer: ChiSquared::new(m),
|
||||
denom: ChiSquared::new(n),
|
||||
dof_ratio: n / m
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Distribution<f64> for FisherF {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
self.numer.sample(rng) / self.denom.sample(rng) * self.dof_ratio
|
||||
}
|
||||
}
|
||||
|
||||
/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
|
||||
/// freedom.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{StudentT, Distribution};
|
||||
///
|
||||
/// let t = StudentT::new(11.0);
|
||||
/// let v = t.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a t(11) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StudentT {
|
||||
chi: ChiSquared,
|
||||
dof: f64
|
||||
}
|
||||
|
||||
impl StudentT {
|
||||
/// Create a new Student t distribution with `n` degrees of
|
||||
/// freedom. Panics if `n <= 0`.
|
||||
pub fn new(n: f64) -> StudentT {
|
||||
assert!(n > 0.0, "StudentT::new called with `n <= 0`");
|
||||
StudentT {
|
||||
chi: ChiSquared::new(n),
|
||||
dof: n
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Distribution<f64> for StudentT {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
let norm = rng.sample(StandardNormal);
|
||||
norm * (self.dof / self.chi.sample(rng)).sqrt()
|
||||
}
|
||||
}
|
||||
|
||||
/// The Beta distribution with shape parameters `alpha` and `beta`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{Distribution, Beta};
|
||||
///
|
||||
/// let beta = Beta::new(2.0, 5.0);
|
||||
/// let v = beta.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a Beta(2, 5) distribution", v);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Beta {
|
||||
gamma_a: Gamma,
|
||||
gamma_b: Gamma,
|
||||
}
|
||||
|
||||
impl Beta {
|
||||
/// Construct an object representing the `Beta(alpha, beta)`
|
||||
/// distribution.
|
||||
///
|
||||
/// Panics if `shape <= 0` or `scale <= 0`.
|
||||
pub fn new(alpha: f64, beta: f64) -> Beta {
|
||||
assert!((alpha > 0.) & (beta > 0.));
|
||||
Beta {
|
||||
gamma_a: Gamma::new(alpha, 1.),
|
||||
gamma_b: Gamma::new(beta, 1.),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<f64> for Beta {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
let x = self.gamma_a.sample(rng);
|
||||
let y = self.gamma_b.sample(rng);
|
||||
x / (x + y)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::Distribution;
|
||||
use super::{Beta, ChiSquared, StudentT, FisherF};
|
||||
|
||||
#[test]
|
||||
fn test_chi_squared_one() {
|
||||
let chi = ChiSquared::new(1.0);
|
||||
let mut rng = crate::test::rng(201);
|
||||
for _ in 0..1000 {
|
||||
chi.sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_chi_squared_small() {
|
||||
let chi = ChiSquared::new(0.5);
|
||||
let mut rng = crate::test::rng(202);
|
||||
for _ in 0..1000 {
|
||||
chi.sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_chi_squared_large() {
|
||||
let chi = ChiSquared::new(30.0);
|
||||
let mut rng = crate::test::rng(203);
|
||||
for _ in 0..1000 {
|
||||
chi.sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_chi_squared_invalid_dof() {
|
||||
ChiSquared::new(-1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f() {
|
||||
let f = FisherF::new(2.0, 32.0);
|
||||
let mut rng = crate::test::rng(204);
|
||||
for _ in 0..1000 {
|
||||
f.sample(&mut rng);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_t() {
|
||||
let t = StudentT::new(11.0);
|
||||
let mut rng = crate::test::rng(205);
|
||||
for _ in 0..1000 {
|
||||
t.sample(&mut rng);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_beta() {
|
||||
let beta = Beta::new(1.0, 2.0);
|
||||
let mut rng = crate::test::rng(201);
|
||||
for _ in 0..1000 {
|
||||
beta.sample(&mut rng);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_beta_invalid_dof() {
|
||||
Beta::new(0., 0.);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright 2019 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
|
||||
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://rust-random.github.io/rand/")]
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(missing_debug_implementations)]
|
||||
|
||||
//! Generating random samples from probability distributions.
|
||||
//!
|
||||
//! ## Re-exports
|
||||
//!
|
||||
//! This crate is a super-set of the [`rand::distributions`] module. See the
|
||||
//! [`rand::distributions`] module documentation for an overview of the core
|
||||
//! [`Distribution`] trait and implementations.
|
||||
//!
|
||||
//! The following are re-exported:
|
||||
//!
|
||||
//! - The [`Distribution`] trait and [`DistIter`] helper type
|
||||
//! - The [`Standard`], [`Alphanumeric`], [`Uniform`], [`OpenClosed01`], [`Open01`] and [`Bernoulli`] distributions
|
||||
//! - The [`weighted`] sub-module
|
||||
//!
|
||||
//! ## Distributions
|
||||
//!
|
||||
//! This crate provides the following probability distributions:
|
||||
//!
|
||||
//! - Related to real-valued quantities that grow linearly
|
||||
//! (e.g. errors, offsets):
|
||||
//! - [`Normal`] distribution, and [`StandardNormal`] as a primitive
|
||||
//! - [`Cauchy`] distribution
|
||||
//! - Related to Bernoulli trials (yes/no events, with a given probability):
|
||||
//! - [`Binomial`] distribution
|
||||
//! - Related to positive real-valued quantities that grow exponentially
|
||||
//! (e.g. prices, incomes, populations):
|
||||
//! - [`LogNormal`] distribution
|
||||
//! - Related to the occurrence of independent events at a given rate:
|
||||
//! - [`Pareto`] distribution
|
||||
//! - [`Poisson`] distribution
|
||||
//! - [`Exp`]onential distribution, and [`Exp1`] as a primitive
|
||||
//! - [`Weibull`] distribution
|
||||
//! - Gamma and derived distributions:
|
||||
//! - [`Gamma`] distribution
|
||||
//! - [`ChiSquared`] distribution
|
||||
//! - [`StudentT`] distribution
|
||||
//! - [`FisherF`] distribution
|
||||
//! - Triangular distribution:
|
||||
//! - [`Beta`] distribution
|
||||
//! - [`Triangular`] distribution
|
||||
//! - Multivariate probability distributions
|
||||
//! - [`Dirichlet`] distribution
|
||||
//! - [`UnitSphereSurface`] distribution
|
||||
//! - [`UnitCircle`] distribution
|
||||
|
||||
pub use rand::distributions::{Distribution, DistIter, Standard,
|
||||
Alphanumeric, Uniform, OpenClosed01, Open01, Bernoulli, weighted};
|
||||
|
||||
pub use self::unit_sphere::UnitSphereSurface;
|
||||
pub use self::unit_circle::UnitCircle;
|
||||
pub use self::gamma::{Gamma, ChiSquared, FisherF,
|
||||
StudentT, Beta};
|
||||
pub use self::normal::{Normal, LogNormal, StandardNormal};
|
||||
pub use self::exponential::{Exp, Exp1};
|
||||
pub use self::pareto::Pareto;
|
||||
pub use self::poisson::Poisson;
|
||||
pub use self::binomial::Binomial;
|
||||
pub use self::cauchy::Cauchy;
|
||||
pub use self::dirichlet::Dirichlet;
|
||||
pub use self::triangular::Triangular;
|
||||
pub use self::weibull::Weibull;
|
||||
|
||||
mod unit_sphere;
|
||||
mod unit_circle;
|
||||
mod gamma;
|
||||
mod normal;
|
||||
mod exponential;
|
||||
mod pareto;
|
||||
mod poisson;
|
||||
mod binomial;
|
||||
mod cauchy;
|
||||
mod dirichlet;
|
||||
mod triangular;
|
||||
mod weibull;
|
||||
mod utils;
|
||||
mod ziggurat_tables;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::{RngCore, SeedableRng, rngs::StdRng};
|
||||
|
||||
pub fn rng(seed: u64) -> impl RngCore {
|
||||
StdRng::seed_from_u64(seed)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
// Copyright 2013 The Rust Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The normal and derived distributions.
|
||||
|
||||
use rand::Rng;
|
||||
use crate::{ziggurat_tables, Distribution, Open01};
|
||||
use crate::utils::ziggurat;
|
||||
|
||||
/// Samples floating-point numbers according to the normal distribution
|
||||
/// `N(0, 1)` (a.k.a. a standard normal, or Gaussian). This is equivalent to
|
||||
/// `Normal::new(0.0, 1.0)` but faster.
|
||||
///
|
||||
/// See `Normal` for the general normal distribution.
|
||||
///
|
||||
/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method.
|
||||
///
|
||||
/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
|
||||
/// Generate Normal Random Samples*](
|
||||
/// https://www.doornik.com/research/ziggurat.pdf).
|
||||
/// Nuffield College, Oxford
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use rand::prelude::*;
|
||||
/// use rand_distr::StandardNormal;
|
||||
///
|
||||
/// let val: f64 = SmallRng::from_entropy().sample(StandardNormal);
|
||||
/// println!("{}", val);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StandardNormal;
|
||||
|
||||
impl Distribution<f64> for StandardNormal {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
#[inline]
|
||||
fn pdf(x: f64) -> f64 {
|
||||
(-x*x/2.0).exp()
|
||||
}
|
||||
#[inline]
|
||||
fn zero_case<R: Rng + ?Sized>(rng: &mut R, u: f64) -> f64 {
|
||||
// compute a random number in the tail by hand
|
||||
|
||||
// strange initial conditions, because the loop is not
|
||||
// do-while, so the condition should be true on the first
|
||||
// run, they get overwritten anyway (0 < 1, so these are
|
||||
// good).
|
||||
let mut x = 1.0f64;
|
||||
let mut y = 0.0f64;
|
||||
|
||||
while -2.0 * y < x * x {
|
||||
let x_: f64 = rng.sample(Open01);
|
||||
let y_: f64 = rng.sample(Open01);
|
||||
|
||||
x = x_.ln() / ziggurat_tables::ZIG_NORM_R;
|
||||
y = y_.ln();
|
||||
}
|
||||
|
||||
if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x }
|
||||
}
|
||||
|
||||
ziggurat(rng, true, // this is symmetric
|
||||
&ziggurat_tables::ZIG_NORM_X,
|
||||
&ziggurat_tables::ZIG_NORM_F,
|
||||
pdf, zero_case)
|
||||
}
|
||||
}
|
||||
|
||||
/// The normal distribution `N(mean, std_dev**2)`.
|
||||
///
|
||||
/// This uses the ZIGNOR variant of the Ziggurat method, see [`StandardNormal`]
|
||||
/// for more details.
|
||||
///
|
||||
/// Note that [`StandardNormal`] is an optimised implementation for mean 0, and
|
||||
/// standard deviation 1.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{Normal, Distribution};
|
||||
///
|
||||
/// // mean 2, standard deviation 3
|
||||
/// let normal = Normal::new(2.0, 3.0);
|
||||
/// let v = normal.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a N(2, 9) distribution", v)
|
||||
/// ```
|
||||
///
|
||||
/// [`StandardNormal`]: crate::StandardNormal
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Normal {
|
||||
mean: f64,
|
||||
std_dev: f64,
|
||||
}
|
||||
|
||||
impl Normal {
|
||||
/// Construct a new `Normal` distribution with the given mean and
|
||||
/// standard deviation.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `std_dev < 0`.
|
||||
#[inline]
|
||||
pub fn new(mean: f64, std_dev: f64) -> Normal {
|
||||
assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
|
||||
Normal {
|
||||
mean,
|
||||
std_dev
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Distribution<f64> for Normal {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
let n = rng.sample(StandardNormal);
|
||||
self.mean + self.std_dev * n
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// The log-normal distribution `ln N(mean, std_dev**2)`.
|
||||
///
|
||||
/// If `X` is log-normal distributed, then `ln(X)` is `N(mean, std_dev**2)`
|
||||
/// distributed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{LogNormal, Distribution};
|
||||
///
|
||||
/// // mean 2, standard deviation 3
|
||||
/// let log_normal = LogNormal::new(2.0, 3.0);
|
||||
/// let v = log_normal.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from an ln N(2, 9) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LogNormal {
|
||||
norm: Normal
|
||||
}
|
||||
|
||||
impl LogNormal {
|
||||
/// Construct a new `LogNormal` distribution with the given mean
|
||||
/// and standard deviation.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `std_dev < 0`.
|
||||
#[inline]
|
||||
pub fn new(mean: f64, std_dev: f64) -> LogNormal {
|
||||
assert!(std_dev >= 0.0, "LogNormal::new called with `std_dev` < 0");
|
||||
LogNormal { norm: Normal::new(mean, std_dev) }
|
||||
}
|
||||
}
|
||||
impl Distribution<f64> for LogNormal {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
self.norm.sample(rng).exp()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Distribution;
|
||||
use super::{Normal, LogNormal};
|
||||
|
||||
#[test]
|
||||
fn test_normal() {
|
||||
let norm = Normal::new(10.0, 10.0);
|
||||
let mut rng = crate::test::rng(210);
|
||||
for _ in 0..1000 {
|
||||
norm.sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_normal_invalid_sd() {
|
||||
Normal::new(10.0, -1.0);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_log_normal() {
|
||||
let lnorm = LogNormal::new(10.0, 10.0);
|
||||
let mut rng = crate::test::rng(211);
|
||||
for _ in 0..1000 {
|
||||
lnorm.sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_log_normal_invalid_sd() {
|
||||
LogNormal::new(10.0, -1.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The Pareto distribution.
|
||||
|
||||
use rand::Rng;
|
||||
use crate::{Distribution, OpenClosed01};
|
||||
|
||||
/// Samples floating-point numbers according to the Pareto distribution
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use rand::prelude::*;
|
||||
/// use rand_distr::Pareto;
|
||||
///
|
||||
/// let val: f64 = SmallRng::from_entropy().sample(Pareto::new(1., 2.));
|
||||
/// println!("{}", val);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Pareto {
|
||||
scale: f64,
|
||||
inv_neg_shape: f64,
|
||||
}
|
||||
|
||||
impl Pareto {
|
||||
/// Construct a new Pareto distribution with given `scale` and `shape`.
|
||||
///
|
||||
/// In the literature, `scale` is commonly written as x<sub>m</sub> or k and
|
||||
/// `shape` is often written as α.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// `scale` and `shape` have to be non-zero and positive.
|
||||
pub fn new(scale: f64, shape: f64) -> Pareto {
|
||||
assert!((scale > 0.) & (shape > 0.));
|
||||
Pareto { scale, inv_neg_shape: -1.0 / shape }
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<f64> for Pareto {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
let u: f64 = rng.sample(OpenClosed01);
|
||||
self.scale * u.powf(self.inv_neg_shape)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Distribution;
|
||||
use super::Pareto;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn invalid() {
|
||||
Pareto::new(0., 0.);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sample() {
|
||||
let scale = 1.0;
|
||||
let shape = 2.0;
|
||||
let d = Pareto::new(scale, shape);
|
||||
let mut rng = crate::test::rng(1);
|
||||
for _ in 0..1000 {
|
||||
let r = d.sample(&mut rng);
|
||||
assert!(r >= scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
// Copyright 2016-2017 The Rust Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The Poisson distribution.
|
||||
|
||||
use rand::Rng;
|
||||
use crate::{Distribution, Cauchy};
|
||||
use crate::utils::log_gamma;
|
||||
|
||||
/// The Poisson distribution `Poisson(lambda)`.
|
||||
///
|
||||
/// This distribution has a density function:
|
||||
/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{Poisson, Distribution};
|
||||
///
|
||||
/// let poi = Poisson::new(2.0);
|
||||
/// let v = poi.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a Poisson(2) distribution", v);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Poisson {
|
||||
lambda: f64,
|
||||
// precalculated values
|
||||
exp_lambda: f64,
|
||||
log_lambda: f64,
|
||||
sqrt_2lambda: f64,
|
||||
magic_val: f64,
|
||||
}
|
||||
|
||||
impl Poisson {
|
||||
/// Construct a new `Poisson` with the given shape parameter
|
||||
/// `lambda`. Panics if `lambda <= 0`.
|
||||
pub fn new(lambda: f64) -> Poisson {
|
||||
assert!(lambda > 0.0, "Poisson::new called with lambda <= 0");
|
||||
let log_lambda = lambda.ln();
|
||||
Poisson {
|
||||
lambda,
|
||||
exp_lambda: (-lambda).exp(),
|
||||
log_lambda,
|
||||
sqrt_2lambda: (2.0 * lambda).sqrt(),
|
||||
magic_val: lambda * log_lambda - log_gamma(1.0 + lambda),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<u64> for Poisson {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
|
||||
// using the algorithm from Numerical Recipes in C
|
||||
|
||||
// for low expected values use the Knuth method
|
||||
if self.lambda < 12.0 {
|
||||
let mut result = 0;
|
||||
let mut p = 1.0;
|
||||
while p > self.exp_lambda {
|
||||
p *= rng.gen::<f64>();
|
||||
result += 1;
|
||||
}
|
||||
result - 1
|
||||
}
|
||||
// high expected values - rejection method
|
||||
else {
|
||||
let mut int_result: u64;
|
||||
|
||||
// we use the Cauchy distribution as the comparison distribution
|
||||
// f(x) ~ 1/(1+x^2)
|
||||
let cauchy = Cauchy::new(0.0, 1.0);
|
||||
|
||||
loop {
|
||||
let mut result;
|
||||
let mut comp_dev;
|
||||
|
||||
loop {
|
||||
// draw from the Cauchy distribution
|
||||
comp_dev = rng.sample(cauchy);
|
||||
// shift the peak of the comparison ditribution
|
||||
result = self.sqrt_2lambda * comp_dev + self.lambda;
|
||||
// repeat the drawing until we are in the range of possible values
|
||||
if result >= 0.0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now the result is a random variable greater than 0 with Cauchy distribution
|
||||
// the result should be an integer value
|
||||
result = result.floor();
|
||||
int_result = result as u64;
|
||||
|
||||
// this is the ratio of the Poisson distribution to the comparison distribution
|
||||
// the magic value scales the distribution function to a range of approximately 0-1
|
||||
// since it is not exact, we multiply the ratio by 0.9 to avoid ratios greater than 1
|
||||
// this doesn't change the resulting distribution, only increases the rate of failed drawings
|
||||
let check = 0.9 * (1.0 + comp_dev * comp_dev)
|
||||
* (result * self.log_lambda - log_gamma(1.0 + result) - self.magic_val).exp();
|
||||
|
||||
// check with uniform random value - if below the threshold, we are within the target distribution
|
||||
if rng.gen::<f64>() <= check {
|
||||
break;
|
||||
}
|
||||
}
|
||||
int_result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::Distribution;
|
||||
use super::Poisson;
|
||||
|
||||
#[test]
|
||||
fn test_poisson_10() {
|
||||
let poisson = Poisson::new(10.0);
|
||||
let mut rng = crate::test::rng(123);
|
||||
let mut sum = 0;
|
||||
for _ in 0..1000 {
|
||||
sum += poisson.sample(&mut rng);
|
||||
}
|
||||
let avg = (sum as f64) / 1000.0;
|
||||
println!("Poisson average: {}", avg);
|
||||
assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_poisson_15() {
|
||||
// Take the 'high expected values' path
|
||||
let poisson = Poisson::new(15.0);
|
||||
let mut rng = crate::test::rng(123);
|
||||
let mut sum = 0;
|
||||
for _ in 0..1000 {
|
||||
sum += poisson.sample(&mut rng);
|
||||
}
|
||||
let avg = (sum as f64) / 1000.0;
|
||||
println!("Poisson average: {}", avg);
|
||||
assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_poisson_invalid_lambda_zero() {
|
||||
Poisson::new(0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_poisson_invalid_lambda_neg() {
|
||||
Poisson::new(-10.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
//! The triangular distribution.
|
||||
|
||||
use rand::Rng;
|
||||
use crate::{Distribution, Standard};
|
||||
|
||||
/// The triangular distribution.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand_distr::{Triangular, Distribution};
|
||||
///
|
||||
/// let d = Triangular::new(0., 5., 2.5);
|
||||
/// let v = d.sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a triangular distribution", v);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Triangular {
|
||||
min: f64,
|
||||
max: f64,
|
||||
mode: f64,
|
||||
}
|
||||
|
||||
impl Triangular {
|
||||
/// Construct a new `Triangular` with minimum `min`, maximum `max` and mode
|
||||
/// `mode`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If `max < mode`, `mode < max` or `max == min`.
|
||||
///
|
||||
#[inline]
|
||||
pub fn new(min: f64, max: f64, mode: f64) -> Triangular {
|
||||
assert!(max >= mode);
|
||||
assert!(mode >= min);
|
||||
assert!(max != min);
|
||||
Triangular { min, max, mode }
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<f64> for Triangular {
|
||||
#[inline]
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
let f: f64 = rng.sample(Standard);
|
||||
let diff_mode_min = self.mode - self.min;
|
||||
let diff_max_min = self.max - self.min;
|
||||
if f * diff_max_min < diff_mode_min {
|
||||
self.min + (f * diff_max_min * diff_mode_min).sqrt()
|
||||
} else {
|
||||
self.max - ((1. - f) * diff_max_min * (self.max - self.mode)).sqrt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::Distribution;
|
||||
use super::Triangular;
|
||||
|
||||
#[test]
|
||||
fn test_new() {
|
||||
for &(min, max, mode) in &[
|
||||
(-1., 1., 0.), (1., 2., 1.), (5., 25., 25.), (1e-5, 1e5, 1e-3),
|
||||
(0., 1., 0.9), (-4., -0.5, -2.), (-13.039, 8.41, 1.17),
|
||||
] {
|
||||
println!("{} {} {}", min, max, mode);
|
||||
let _ = Triangular::new(min, max, mode);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sample() {
|
||||
let norm = Triangular::new(0., 1., 0.5);
|
||||
let mut rng = crate::test::rng(1);
|
||||
for _ in 0..1000 {
|
||||
norm.sample(&mut rng);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rand::Rng;
|
||||
use crate::{Distribution, Uniform};
|
||||
|
||||
/// Samples uniformly from the edge of the unit circle in two dimensions.
|
||||
///
|
||||
/// Implemented via a method by von Neumann[^1].
|
||||
///
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{UnitCircle, Distribution};
|
||||
///
|
||||
/// let circle = UnitCircle::new();
|
||||
/// let v = circle.sample(&mut rand::thread_rng());
|
||||
/// println!("{:?} is from the unit circle.", v)
|
||||
/// ```
|
||||
///
|
||||
/// [^1]: von Neumann, J. (1951) [*Various Techniques Used in Connection with
|
||||
/// Random Digits.*](https://mcnp.lanl.gov/pdf_files/nbs_vonneumann.pdf)
|
||||
/// NBS Appl. Math. Ser., No. 12. Washington, DC: U.S. Government Printing
|
||||
/// Office, pp. 36-38.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct UnitCircle;
|
||||
|
||||
impl UnitCircle {
|
||||
/// Construct a new `UnitCircle` distribution.
|
||||
#[inline]
|
||||
pub fn new() -> UnitCircle {
|
||||
UnitCircle
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<[f64; 2]> for UnitCircle {
|
||||
#[inline]
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 2] {
|
||||
let uniform = Uniform::new(-1., 1.);
|
||||
let mut x1;
|
||||
let mut x2;
|
||||
let mut sum;
|
||||
loop {
|
||||
x1 = uniform.sample(rng);
|
||||
x2 = uniform.sample(rng);
|
||||
sum = x1*x1 + x2*x2;
|
||||
if sum < 1. {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let diff = x1*x1 - x2*x2;
|
||||
[diff / sum, 2.*x1*x2 / sum]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Distribution;
|
||||
use super::UnitCircle;
|
||||
|
||||
/// Assert that two numbers are almost equal to each other.
|
||||
///
|
||||
/// On panic, this macro will print the values of the expressions with their
|
||||
/// debug representations.
|
||||
macro_rules! assert_almost_eq {
|
||||
($a:expr, $b:expr, $prec:expr) => (
|
||||
let diff = ($a - $b).abs();
|
||||
if diff > $prec {
|
||||
panic!(format!(
|
||||
"assertion failed: `abs(left - right) = {:.1e} < {:e}`, \
|
||||
(left: `{}`, right: `{}`)",
|
||||
diff, $prec, $a, $b));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn norm() {
|
||||
let mut rng = crate::test::rng(1);
|
||||
let dist = UnitCircle::new();
|
||||
for _ in 0..1000 {
|
||||
let x = dist.sample(&mut rng);
|
||||
assert_almost_eq!(x[0]*x[0] + x[1]*x[1], 1., 1e-15);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_stability() {
|
||||
let mut rng = crate::test::rng(2);
|
||||
let dist = UnitCircle::new();
|
||||
assert_eq!(dist.sample(&mut rng), [-0.8032118336637037, 0.5956935036263119]);
|
||||
assert_eq!(dist.sample(&mut rng), [-0.4742919588505423, -0.880367615130018]);
|
||||
assert_eq!(dist.sample(&mut rng), [0.9297328981467168, 0.368234623716601]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rand::Rng;
|
||||
use crate::{Distribution, Uniform};
|
||||
|
||||
/// Samples uniformly from the surface of the unit sphere in three dimensions.
|
||||
///
|
||||
/// Implemented via a method by Marsaglia[^1].
|
||||
///
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rand_distr::{UnitSphereSurface, Distribution};
|
||||
///
|
||||
/// let sphere = UnitSphereSurface::new();
|
||||
/// let v = sphere.sample(&mut rand::thread_rng());
|
||||
/// println!("{:?} is from the unit sphere surface.", v)
|
||||
/// ```
|
||||
///
|
||||
/// [^1]: Marsaglia, George (1972). [*Choosing a Point from the Surface of a
|
||||
/// Sphere.*](https://doi.org/10.1214/aoms/1177692644)
|
||||
/// Ann. Math. Statist. 43, no. 2, 645--646.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct UnitSphereSurface;
|
||||
|
||||
impl UnitSphereSurface {
|
||||
/// Construct a new `UnitSphereSurface` distribution.
|
||||
#[inline]
|
||||
pub fn new() -> UnitSphereSurface {
|
||||
UnitSphereSurface
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<[f64; 3]> for UnitSphereSurface {
|
||||
#[inline]
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 3] {
|
||||
let uniform = Uniform::new(-1., 1.);
|
||||
loop {
|
||||
let (x1, x2) = (uniform.sample(rng), uniform.sample(rng));
|
||||
let sum = x1*x1 + x2*x2;
|
||||
if sum >= 1. {
|
||||
continue;
|
||||
}
|
||||
let factor = 2. * (1.0_f64 - sum).sqrt();
|
||||
return [x1 * factor, x2 * factor, 1. - 2.*sum];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Distribution;
|
||||
use super::UnitSphereSurface;
|
||||
|
||||
/// Assert that two numbers are almost equal to each other.
|
||||
///
|
||||
/// On panic, this macro will print the values of the expressions with their
|
||||
/// debug representations.
|
||||
macro_rules! assert_almost_eq {
|
||||
($a:expr, $b:expr, $prec:expr) => (
|
||||
let diff = ($a - $b).abs();
|
||||
if diff > $prec {
|
||||
panic!(format!(
|
||||
"assertion failed: `abs(left - right) = {:.1e} < {:e}`, \
|
||||
(left: `{}`, right: `{}`)",
|
||||
diff, $prec, $a, $b));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn norm() {
|
||||
let mut rng = crate::test::rng(1);
|
||||
let dist = UnitSphereSurface::new();
|
||||
for _ in 0..1000 {
|
||||
let x = dist.sample(&mut rng);
|
||||
assert_almost_eq!(x[0]*x[0] + x[1]*x[1] + x[2]*x[2], 1., 1e-15);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_stability() {
|
||||
let mut rng = crate::test::rng(2);
|
||||
let dist = UnitSphereSurface::new();
|
||||
assert_eq!(dist.sample(&mut rng),
|
||||
[-0.24950027180862533, -0.7552572587896719, 0.6060825747478084]);
|
||||
assert_eq!(dist.sample(&mut rng),
|
||||
[0.47604534507233487, -0.797200864987207, -0.3712837328763685]);
|
||||
assert_eq!(dist.sample(&mut rng),
|
||||
[0.9795722330927367, 0.18692349236651176, 0.07414747571708524]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Math helper functions
|
||||
|
||||
use rand::Rng;
|
||||
use crate::ziggurat_tables;
|
||||
|
||||
use rand::distributions::hidden_export::IntoFloat;
|
||||
|
||||
/// Calculates ln(gamma(x)) (natural logarithm of the gamma
|
||||
/// function) using the Lanczos approximation.
|
||||
///
|
||||
/// The approximation expresses the gamma function as:
|
||||
/// `gamma(z+1) = sqrt(2*pi)*(z+g+0.5)^(z+0.5)*exp(-z-g-0.5)*Ag(z)`
|
||||
/// `g` is an arbitrary constant; we use the approximation with `g=5`.
|
||||
///
|
||||
/// Noting that `gamma(z+1) = z*gamma(z)` and applying `ln` to both sides:
|
||||
/// `ln(gamma(z)) = (z+0.5)*ln(z+g+0.5)-(z+g+0.5) + ln(sqrt(2*pi)*Ag(z)/z)`
|
||||
///
|
||||
/// `Ag(z)` is an infinite series with coefficients that can be calculated
|
||||
/// ahead of time - we use just the first 6 terms, which is good enough
|
||||
/// for most purposes.
|
||||
pub fn log_gamma(x: f64) -> f64 {
|
||||
// precalculated 6 coefficients for the first 6 terms of the series
|
||||
let coefficients: [f64; 6] = [
|
||||
76.18009172947146,
|
||||
-86.50532032941677,
|
||||
24.01409824083091,
|
||||
-1.231739572450155,
|
||||
0.1208650973866179e-2,
|
||||
-0.5395239384953e-5,
|
||||
];
|
||||
|
||||
// (x+0.5)*ln(x+g+0.5)-(x+g+0.5)
|
||||
let tmp = x + 5.5;
|
||||
let log = (x + 0.5) * tmp.ln() - tmp;
|
||||
|
||||
// the first few terms of the series for Ag(x)
|
||||
let mut a = 1.000000000190015;
|
||||
let mut denom = x;
|
||||
for coeff in &coefficients {
|
||||
denom += 1.0;
|
||||
a += coeff / denom;
|
||||
}
|
||||
|
||||
// get everything together
|
||||
// a is Ag(x)
|
||||
// 2.5066... is sqrt(2pi)
|
||||
log + (2.5066282746310005 * a / x).ln()
|
||||
}
|
||||
|
||||
/// Sample a random number using the Ziggurat method (specifically the
|
||||
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
|
||||
/// directly from the paper:
|
||||
///
|
||||
/// * `rng`: source of randomness
|
||||
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
|
||||
/// * `X`: the $x_i$ abscissae.
|
||||
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
|
||||
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
|
||||
/// * `pdf`: the probability density function
|
||||
/// * `zero_case`: manual sampling from the tail when we chose the
|
||||
/// bottom box (i.e. i == 0)
|
||||
|
||||
// the perf improvement (25-50%) is definitely worth the extra code
|
||||
// size from force-inlining.
|
||||
#[inline(always)]
|
||||
pub fn ziggurat<R: Rng + ?Sized, P, Z>(
|
||||
rng: &mut R,
|
||||
symmetric: bool,
|
||||
x_tab: ziggurat_tables::ZigTable,
|
||||
f_tab: ziggurat_tables::ZigTable,
|
||||
mut pdf: P,
|
||||
mut zero_case: Z)
|
||||
-> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 {
|
||||
loop {
|
||||
// As an optimisation we re-implement the conversion to a f64.
|
||||
// From the remaining 12 most significant bits we use 8 to construct `i`.
|
||||
// This saves us generating a whole extra random number, while the added
|
||||
// precision of using 64 bits for f64 does not buy us much.
|
||||
let bits = rng.next_u64();
|
||||
let i = bits as usize & 0xff;
|
||||
|
||||
let u = if symmetric {
|
||||
// Convert to a value in the range [2,4) and substract to get [-1,1)
|
||||
// We can't convert to an open range directly, that would require
|
||||
// substracting `3.0 - EPSILON`, which is not representable.
|
||||
// It is possible with an extra step, but an open range does not
|
||||
// seem neccesary for the ziggurat algorithm anyway.
|
||||
(bits >> 12).into_float_with_exponent(1) - 3.0
|
||||
} else {
|
||||
// Convert to a value in the range [1,2) and substract to get (0,1)
|
||||
(bits >> 12).into_float_with_exponent(0)
|
||||
- (1.0 - std::f64::EPSILON / 2.0)
|
||||
};
|
||||
let x = u * x_tab[i];
|
||||
|
||||
let test_x = if symmetric { x.abs() } else {x};
|
||||
|
||||
// algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
|
||||
if test_x < x_tab[i + 1] {
|
||||
return x;
|
||||
}
|
||||
if i == 0 {
|
||||
return zero_case(rng, u);
|
||||
}
|
||||
// algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
|
||||
if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The Weibull distribution.
|
||||
|
||||
use rand::Rng;
|
||||
use crate::{Distribution, OpenClosed01};
|
||||
|
||||
/// Samples floating-point numbers according to the Weibull distribution
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use rand::prelude::*;
|
||||
/// use rand_distr::Weibull;
|
||||
///
|
||||
/// let val: f64 = SmallRng::from_entropy().sample(Weibull::new(1., 10.));
|
||||
/// println!("{}", val);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Weibull {
|
||||
inv_shape: f64,
|
||||
scale: f64,
|
||||
}
|
||||
|
||||
impl Weibull {
|
||||
/// Construct a new `Weibull` distribution with given `scale` and `shape`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// `scale` and `shape` have to be non-zero and positive.
|
||||
pub fn new(scale: f64, shape: f64) -> Weibull {
|
||||
assert!((scale > 0.) & (shape > 0.));
|
||||
Weibull { inv_shape: 1./shape, scale }
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<f64> for Weibull {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
|
||||
let x: f64 = rng.sample(OpenClosed01);
|
||||
self.scale * (-x.ln()).powf(self.inv_shape)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Distribution;
|
||||
use super::Weibull;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn invalid() {
|
||||
Weibull::new(0., 0.);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sample() {
|
||||
let scale = 1.0;
|
||||
let shape = 2.0;
|
||||
let d = Weibull::new(scale, shape);
|
||||
let mut rng = crate::test::rng(1);
|
||||
for _ in 0..1000 {
|
||||
let r = d.sample(&mut rng);
|
||||
assert!(r >= 0.);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
// Copyright 2018 Developers of the Rand project.
|
||||
// Copyright 2013 The Rust Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Tables for distributions which are sampled using the ziggurat
|
||||
// algorithm. Autogenerated by `ziggurat_tables.py`.
|
||||
|
||||
pub type ZigTable = &'static [f64; 257];
|
||||
pub const ZIG_NORM_R: f64 = 3.654152885361008796;
|
||||
pub static ZIG_NORM_X: [f64; 257] =
|
||||
[3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074,
|
||||
3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434,
|
||||
2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548,
|
||||
2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056,
|
||||
2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570,
|
||||
2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761,
|
||||
2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318,
|
||||
2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520,
|
||||
2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952,
|
||||
2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565,
|
||||
2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760,
|
||||
2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995,
|
||||
2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268,
|
||||
2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957,
|
||||
2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778,
|
||||
2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715,
|
||||
2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244,
|
||||
1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896,
|
||||
1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257,
|
||||
1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081,
|
||||
1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281,
|
||||
1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566,
|
||||
1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199,
|
||||
1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933,
|
||||
1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012,
|
||||
1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086,
|
||||
1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338,
|
||||
1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526,
|
||||
1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427,
|
||||
1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339,
|
||||
1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456,
|
||||
1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553,
|
||||
1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404,
|
||||
1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369,
|
||||
1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830,
|
||||
1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425,
|
||||
1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534,
|
||||
1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964,
|
||||
1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606,
|
||||
1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679,
|
||||
1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728,
|
||||
1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732,
|
||||
1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903,
|
||||
1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552,
|
||||
1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650,
|
||||
1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240,
|
||||
1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975,
|
||||
1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151,
|
||||
1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714,
|
||||
1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538,
|
||||
1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441,
|
||||
1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750,
|
||||
0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130,
|
||||
0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997,
|
||||
0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550,
|
||||
0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752,
|
||||
0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785,
|
||||
0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653,
|
||||
0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448,
|
||||
0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928,
|
||||
0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262,
|
||||
0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393,
|
||||
0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746,
|
||||
0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806,
|
||||
0.000000000000000000];
|
||||
pub static ZIG_NORM_F: [f64; 257] =
|
||||
[0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872,
|
||||
0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100,
|
||||
0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839,
|
||||
0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237,
|
||||
0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690,
|
||||
0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918,
|
||||
0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664,
|
||||
0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916,
|
||||
0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854,
|
||||
0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965,
|
||||
0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509,
|
||||
0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229,
|
||||
0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627,
|
||||
0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880,
|
||||
0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014,
|
||||
0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349,
|
||||
0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352,
|
||||
0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926,
|
||||
0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563,
|
||||
0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071,
|
||||
0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654,
|
||||
0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926,
|
||||
0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112,
|
||||
0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651,
|
||||
0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589,
|
||||
0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525,
|
||||
0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988,
|
||||
0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150,
|
||||
0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837,
|
||||
0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316,
|
||||
0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984,
|
||||
0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274,
|
||||
0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396,
|
||||
0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099,
|
||||
0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340,
|
||||
0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515,
|
||||
0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344,
|
||||
0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958,
|
||||
0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668,
|
||||
0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784,
|
||||
0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519,
|
||||
0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750,
|
||||
0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481,
|
||||
0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788,
|
||||
0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658,
|
||||
0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142,
|
||||
0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700,
|
||||
0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941,
|
||||
0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916,
|
||||
0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473,
|
||||
0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719,
|
||||
0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205,
|
||||
0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991,
|
||||
0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357,
|
||||
0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376,
|
||||
0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409,
|
||||
0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437,
|
||||
0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500,
|
||||
0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902,
|
||||
0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935,
|
||||
0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077,
|
||||
0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839,
|
||||
0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247,
|
||||
0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328,
|
||||
1.000000000000000000];
|
||||
pub const ZIG_EXP_R: f64 = 7.697117470131050077;
|
||||
pub static ZIG_EXP_X: [f64; 257] =
|
||||
[8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696,
|
||||
6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488,
|
||||
5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530,
|
||||
4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380,
|
||||
4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857,
|
||||
4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762,
|
||||
3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744,
|
||||
3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770,
|
||||
3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608,
|
||||
3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405,
|
||||
3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160,
|
||||
3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481,
|
||||
3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601,
|
||||
2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825,
|
||||
2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780,
|
||||
2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752,
|
||||
2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489,
|
||||
2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970,
|
||||
2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815,
|
||||
2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886,
|
||||
2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372,
|
||||
2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213,
|
||||
2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027,
|
||||
2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289,
|
||||
2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526,
|
||||
2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563,
|
||||
1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943,
|
||||
1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242,
|
||||
1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954,
|
||||
1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014,
|
||||
1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566,
|
||||
1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896,
|
||||
1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334,
|
||||
1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892,
|
||||
1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092,
|
||||
1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058,
|
||||
1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504,
|
||||
1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137,
|
||||
1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189,
|
||||
1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117,
|
||||
1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330,
|
||||
1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124,
|
||||
1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677,
|
||||
1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511,
|
||||
1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813,
|
||||
1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209,
|
||||
1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735,
|
||||
0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509,
|
||||
0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311,
|
||||
0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066,
|
||||
0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206,
|
||||
0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430,
|
||||
0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102,
|
||||
0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959,
|
||||
0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947,
|
||||
0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030,
|
||||
0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626,
|
||||
0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398,
|
||||
0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235,
|
||||
0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765,
|
||||
0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122,
|
||||
0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703,
|
||||
0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842,
|
||||
0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570,
|
||||
0.000000000000000000];
|
||||
pub static ZIG_EXP_F: [f64; 257] =
|
||||
[0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573,
|
||||
0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797,
|
||||
0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991,
|
||||
0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981,
|
||||
0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943,
|
||||
0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355,
|
||||
0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581,
|
||||
0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221,
|
||||
0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622,
|
||||
0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431,
|
||||
0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139,
|
||||
0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289,
|
||||
0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379,
|
||||
0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030,
|
||||
0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660,
|
||||
0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816,
|
||||
0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752,
|
||||
0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435,
|
||||
0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146,
|
||||
0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197,
|
||||
0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213,
|
||||
0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145,
|
||||
0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283,
|
||||
0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641,
|
||||
0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671,
|
||||
0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602,
|
||||
0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146,
|
||||
0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839,
|
||||
0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129,
|
||||
0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081,
|
||||
0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829,
|
||||
0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083,
|
||||
0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189,
|
||||
0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654,
|
||||
0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628,
|
||||
0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956,
|
||||
0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560,
|
||||
0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543,
|
||||
0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173,
|
||||
0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967,
|
||||
0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746,
|
||||
0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252,
|
||||
0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185,
|
||||
0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223,
|
||||
0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717,
|
||||
0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449,
|
||||
0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379,
|
||||
0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056,
|
||||
0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350,
|
||||
0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209,
|
||||
0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907,
|
||||
0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836,
|
||||
0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708,
|
||||
0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881,
|
||||
0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931,
|
||||
0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056,
|
||||
0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150,
|
||||
0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560,
|
||||
0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398,
|
||||
0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177,
|
||||
0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456,
|
||||
0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838,
|
||||
0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101,
|
||||
0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477,
|
||||
1.000000000000000000];
|
||||
@@ -69,7 +69,8 @@ pub struct OpenClosed01;
|
||||
pub struct Open01;
|
||||
|
||||
|
||||
pub(crate) trait IntoFloat {
|
||||
#[doc(hidden)]
|
||||
pub trait IntoFloat {
|
||||
type F;
|
||||
|
||||
/// Helper method to combine the fraction and a contant exponent into a
|
||||
|
||||
@@ -213,6 +213,9 @@ mod bernoulli;
|
||||
#[cfg(feature="std")] mod weibull;
|
||||
|
||||
mod float;
|
||||
#[doc(hidden)] pub mod hidden_export {
|
||||
pub use super::float::IntoFloat; // used by rand_distr
|
||||
}
|
||||
mod integer;
|
||||
mod other;
|
||||
mod utils;
|
||||
|
||||
Reference in New Issue
Block a user