diff options
Diffstat (limited to 'rand/rand_distr')
26 files changed, 0 insertions, 3795 deletions
diff --git a/rand/rand_distr/CHANGELOG.md b/rand/rand_distr/CHANGELOG.md deleted file mode 100644 index 376bb95..0000000 --- a/rand/rand_distr/CHANGELOG.md +++ /dev/null @@ -1,21 +0,0 @@ -# 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.2.1] - 2019-06-29 -- Update dependency to support Rand 0.7 -- Doc link fixes - -## [0.2.0] - 2019-06-06 -- Remove `new` constructors for zero-sized types -- Add Pert distribution -- Fix undefined behavior in `Poisson` -- Make all distributions return `Result`s instead of panicking -- Implement `f32` support for most distributions -- Rename `UnitSphereSurface` to `UnitSphere` -- Implement `UnitBall` and `UnitDisc` - -## [0.1.0] - 2019-06-06 -Initial release. This is equivalent to the code in `rand` 0.6.5. diff --git a/rand/rand_distr/COPYRIGHT b/rand/rand_distr/COPYRIGHT deleted file mode 100644 index 468d907..0000000 --- a/rand/rand_distr/COPYRIGHT +++ /dev/null @@ -1,12 +0,0 @@ -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. diff --git a/rand/rand_distr/Cargo.toml b/rand/rand_distr/Cargo.toml deleted file mode 100644 index 315a5b0..0000000 --- a/rand/rand_distr/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "rand_distr" -version = "0.2.1" -authors = ["The Rand Project Developers"] -license = "MIT OR 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.7" } - -[dev-dependencies] -rand_pcg = { version = "0.2", path = "../rand_pcg" } -# Histogram implementation for testing uniformity -average = "0.9.2" diff --git a/rand/rand_distr/LICENSE-APACHE b/rand/rand_distr/LICENSE-APACHE deleted file mode 100644 index 17d7468..0000000 --- a/rand/rand_distr/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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. diff --git a/rand/rand_distr/LICENSE-MIT b/rand/rand_distr/LICENSE-MIT deleted file mode 100644 index cf65607..0000000 --- a/rand/rand_distr/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -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. diff --git a/rand/rand_distr/README.md b/rand/rand_distr/README.md deleted file mode 100644 index 68acd2f..0000000 --- a/rand/rand_distr/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# rand_distr - -[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) -[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) -[![Latest version](https://img.shields.io/crates/v/rand_distr.svg)](https://crates.io/crates/rand_distr) -[[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) -[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_distr) -[![API](https://docs.rs/rand_distr/badge.svg)](https://docs.rs/rand_distr) -[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](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, Binomial, Cauchy, ChiSquared, Dirichlet, exponential, -Fisher F, Gamma, Log-normal, Normal, Pareto, Poisson, StudentT, Triangular and -Weibull distributions, as well as sampling points from the unit circle and unit -sphere surface. - -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. diff --git a/rand/rand_distr/benches/distributions.rs b/rand/rand_distr/benches/distributions.rs deleted file mode 100644 index 63bde36..0000000 --- a/rand/rand_distr/benches/distributions.rs +++ /dev/null @@ -1,316 +0,0 @@ -// 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. - -#![feature(test)] - -const RAND_BENCH_N: u64 = 1000; - -use std::mem::size_of; -use std::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128}; -use test::Bencher; -use std::time::Duration; - -use rand::prelude::*; -use rand_distr::{*, weighted::WeightedIndex}; - -// At this time, distributions are optimised for 64-bit platforms. -use rand_pcg::Pcg64Mcg; - -macro_rules! distr_int { - ($fnn:ident, $ty:ty, $distr:expr) => { - #[bench] - fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); - let distr = $distr; - - b.iter(|| { - let mut accum = 0 as $ty; - for _ in 0..RAND_BENCH_N { - let x: $ty = distr.sample(&mut rng); - accum = accum.wrapping_add(x); - } - accum - }); - b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; - } - } -} - -macro_rules! distr_nz_int { - ($fnn:ident, $tynz:ty, $ty:ty, $distr:expr) => { - #[bench] - fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); - let distr = $distr; - - b.iter(|| { - let mut accum = 0 as $ty; - for _ in 0..RAND_BENCH_N { - let x: $tynz = distr.sample(&mut rng); - accum = accum.wrapping_add(x.get()); - } - accum - }); - b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; - } - } -} - -macro_rules! distr_float { - ($fnn:ident, $ty:ty, $distr:expr) => { - #[bench] - fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); - let distr = $distr; - - b.iter(|| { - let mut accum = 0.0; - for _ in 0..RAND_BENCH_N { - let x: $ty = distr.sample(&mut rng); - accum += x; - } - accum - }); - b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; - } - } -} - -macro_rules! distr_duration { - ($fnn:ident, $distr:expr) => { - #[bench] - fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); - let distr = $distr; - - b.iter(|| { - let mut accum = Duration::new(0, 0); - for _ in 0..RAND_BENCH_N { - let x: Duration = distr.sample(&mut rng); - accum = accum.checked_add(x).unwrap_or(Duration::new(u64::max_value(), 999_999_999)); - } - accum - }); - b.bytes = size_of::<Duration>() as u64 * RAND_BENCH_N; - } - } -} - -macro_rules! distr { - ($fnn:ident, $ty:ty, $distr:expr) => { - #[bench] - fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); - let distr = $distr; - - b.iter(|| { - let mut accum = 0u32; - for _ in 0..RAND_BENCH_N { - let x: $ty = distr.sample(&mut rng); - accum = accum.wrapping_add(x as u32); - } - accum - }); - b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; - } - } -} - -macro_rules! distr_arr { - ($fnn:ident, $ty:ty, $distr:expr) => { - #[bench] - fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); - let distr = $distr; - - b.iter(|| { - let mut accum = 0u32; - for _ in 0..RAND_BENCH_N { - let x: $ty = distr.sample(&mut rng); - accum = accum.wrapping_add(x[0] as u32); - } - accum - }); - b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; - } - } -} - -// uniform -distr_int!(distr_uniform_i8, i8, Uniform::new(20i8, 100)); -distr_int!(distr_uniform_i16, i16, Uniform::new(-500i16, 2000)); -distr_int!(distr_uniform_i32, i32, Uniform::new(-200_000_000i32, 800_000_000)); -distr_int!(distr_uniform_i64, i64, Uniform::new(3i64, 123_456_789_123)); -distr_int!(distr_uniform_i128, i128, Uniform::new(-123_456_789_123i128, 123_456_789_123_456_789)); -distr_int!(distr_uniform_usize16, usize, Uniform::new(0usize, 0xb9d7)); -distr_int!(distr_uniform_usize32, usize, Uniform::new(0usize, 0x548c0f43)); -#[cfg(target_pointer_width = "64")] -distr_int!(distr_uniform_usize64, usize, Uniform::new(0usize, 0x3a42714f2bf927a8)); -distr_int!(distr_uniform_isize, isize, Uniform::new(-1060478432isize, 1858574057)); - -distr_float!(distr_uniform_f32, f32, Uniform::new(2.26f32, 2.319)); -distr_float!(distr_uniform_f64, f64, Uniform::new(2.26f64, 2.319)); - -const LARGE_SEC: u64 = u64::max_value() / 1000; - -distr_duration!(distr_uniform_duration_largest, - Uniform::new_inclusive(Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999)) -); -distr_duration!(distr_uniform_duration_large, - Uniform::new(Duration::new(0, 0), Duration::new(LARGE_SEC, 1_000_000_000 / 2)) -); -distr_duration!(distr_uniform_duration_one, - Uniform::new(Duration::new(0, 0), Duration::new(1, 0)) -); -distr_duration!(distr_uniform_duration_variety, - Uniform::new(Duration::new(10000, 423423), Duration::new(200000, 6969954)) -); -distr_duration!(distr_uniform_duration_edge, - Uniform::new_inclusive(Duration::new(LARGE_SEC, 999_999_999), Duration::new(LARGE_SEC + 1, 1)) -); - - -// standard -distr_int!(distr_standard_i8, i8, Standard); -distr_int!(distr_standard_i16, i16, Standard); -distr_int!(distr_standard_i32, i32, Standard); -distr_int!(distr_standard_i64, i64, Standard); -distr_int!(distr_standard_i128, i128, Standard); -distr_nz_int!(distr_standard_nz8, NonZeroU8, u8, Standard); -distr_nz_int!(distr_standard_nz16, NonZeroU16, u16, Standard); -distr_nz_int!(distr_standard_nz32, NonZeroU32, u32, Standard); -distr_nz_int!(distr_standard_nz64, NonZeroU64, u64, Standard); -distr_nz_int!(distr_standard_nz128, NonZeroU128, u128, Standard); - -distr!(distr_standard_bool, bool, Standard); -distr!(distr_standard_alphanumeric, char, Alphanumeric); -distr!(distr_standard_codepoint, char, Standard); - -distr_float!(distr_standard_f32, f32, Standard); -distr_float!(distr_standard_f64, f64, Standard); -distr_float!(distr_open01_f32, f32, Open01); -distr_float!(distr_open01_f64, f64, Open01); -distr_float!(distr_openclosed01_f32, f32, OpenClosed01); -distr_float!(distr_openclosed01_f64, f64, OpenClosed01); - -// distributions -distr_float!(distr_exp, f64, Exp::new(1.23 * 4.56).unwrap()); -distr_float!(distr_normal, f64, Normal::new(-1.23, 4.56).unwrap()); -distr_float!(distr_log_normal, f64, LogNormal::new(-1.23, 4.56).unwrap()); -distr_float!(distr_gamma_large_shape, f64, Gamma::new(10., 1.0).unwrap()); -distr_float!(distr_gamma_small_shape, f64, Gamma::new(0.1, 1.0).unwrap()); -distr_float!(distr_cauchy, f64, Cauchy::new(4.2, 6.9).unwrap()); -distr_float!(distr_triangular, f64, Triangular::new(0., 1., 0.9).unwrap()); -distr_int!(distr_binomial, u64, Binomial::new(20, 0.7).unwrap()); -distr_int!(distr_binomial_small, u64, Binomial::new(1000000, 1e-30).unwrap()); -distr_int!(distr_poisson, u64, Poisson::new(4.0).unwrap()); -distr!(distr_bernoulli, bool, Bernoulli::new(0.18).unwrap()); -distr_arr!(distr_circle, [f64; 2], UnitCircle); -distr_arr!(distr_sphere, [f64; 3], UnitSphere); - -// Weighted -distr_int!(distr_weighted_i8, usize, WeightedIndex::new(&[1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap()); -distr_int!(distr_weighted_u32, usize, WeightedIndex::new(&[1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap()); -distr_int!(distr_weighted_f64, usize, WeightedIndex::new(&[1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap()); -distr_int!(distr_weighted_large_set, usize, WeightedIndex::new((0..10000).rev().chain(1..10001)).unwrap()); - -distr_int!(distr_weighted_alias_method_i8, usize, weighted::alias_method::WeightedIndex::new(vec![1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap()); -distr_int!(distr_weighted_alias_method_u32, usize, weighted::alias_method::WeightedIndex::new(vec![1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap()); -distr_int!(distr_weighted_alias_method_f64, usize, weighted::alias_method::WeightedIndex::new(vec![1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap()); -distr_int!(distr_weighted_alias_method_large_set, usize, weighted::alias_method::WeightedIndex::new((0..10000).rev().chain(1..10001).collect()).unwrap()); - -// construct and sample from a range -macro_rules! gen_range_int { - ($fnn:ident, $ty:ident, $low:expr, $high:expr) => { - #[bench] - fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); - - b.iter(|| { - let mut high = $high; - let mut accum: $ty = 0; - for _ in 0..RAND_BENCH_N { - accum = accum.wrapping_add(rng.gen_range($low, high)); - // force recalculation of range each time - high = high.wrapping_add(1) & std::$ty::MAX; - } - accum - }); - b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; - } - } -} - -gen_range_int!(gen_range_i8, i8, -20i8, 100); -gen_range_int!(gen_range_i16, i16, -500i16, 2000); -gen_range_int!(gen_range_i32, i32, -200_000_000i32, 800_000_000); -gen_range_int!(gen_range_i64, i64, 3i64, 123_456_789_123); -gen_range_int!(gen_range_i128, i128, -12345678901234i128, 123_456_789_123_456_789); - -// construct and sample from a floating-point range -macro_rules! gen_range_float { - ($fnn:ident, $ty:ident, $low:expr, $high:expr) => { - #[bench] - fn $fnn(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); - - b.iter(|| { - let mut high = $high; - let mut low = $low; - let mut accum: $ty = 0.0; - for _ in 0..RAND_BENCH_N { - accum += rng.gen_range(low, high); - // force recalculation of range each time - low += 0.9; - high += 1.1; - } - accum - }); - b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; - } - } -} - -gen_range_float!(gen_range_f32, f32, -20000.0f32, 100000.0); -gen_range_float!(gen_range_f64, f64, 123.456f64, 7890.12); - -#[bench] -fn dist_iter(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_entropy(); - let distr = Normal::new(-2.71828, 3.14159).unwrap(); - let mut iter = distr.sample_iter(&mut rng); - - b.iter(|| { - let mut accum = 0.0; - for _ in 0..RAND_BENCH_N { - accum += iter.next().unwrap(); - } - accum - }); - b.bytes = size_of::<f64>() as u64 * RAND_BENCH_N; -} - -macro_rules! sample_binomial { - ($name:ident, $n:expr, $p:expr) => { - #[bench] - fn $name(b: &mut Bencher) { - let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap(); - let (n, p) = ($n, $p); - b.iter(|| { - let d = Binomial::new(n, p).unwrap(); - rng.sample(d) - }) - } - } -} - -sample_binomial!(misc_binomial_1, 1, 0.9); -sample_binomial!(misc_binomial_10, 10, 0.9); -sample_binomial!(misc_binomial_100, 100, 0.99); -sample_binomial!(misc_binomial_1000, 1000, 0.01); -sample_binomial!(misc_binomial_1e12, 1000_000_000_000, 0.2); diff --git a/rand/rand_distr/src/binomial.rs b/rand/rand_distr/src/binomial.rs deleted file mode 100644 index 0e6bf9a..0000000 --- a/rand/rand_distr/src/binomial.rs +++ /dev/null @@ -1,329 +0,0 @@ -// 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, Uniform}; - -/// 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).unwrap(); -/// 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, -} - -/// Error type returned from `Binomial::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Error { - /// `p < 0` or `nan`. - ProbabilityTooSmall, - /// `p > 1`. - ProbabilityTooLarge, -} - -impl Binomial { - /// Construct a new `Binomial` with the given shape parameters `n` (number - /// of trials) and `p` (probability of success). - pub fn new(n: u64, p: f64) -> Result<Binomial, Error> { - if !(p >= 0.0) { - return Err(Error::ProbabilityTooSmall); - } - if !(p <= 1.0) { - return Err(Error::ProbabilityTooLarge); - } - Ok(Binomial { n, p }) - } -} - -/// Convert a `f64` to an `i64`, panicing on overflow. -// In the future (Rust 1.34), this might be replaced with `TryFrom`. -fn f64_to_i64(x: f64) -> i64 { - assert!(x < (::std::i64::MAX as f64)); - x as i64 -} - -impl Distribution<u64> for Binomial { - #[allow(clippy::many_single_char_names)] // Same names as in the reference. - 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; - } - - // The 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; - let q = 1. - p; - - // For small n * min(p, 1 - p), the BINV algorithm based on the inverse - // transformation of the binomial distribution is efficient. Otherwise, - // the BTPE algorithm is used. - // - // 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 - - // Threshold for prefering the BINV algorithm. The paper suggests 10, - // Ranlib uses 30, and GSL uses 14. - const BINV_THRESHOLD: f64 = 10.; - - if (self.n as f64) * p < BINV_THRESHOLD && - self.n <= (::std::i32::MAX as u64) { - // Use the BINV algorithm. - 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 { - // Use the BTPE algorithm. - - // Threshold for using the squeeze algorithm. This can be freely - // chosen based on performance. Ranlib and GSL use 20. - const SQUEEZE_THRESHOLD: i64 = 20; - - // Step 0: Calculate constants as functions of `n` and `p`. - let n = self.n as f64; - let np = n * p; - let npq = np * q; - let f_m = np + p; - let m = f64_to_i64(f_m); - // radius of triangle region, since height=1 also area of region - let p1 = (2.195 * npq.sqrt() - 4.6 * q).floor() + 0.5; - // tip of triangle - let x_m = (m as f64) + 0.5; - // left edge of triangle - let x_l = x_m - p1; - // right edge of triangle - let x_r = x_m + p1; - let c = 0.134 + 20.5 / (15.3 + (m as f64)); - // p1 + area of parallelogram region - let p2 = p1 * (1. + 2. * c); - - fn lambda(a: f64) -> f64 { - a * (1. + 0.5 * a) - } - - let lambda_l = lambda((f_m - x_l) / (f_m - x_l * p)); - let lambda_r = lambda((x_r - f_m) / (x_r * q)); - // p1 + area of left tail - let p3 = p2 + c / lambda_l; - // p1 + area of right tail - let p4 = p3 + c / lambda_r; - - // return value - let mut y: i64; - - let gen_u = Uniform::new(0., p4); - let gen_v = Uniform::new(0., 1.); - - loop { - // Step 1: Generate `u` for selecting the region. If region 1 is - // selected, generate a triangularly distributed variate. - let u = gen_u.sample(rng); - let mut v = gen_v.sample(rng); - if !(u > p1) { - y = f64_to_i64(x_m - p1 * v + u); - break; - } - - if !(u > p2) { - // Step 2: Region 2, parallelograms. Check if region 2 is - // used. If so, generate `y`. - let x = x_l + (u - p1) / c; - v = v * c + 1.0 - (x - x_m).abs() / p1; - if v > 1. { - continue; - } else { - y = f64_to_i64(x); - } - } else if !(u > p3) { - // Step 3: Region 3, left exponential tail. - y = f64_to_i64(x_l + v.ln() / lambda_l); - if y < 0 { - continue; - } else { - v *= (u - p2) * lambda_l; - } - } else { - // Step 4: Region 4, right exponential tail. - y = f64_to_i64(x_r - v.ln() / lambda_r); - if y > 0 && (y as u64) > self.n { - continue; - } else { - v *= (u - p3) * lambda_r; - } - } - - // Step 5: Acceptance/rejection comparison. - - // Step 5.0: Test for appropriate method of evaluating f(y). - let k = (y - m).abs(); - if !(k > SQUEEZE_THRESHOLD && (k as f64) < 0.5 * npq - 1.) { - // Step 5.1: Evaluate f(y) via the recursive relationship. Start the - // search from the mode. - let s = p / q; - let a = s * (n + 1.); - let mut f = 1.0; - if m < y { - let mut i = m; - loop { - i += 1; - f *= a / (i as f64) - s; - if i == y { - break; - } - } - } else if m > y { - let mut i = y; - loop { - i += 1; - f /= a / (i as f64) - s; - if i == m { - break; - } - } - } - if v > f { - continue; - } else { - break; - } - } - - // Step 5.2: Squeezing. Check the value of ln(v) againts upper and - // lower bound of ln(f(y)). - let k = k as f64; - let rho = (k / npq) * ((k * (k / 3. + 0.625) + 1./6.) / npq + 0.5); - let t = -0.5 * k*k / npq; - let alpha = v.ln(); - if alpha < t - rho { - break; - } - if alpha > t + rho { - continue; - } - - // Step 5.3: Final acceptance/rejection test. - let x1 = (y + 1) as f64; - let f1 = (m + 1) as f64; - let z = (f64_to_i64(n) + 1 - m) as f64; - let w = (f64_to_i64(n) - y + 1) as f64; - - fn stirling(a: f64) -> f64 { - let a2 = a * a; - (13860. - (462. - (132. - (99. - 140. / a2) / a2) / a2) / a2) / a / 166320. - } - - if alpha > x_m * (f1 / x1).ln() - + (n - (m as f64) + 0.5) * (z / w).ln() - + ((y - m) as f64) * (w * p / (x1 * q)).ln() - // We use the signs from the GSL implementation, which are - // different than the ones in the reference. According to - // the GSL authors, the new signs were verified to be - // correct by one of the original designers of the - // algorithm. - + stirling(f1) + stirling(z) - stirling(x1) - stirling(w) - { - continue; - } - - break; - } - assert!(y >= 0); - result = y 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).unwrap(); - - 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).unwrap()), 0); - assert_eq!(rng.sample(Binomial::new(20, 1.0).unwrap()), 20); - } - - #[test] - #[should_panic] - fn test_binomial_invalid_lambda_neg() { - Binomial::new(20, -10.0).unwrap(); - } -} diff --git a/rand/rand_distr/src/cauchy.rs b/rand/rand_distr/src/cauchy.rs deleted file mode 100644 index 6b0e7c6..0000000 --- a/rand/rand_distr/src/cauchy.rs +++ /dev/null @@ -1,120 +0,0 @@ -// 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, Standard}; -use crate::utils::Float; - -/// 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).unwrap(); -/// let v = cau.sample(&mut rand::thread_rng()); -/// println!("{} is from a Cauchy(2, 5) distribution", v); -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct Cauchy<N> { - median: N, - scale: N, -} - -/// Error type returned from `Cauchy::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Error { - /// `scale <= 0` or `nan`. - ScaleTooSmall, -} - -impl<N: Float> Cauchy<N> -where Standard: Distribution<N> -{ - /// Construct a new `Cauchy` with the given shape parameters - /// `median` the peak location and `scale` the scale factor. - pub fn new(median: N, scale: N) -> Result<Cauchy<N>, Error> { - if !(scale > N::from(0.0)) { - return Err(Error::ScaleTooSmall); - } - Ok(Cauchy { - median, - scale - }) - } -} - -impl<N: Float> Distribution<N> for Cauchy<N> -where Standard: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - // sample from [0, 1) - let x = Standard.sample(rng); - // get standard cauchy random number - // note that π/2 is not exactly representable, even if x=0.5 the result is finite - let comp_dev = (N::pi() * x).tan(); - // shift and scale according to parameters - self.median + self.scale * comp_dev - } -} - -#[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_averages() { - // NOTE: given that the variance and mean are undefined, - // this test does not have any rigorous statistical meaning. - let cauchy = Cauchy::new(10.0, 5.0).unwrap(); - let mut rng = crate::test::rng(123); - let mut numbers: [f64; 1000] = [0.0; 1000]; - let mut sum = 0.0; - for i in 0..1000 { - numbers[i] = cauchy.sample(&mut rng); - sum += numbers[i]; - } - let median = median(&mut numbers); - println!("Cauchy median: {}", median); - assert!((median - 10.0).abs() < 0.4); // not 100% certain, but probable enough - let mean = sum / 1000.0; - println!("Cauchy mean: {}", mean); - // for a Cauchy distribution the mean should not converge - assert!((mean - 10.0).abs() > 0.4); // not 100% certain, but probable enough - } - - #[test] - #[should_panic] - fn test_cauchy_invalid_scale_zero() { - Cauchy::new(0.0, 0.0).unwrap(); - } - - #[test] - #[should_panic] - fn test_cauchy_invalid_scale_neg() { - Cauchy::new(0.0, -10.0).unwrap(); - } -} diff --git a/rand/rand_distr/src/dirichlet.rs b/rand/rand_distr/src/dirichlet.rs deleted file mode 100644 index 71cf73c..0000000 --- a/rand/rand_distr/src/dirichlet.rs +++ /dev/null @@ -1,154 +0,0 @@ -// 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, Gamma, StandardNormal, Exp1, Open01}; -use crate::utils::Float; - -/// 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]).unwrap(); -/// 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<N> { - /// Concentration parameters (alpha) - alpha: Vec<N>, -} - -/// Error type returned from `Dirchlet::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Error { - /// `alpha.len() < 2`. - AlphaTooShort, - /// `alpha <= 0.0` or `nan`. - AlphaTooSmall, - /// `size < 2`. - SizeTooSmall, -} - -impl<N: Float> Dirichlet<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - /// Construct a new `Dirichlet` with the given alpha parameter `alpha`. - /// - /// Requires `alpha.len() >= 2`. - #[inline] - pub fn new<V: Into<Vec<N>>>(alpha: V) -> Result<Dirichlet<N>, Error> { - let a = alpha.into(); - if a.len() < 2 { - return Err(Error::AlphaTooShort); - } - for &ai in &a { - if !(ai > N::from(0.0)) { - return Err(Error::AlphaTooSmall); - } - } - - Ok(Dirichlet { alpha: a }) - } - - /// Construct a new `Dirichlet` with the given shape parameter `alpha` and `size`. - /// - /// Requires `size >= 2`. - #[inline] - pub fn new_with_size(alpha: N, size: usize) -> Result<Dirichlet<N>, Error> { - if !(alpha > N::from(0.0)) { - return Err(Error::AlphaTooSmall); - } - if size < 2 { - return Err(Error::SizeTooSmall); - } - Ok(Dirichlet { - alpha: vec![alpha; size], - }) - } -} - -impl<N: Float> Distribution<Vec<N>> for Dirichlet<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec<N> { - let n = self.alpha.len(); - let mut samples = vec![N::from(0.0); n]; - let mut sum = N::from(0.0); - - for (s, &a) in samples.iter_mut().zip(self.alpha.iter()) { - let g = Gamma::new(a, N::from(1.0)).unwrap(); - *s = g.sample(rng); - sum += *s; - } - let invacc = N::from(1.0) / sum; - for s in samples.iter_mut() { - *s *= 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]).unwrap(); - 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_size(alpha, size).unwrap(); - 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_size(0.5f64, 1).unwrap(); - } - - #[test] - #[should_panic] - fn test_dirichlet_invalid_alpha() { - Dirichlet::new_with_size(0.0f64, 2).unwrap(); - } -} diff --git a/rand/rand_distr/src/exponential.rs b/rand/rand_distr/src/exponential.rs deleted file mode 100644 index 8322489..0000000 --- a/rand/rand_distr/src/exponential.rs +++ /dev/null @@ -1,145 +0,0 @@ -// 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, Float}; - -/// 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 = thread_rng().sample(Exp1); -/// println!("{}", val); -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct Exp1; - -impl Distribution<f32> for Exp1 { - #[inline] - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f32 { - // TODO: use optimal 32-bit implementation - let x: f64 = self.sample(rng); - x as f32 - } -} - -// 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).unwrap(); -/// let v = exp.sample(&mut rand::thread_rng()); -/// println!("{} is from a Exp(2) distribution", v); -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct Exp<N> { - /// `lambda` stored as `1/lambda`, since this is what we scale by. - lambda_inverse: N -} - -/// Error type returned from `Exp::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Error { - /// `lambda <= 0` or `nan`. - LambdaTooSmall, -} - -impl<N: Float> Exp<N> -where Exp1: Distribution<N> -{ - /// Construct a new `Exp` with the given shape parameter - /// `lambda`. - #[inline] - pub fn new(lambda: N) -> Result<Exp<N>, Error> { - if !(lambda > N::from(0.0)) { - return Err(Error::LambdaTooSmall); - } - Ok(Exp { lambda_inverse: N::from(1.0) / lambda }) - } -} - -impl<N: Float> Distribution<N> for Exp<N> -where Exp1: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - rng.sample(Exp1) * self.lambda_inverse - } -} - -#[cfg(test)] -mod test { - use crate::Distribution; - use super::Exp; - - #[test] - fn test_exp() { - let exp = Exp::new(10.0).unwrap(); - 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).unwrap(); - } - #[test] - #[should_panic] - fn test_exp_invalid_lambda_neg() { - Exp::new(-10.0).unwrap(); - } -} diff --git a/rand/rand_distr/src/gamma.rs b/rand/rand_distr/src/gamma.rs deleted file mode 100644 index 4018361..0000000 --- a/rand/rand_distr/src/gamma.rs +++ /dev/null @@ -1,485 +0,0 @@ -// 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, Exp1, Exp, Open01}; -use crate::utils::Float; - -/// 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).unwrap(); -/// 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<N> { - repr: GammaRepr<N>, -} - -/// Error type returned from `Gamma::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Error { - /// `shape <= 0` or `nan`. - ShapeTooSmall, - /// `scale <= 0` or `nan`. - ScaleTooSmall, - /// `1 / scale == 0`. - ScaleTooLarge, -} - -#[derive(Clone, Copy, Debug)] -enum GammaRepr<N> { - Large(GammaLargeShape<N>), - One(Exp<N>), - Small(GammaSmallShape<N>) -} - -// 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<N> { - inv_shape: N, - large_shape: GammaLargeShape<N> -} - -/// 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<N> { - scale: N, - c: N, - d: N -} - -impl<N: Float> Gamma<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - /// Construct an object representing the `Gamma(shape, scale)` - /// distribution. - #[inline] - pub fn new(shape: N, scale: N) -> Result<Gamma<N>, Error> { - if !(shape > N::from(0.0)) { - return Err(Error::ShapeTooSmall); - } - if !(scale > N::from(0.0)) { - return Err(Error::ScaleTooSmall); - } - - let repr = if shape == N::from(1.0) { - One(Exp::new(N::from(1.0) / scale).map_err(|_| Error::ScaleTooLarge)?) - } else if shape < N::from(1.0) { - Small(GammaSmallShape::new_raw(shape, scale)) - } else { - Large(GammaLargeShape::new_raw(shape, scale)) - }; - Ok(Gamma { repr }) - } -} - -impl<N: Float> GammaSmallShape<N> -where StandardNormal: Distribution<N>, Open01: Distribution<N> -{ - fn new_raw(shape: N, scale: N) -> GammaSmallShape<N> { - GammaSmallShape { - inv_shape: N::from(1.0) / shape, - large_shape: GammaLargeShape::new_raw(shape + N::from(1.0), scale) - } - } -} - -impl<N: Float> GammaLargeShape<N> -where StandardNormal: Distribution<N>, Open01: Distribution<N> -{ - fn new_raw(shape: N, scale: N) -> GammaLargeShape<N> { - let d = shape - N::from(1. / 3.); - GammaLargeShape { - scale, - c: N::from(1.0) / (N::from(9.) * d).sqrt(), - d - } - } -} - -impl<N: Float> Distribution<N> for Gamma<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - match self.repr { - Small(ref g) => g.sample(rng), - One(ref g) => g.sample(rng), - Large(ref g) => g.sample(rng), - } - } -} -impl<N: Float> Distribution<N> for GammaSmallShape<N> -where StandardNormal: Distribution<N>, Open01: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - let u: N = rng.sample(Open01); - - self.large_shape.sample(rng) * u.powf(self.inv_shape) - } -} -impl<N: Float> Distribution<N> for GammaLargeShape<N> -where StandardNormal: Distribution<N>, Open01: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - // Marsaglia & Tsang method, 2000 - loop { - let x: N = rng.sample(StandardNormal); - let v_cbrt = N::from(1.0) + self.c * x; - if v_cbrt <= N::from(0.0) { // a^3 <= 0 iff a <= 0 - continue - } - - let v = v_cbrt * v_cbrt * v_cbrt; - let u: N = rng.sample(Open01); - - let x_sqr = x * x; - if u < N::from(1.0) - N::from(0.0331) * x_sqr * x_sqr || - u.ln() < N::from(0.5) * x_sqr + self.d * (N::from(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).unwrap(); -/// let v = chi.sample(&mut rand::thread_rng()); -/// println!("{} is from a χ²(11) distribution", v) -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct ChiSquared<N> { - repr: ChiSquaredRepr<N>, -} - -/// Error type returned from `ChiSquared::new` and `StudentT::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum ChiSquaredError { - /// `0.5 * k <= 0` or `nan`. - DoFTooSmall, -} - -#[derive(Clone, Copy, Debug)] -enum ChiSquaredRepr<N> { - // 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<N>), -} - -impl<N: Float> ChiSquared<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - /// Create a new chi-squared distribution with degrees-of-freedom - /// `k`. - pub fn new(k: N) -> Result<ChiSquared<N>, ChiSquaredError> { - let repr = if k == N::from(1.0) { - DoFExactlyOne - } else { - if !(N::from(0.5) * k > N::from(0.0)) { - return Err(ChiSquaredError::DoFTooSmall); - } - DoFAnythingElse(Gamma::new(N::from(0.5) * k, N::from(2.0)).unwrap()) - }; - Ok(ChiSquared { repr }) - } -} -impl<N: Float> Distribution<N> for ChiSquared<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - match self.repr { - DoFExactlyOne => { - // k == 1 => N(0,1)^2 - let norm: N = 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).unwrap(); -/// let v = f.sample(&mut rand::thread_rng()); -/// println!("{} is from an F(2, 32) distribution", v) -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct FisherF<N> { - numer: ChiSquared<N>, - denom: ChiSquared<N>, - // denom_dof / numer_dof so that this can just be a straight - // multiplication, rather than a division. - dof_ratio: N, -} - -/// Error type returned from `FisherF::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum FisherFError { - /// `m <= 0` or `nan`. - MTooSmall, - /// `n <= 0` or `nan`. - NTooSmall, -} - -impl<N: Float> FisherF<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - /// Create a new `FisherF` distribution, with the given parameter. - pub fn new(m: N, n: N) -> Result<FisherF<N>, FisherFError> { - if !(m > N::from(0.0)) { - return Err(FisherFError::MTooSmall); - } - if !(n > N::from(0.0)) { - return Err(FisherFError::NTooSmall); - } - - Ok(FisherF { - numer: ChiSquared::new(m).unwrap(), - denom: ChiSquared::new(n).unwrap(), - dof_ratio: n / m - }) - } -} -impl<N: Float> Distribution<N> for FisherF<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - 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).unwrap(); -/// let v = t.sample(&mut rand::thread_rng()); -/// println!("{} is from a t(11) distribution", v) -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct StudentT<N> { - chi: ChiSquared<N>, - dof: N -} - -impl<N: Float> StudentT<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - /// Create a new Student t distribution with `n` degrees of - /// freedom. - pub fn new(n: N) -> Result<StudentT<N>, ChiSquaredError> { - Ok(StudentT { - chi: ChiSquared::new(n)?, - dof: n - }) - } -} -impl<N: Float> Distribution<N> for StudentT<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - let norm: N = 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).unwrap(); -/// let v = beta.sample(&mut rand::thread_rng()); -/// println!("{} is from a Beta(2, 5) distribution", v); -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct Beta<N> { - gamma_a: Gamma<N>, - gamma_b: Gamma<N>, -} - -/// Error type returned from `Beta::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum BetaError { - /// `alpha <= 0` or `nan`. - AlphaTooSmall, - /// `beta <= 0` or `nan`. - BetaTooSmall, -} - -impl<N: Float> Beta<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - /// Construct an object representing the `Beta(alpha, beta)` - /// distribution. - pub fn new(alpha: N, beta: N) -> Result<Beta<N>, BetaError> { - Ok(Beta { - gamma_a: Gamma::new(alpha, N::from(1.)) - .map_err(|_| BetaError::AlphaTooSmall)?, - gamma_b: Gamma::new(beta, N::from(1.)) - .map_err(|_| BetaError::BetaTooSmall)?, - }) - } -} - -impl<N: Float> Distribution<N> for Beta<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - 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).unwrap(); - 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).unwrap(); - 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).unwrap(); - 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).unwrap(); - } - - #[test] - fn test_f() { - let f = FisherF::new(2.0, 32.0).unwrap(); - 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).unwrap(); - 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).unwrap(); - 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.).unwrap(); - } -} diff --git a/rand/rand_distr/src/lib.rs b/rand/rand_distr/src/lib.rs deleted file mode 100644 index baf65ed..0000000 --- a/rand/rand_distr/src/lib.rs +++ /dev/null @@ -1,134 +0,0 @@ -// 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)] - -#![allow(clippy::excessive_precision, clippy::float_cmp, clippy::unreadable_literal)] -#![allow(clippy::neg_cmp_op_on_partial_ord)] // suggested fix too verbose - -//! 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 -//! - [`UnitSphere`] distribution -//! - [`UnitBall`] distribution -//! - [`UnitCircle`] distribution -//! - [`UnitDisc`] distribution - -pub use rand::distributions::{Distribution, DistIter, Standard, - Alphanumeric, Uniform, OpenClosed01, Open01, Bernoulli, uniform, weighted}; - -pub use self::unit_sphere::UnitSphere; -pub use self::unit_ball::UnitBall; -pub use self::unit_circle::UnitCircle; -pub use self::unit_disc::UnitDisc; -pub use self::gamma::{Gamma, Error as GammaError, ChiSquared, ChiSquaredError, - FisherF, FisherFError, StudentT, Beta, BetaError}; -pub use self::normal::{Normal, Error as NormalError, LogNormal, StandardNormal}; -pub use self::exponential::{Exp, Error as ExpError, Exp1}; -pub use self::pareto::{Pareto, Error as ParetoError}; -pub use self::pert::{Pert, PertError}; -pub use self::poisson::{Poisson, Error as PoissonError}; -pub use self::binomial::{Binomial, Error as BinomialError}; -pub use self::cauchy::{Cauchy, Error as CauchyError}; -pub use self::dirichlet::{Dirichlet, Error as DirichletError}; -pub use self::triangular::{Triangular, TriangularError}; -pub use self::weibull::{Weibull, Error as WeibullError}; -pub use self::utils::Float; - -mod unit_sphere; -mod unit_ball; -mod unit_circle; -mod unit_disc; -mod gamma; -mod normal; -mod exponential; -mod pareto; -mod pert; -mod poisson; -mod binomial; -mod cauchy; -mod dirichlet; -mod triangular; -mod weibull; -mod utils; -mod ziggurat_tables; - -#[cfg(test)] -mod test { - // Notes on testing - // - // Testing random number distributions correctly is hard. The following - // testing is desired: - // - // - Construction: test initialisation with a few valid parameter sets. - // - Erroneous usage: test that incorrect usage generates an error. - // - Vector: test that usage with fixed inputs (including RNG) generates a - // fixed output sequence on all platforms. - // - Correctness at fixed points (optional): using a specific mock RNG, - // check that specific values are sampled (e.g. end-points and median of - // distribution). - // - Correctness of PDF (extra): generate a histogram of samples within a - // certain range, and check this approximates the PDF. These tests are - // expected to be expensive, and should be behind a feature-gate. - // - // TODO: Vector and correctness tests are largely absent so far. - // NOTE: Some distributions have tests checking only that samples can be - // generated. This is redundant with vector and correctness tests. - - /// Construct a deterministic RNG with the given seed - pub fn rng(seed: u64) -> impl rand::RngCore { - // For tests, we want a statistically good, fast, reproducible RNG. - // PCG32 will do fine, and will be easy to embed if we ever need to. - const INC: u64 = 11634580027462260723; - rand_pcg::Pcg32::new(seed, INC) - } -} diff --git a/rand/rand_distr/src/normal.rs b/rand/rand_distr/src/normal.rs deleted file mode 100644 index 882754f..0000000 --- a/rand/rand_distr/src/normal.rs +++ /dev/null @@ -1,219 +0,0 @@ -// 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, Float}; - -/// 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 = thread_rng().sample(StandardNormal); -/// println!("{}", val); -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct StandardNormal; - -impl Distribution<f32> for StandardNormal { - #[inline] - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f32 { - // TODO: use optimal 32-bit implementation - let x: f64 = self.sample(rng); - x as f32 - } -} - -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).unwrap(); -/// 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<N> { - mean: N, - std_dev: N, -} - -/// Error type returned from `Normal::new` and `LogNormal::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Error { - /// `std_dev < 0` or `nan`. - StdDevTooSmall, -} - -impl<N: Float> Normal<N> -where StandardNormal: Distribution<N> -{ - /// Construct a new `Normal` distribution with the given mean and - /// standard deviation. - #[inline] - pub fn new(mean: N, std_dev: N) -> Result<Normal<N>, Error> { - if !(std_dev >= N::from(0.0)) { - return Err(Error::StdDevTooSmall); - } - Ok(Normal { - mean, - std_dev - }) - } -} - -impl<N: Float> Distribution<N> for Normal<N> -where StandardNormal: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - let n: 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).unwrap(); -/// 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<N> { - norm: Normal<N> -} - -impl<N: Float> LogNormal<N> -where StandardNormal: Distribution<N> -{ - /// Construct a new `LogNormal` distribution with the given mean - /// and standard deviation of the logarithm of the distribution. - #[inline] - pub fn new(mean: N, std_dev: N) -> Result<LogNormal<N>, Error> { - if !(std_dev >= N::from(0.0)) { - return Err(Error::StdDevTooSmall); - } - Ok(LogNormal { norm: Normal::new(mean, std_dev).unwrap() }) - } -} - -impl<N: Float> Distribution<N> for LogNormal<N> -where StandardNormal: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - 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).unwrap(); - 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).unwrap(); - } - - - #[test] - fn test_log_normal() { - let lnorm = LogNormal::new(10.0, 10.0).unwrap(); - 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).unwrap(); - } -} diff --git a/rand/rand_distr/src/pareto.rs b/rand/rand_distr/src/pareto.rs deleted file mode 100644 index 33ea382..0000000 --- a/rand/rand_distr/src/pareto.rs +++ /dev/null @@ -1,89 +0,0 @@ -// 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}; -use crate::utils::Float; - -/// Samples floating-point numbers according to the Pareto distribution -/// -/// # Example -/// ``` -/// use rand::prelude::*; -/// use rand_distr::Pareto; -/// -/// let val: f64 = thread_rng().sample(Pareto::new(1., 2.).unwrap()); -/// println!("{}", val); -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct Pareto<N> { - scale: N, - inv_neg_shape: N, -} - -/// Error type returned from `Pareto::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Error { - /// `scale <= 0` or `nan`. - ScaleTooSmall, - /// `shape <= 0` or `nan`. - ShapeTooSmall, -} - -impl<N: Float> Pareto<N> -where OpenClosed01: Distribution<N> -{ - /// 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 α. - pub fn new(scale: N, shape: N) -> Result<Pareto<N>, Error> { - if !(scale > N::from(0.0)) { - return Err(Error::ScaleTooSmall); - } - if !(shape > N::from(0.0)) { - return Err(Error::ShapeTooSmall); - } - Ok(Pareto { scale, inv_neg_shape: N::from(-1.0) / shape }) - } -} - -impl<N: Float> Distribution<N> for Pareto<N> -where OpenClosed01: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - let u: N = OpenClosed01.sample(rng); - 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.).unwrap(); - } - - #[test] - fn sample() { - let scale = 1.0; - let shape = 2.0; - let d = Pareto::new(scale, shape).unwrap(); - let mut rng = crate::test::rng(1); - for _ in 0..1000 { - let r = d.sample(&mut rng); - assert!(r >= scale); - } - } -} diff --git a/rand/rand_distr/src/pert.rs b/rand/rand_distr/src/pert.rs deleted file mode 100644 index 040cd05..0000000 --- a/rand/rand_distr/src/pert.rs +++ /dev/null @@ -1,132 +0,0 @@ -// 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 PERT distribution. - -use rand::Rng; -use crate::{Distribution, Beta, StandardNormal, Exp1, Open01}; -use crate::utils::Float; - -/// The PERT distribution. -/// -/// Similar to the [`Triangular`] distribution, the PERT distribution is -/// parameterised by a range and a mode within that range. Unlike the -/// [`Triangular`] distribution, the probability density function of the PERT -/// distribution is smooth, with a configurable weighting around the mode. -/// -/// # Example -/// -/// ```rust -/// use rand_distr::{Pert, Distribution}; -/// -/// let d = Pert::new(0., 5., 2.5).unwrap(); -/// let v = d.sample(&mut rand::thread_rng()); -/// println!("{} is from a PERT distribution", v); -/// ``` -/// -/// [`Triangular`]: crate::Triangular -#[derive(Clone, Copy, Debug)] -pub struct Pert<N> { - min: N, - range: N, - beta: Beta<N>, -} - -/// Error type returned from [`Pert`] constructors. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum PertError { - /// `max < min` or `min` or `max` is NaN. - RangeTooSmall, - /// `mode < min` or `mode > max` or `mode` is NaN. - ModeRange, - /// `shape < 0` or `shape` is NaN - ShapeTooSmall, -} - -impl<N: Float> Pert<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - /// Set up the PERT distribution with defined `min`, `max` and `mode`. - /// - /// This is equivalent to calling `Pert::new_shape` with `shape == 4.0`. - #[inline] - pub fn new(min: N, max: N, mode: N) -> Result<Pert<N>, PertError> { - Pert::new_with_shape(min, max, mode, N::from(4.)) - } - - /// Set up the PERT distribution with defined `min`, `max`, `mode` and - /// `shape`. - pub fn new_with_shape(min: N, max: N, mode: N, shape: N) -> Result<Pert<N>, PertError> { - if !(max > min) { - return Err(PertError::RangeTooSmall); - } - if !(mode >= min && max >= mode) { - return Err(PertError::ModeRange); - } - if !(shape >= N::from(0.)) { - return Err(PertError::ShapeTooSmall); - } - - let range = max - min; - let mu = (min + max + shape * mode) / (shape + N::from(2.)); - let v = if mu == mode { - shape * N::from(0.5) + N::from(1.) - } else { - (mu - min) * (N::from(2.) * mode - min - max) - / ((mode - mu) * (max - min)) - }; - let w = v * (max - mu) / (mu - min); - let beta = Beta::new(v, w).map_err(|_| PertError::RangeTooSmall)?; - Ok(Pert{ min, range, beta }) - } -} - -impl<N: Float> Distribution<N> for Pert<N> -where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N> -{ - #[inline] - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - self.beta.sample(rng) * self.range + self.min - } -} - -#[cfg(test)] -mod test { - use std::f64; - use super::*; - - #[test] - fn test_pert() { - for &(min, max, mode) in &[ - (-1., 1., 0.), - (1., 2., 1.), - (5., 25., 25.), - ] { - let _distr = Pert::new(min, max, mode).unwrap(); - // TODO: test correctness - } - - for &(min, max, mode) in &[ - (-1., 1., 2.), - (-1., 1., -2.), - (2., 1., 1.), - ] { - assert!(Pert::new(min, max, mode).is_err()); - } - } - - #[test] - fn value_stability() { - let rng = crate::test::rng(860); - let distr = Pert::new(2., 10., 3.).unwrap(); // mean = 4, var = 12/7 - let seq = distr.sample_iter(rng).take(5).collect::<Vec<f64>>(); - println!("seq: {:?}", seq); - let expected = vec![4.631484136029422, 3.307201472321789, - 3.29995019556348, 3.66835483991721, 3.514246139933899]; - assert!(seq == expected); - } -} diff --git a/rand/rand_distr/src/poisson.rs b/rand/rand_distr/src/poisson.rs deleted file mode 100644 index 4f4a0b7..0000000 --- a/rand/rand_distr/src/poisson.rs +++ /dev/null @@ -1,233 +0,0 @@ -// 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, Standard}; -use crate::utils::Float; - -/// 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).unwrap(); -/// let v: u64 = poi.sample(&mut rand::thread_rng()); -/// println!("{} is from a Poisson(2) distribution", v); -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct Poisson<N> { - lambda: N, - // precalculated values - exp_lambda: N, - log_lambda: N, - sqrt_2lambda: N, - magic_val: N, -} - -/// Error type returned from `Poisson::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Error { - /// `lambda <= 0` or `nan`. - ShapeTooSmall, -} - -impl<N: Float> Poisson<N> -where Standard: Distribution<N> -{ - /// Construct a new `Poisson` with the given shape parameter - /// `lambda`. - pub fn new(lambda: N) -> Result<Poisson<N>, Error> { - if !(lambda > N::from(0.0)) { - return Err(Error::ShapeTooSmall); - } - let log_lambda = lambda.ln(); - Ok(Poisson { - lambda, - exp_lambda: (-lambda).exp(), - log_lambda, - sqrt_2lambda: (N::from(2.0) * lambda).sqrt(), - magic_val: lambda * log_lambda - (N::from(1.0) + lambda).log_gamma(), - }) - } -} - -impl<N: Float> Distribution<N> for Poisson<N> -where Standard: Distribution<N> -{ - #[inline] - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - // using the algorithm from Numerical Recipes in C - - // for low expected values use the Knuth method - if self.lambda < N::from(12.0) { - let mut result = N::from(0.); - let mut p = N::from(1.0); - while p > self.exp_lambda { - p *= rng.gen::<N>(); - result += N::from(1.); - } - result - N::from(1.) - } - // high expected values - rejection method - else { - // we use the Cauchy distribution as the comparison distribution - // f(x) ~ 1/(1+x^2) - let cauchy = Cauchy::new(N::from(0.0), N::from(1.0)).unwrap(); - let mut result; - - loop { - 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 >= N::from(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(); - - // 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 = N::from(0.9) * (N::from(1.0) + comp_dev * comp_dev) - * (result * self.log_lambda - (N::from(1.0) + result).log_gamma() - self.magic_val).exp(); - - // check with uniform random value - if below the threshold, we are within the target distribution - if rng.gen::<N>() <= check { - break; - } - } - result - } - } -} - -impl<N: Float> Distribution<u64> for Poisson<N> -where Standard: Distribution<N> -{ - #[inline] - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 { - let result: N = self.sample(rng); - result.to_u64().unwrap() - } -} - -#[cfg(test)] -mod test { - use crate::Distribution; - use super::Poisson; - - #[test] - fn test_poisson_10() { - let poisson = Poisson::new(10.0).unwrap(); - let mut rng = crate::test::rng(123); - let mut sum_u64 = 0; - let mut sum_f64 = 0.; - for _ in 0..1000 { - let s_u64: u64 = poisson.sample(&mut rng); - let s_f64: f64 = poisson.sample(&mut rng); - sum_u64 += s_u64; - sum_f64 += s_f64; - } - let avg_u64 = (sum_u64 as f64) / 1000.0; - let avg_f64 = sum_f64 / 1000.0; - println!("Poisson averages: {} (u64) {} (f64)", avg_u64, avg_f64); - for &avg in &[avg_u64, avg_f64] { - 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).unwrap(); - let mut rng = crate::test::rng(123); - let mut sum_u64 = 0; - let mut sum_f64 = 0.; - for _ in 0..1000 { - let s_u64: u64 = poisson.sample(&mut rng); - let s_f64: f64 = poisson.sample(&mut rng); - sum_u64 += s_u64; - sum_f64 += s_f64; - } - let avg_u64 = (sum_u64 as f64) / 1000.0; - let avg_f64 = sum_f64 / 1000.0; - println!("Poisson average: {} (u64) {} (f64)", avg_u64, avg_f64); - for &avg in &[avg_u64, avg_f64] { - assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough - } - } - - #[test] - fn test_poisson_10_f32() { - let poisson = Poisson::new(10.0f32).unwrap(); - let mut rng = crate::test::rng(123); - let mut sum_u64 = 0; - let mut sum_f32 = 0.; - for _ in 0..1000 { - let s_u64: u64 = poisson.sample(&mut rng); - let s_f32: f32 = poisson.sample(&mut rng); - sum_u64 += s_u64; - sum_f32 += s_f32; - } - let avg_u64 = (sum_u64 as f32) / 1000.0; - let avg_f32 = sum_f32 / 1000.0; - println!("Poisson averages: {} (u64) {} (f32)", avg_u64, avg_f32); - for &avg in &[avg_u64, avg_f32] { - assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough - } - } - - #[test] - fn test_poisson_15_f32() { - // Take the 'high expected values' path - let poisson = Poisson::new(15.0f32).unwrap(); - let mut rng = crate::test::rng(123); - let mut sum_u64 = 0; - let mut sum_f32 = 0.; - for _ in 0..1000 { - let s_u64: u64 = poisson.sample(&mut rng); - let s_f32: f32 = poisson.sample(&mut rng); - sum_u64 += s_u64; - sum_f32 += s_f32; - } - let avg_u64 = (sum_u64 as f32) / 1000.0; - let avg_f32 = sum_f32 / 1000.0; - println!("Poisson average: {} (u64) {} (f32)", avg_u64, avg_f32); - for &avg in &[avg_u64, avg_f32] { - 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).unwrap(); - } - - #[test] - #[should_panic] - fn test_poisson_invalid_lambda_neg() { - Poisson::new(-10.0).unwrap(); - } -} diff --git a/rand/rand_distr/src/triangular.rs b/rand/rand_distr/src/triangular.rs deleted file mode 100644 index dd0bbfb..0000000 --- a/rand/rand_distr/src/triangular.rs +++ /dev/null @@ -1,125 +0,0 @@ -// 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}; -use crate::utils::Float; - -/// The triangular distribution. -/// -/// A continuous probability distribution parameterised by a range, and a mode -/// (most likely value) within that range. -/// -/// The probability density function is triangular. For a similar distribution -/// with a smooth PDF, see the [`Pert`] distribution. -/// -/// # Example -/// -/// ```rust -/// use rand_distr::{Triangular, Distribution}; -/// -/// let d = Triangular::new(0., 5., 2.5).unwrap(); -/// let v = d.sample(&mut rand::thread_rng()); -/// println!("{} is from a triangular distribution", v); -/// ``` -/// -/// [`Pert`]: crate::Pert -#[derive(Clone, Copy, Debug)] -pub struct Triangular<N> { - min: N, - max: N, - mode: N, -} - -/// Error type returned from [`Triangular::new`]. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum TriangularError { - /// `max < min` or `min` or `max` is NaN. - RangeTooSmall, - /// `mode < min` or `mode > max` or `mode` is NaN. - ModeRange, -} - -impl<N: Float> Triangular<N> -where Standard: Distribution<N> -{ - /// Set up the Triangular distribution with defined `min`, `max` and `mode`. - #[inline] - pub fn new(min: N, max: N, mode: N) -> Result<Triangular<N>, TriangularError> { - if !(max >= min) { - return Err(TriangularError::RangeTooSmall); - } - if !(mode >= min && max >= mode) { - return Err(TriangularError::ModeRange); - } - Ok(Triangular { min, max, mode }) - } -} - -impl<N: Float> Distribution<N> for Triangular<N> -where Standard: Distribution<N> -{ - #[inline] - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - let f: N = rng.sample(Standard); - let diff_mode_min = self.mode - self.min; - let range = self.max - self.min; - let f_range = f * range; - if f_range < diff_mode_min { - self.min + (f_range * diff_mode_min).sqrt() - } else { - self.max - ((range - f_range) * (self.max - self.mode)).sqrt() - } - } -} - -#[cfg(test)] -mod test { - use std::f64; - use rand::{Rng, rngs::mock}; - use super::*; - - #[test] - fn test_triangular() { - let mut half_rng = mock::StepRng::new(0x8000_0000_0000_0000, 0); - assert_eq!(half_rng.gen::<f64>(), 0.5); - for &(min, max, mode, median) in &[ - (-1., 1., 0., 0.), - (1., 2., 1., 2. - 0.5f64.sqrt()), - (5., 25., 25., 5. + 200f64.sqrt()), - (1e-5, 1e5, 1e-3, 1e5 - 4999999949.5f64.sqrt()), - (0., 1., 0.9, 0.45f64.sqrt()), - (-4., -0.5, -2., -4.0 + 3.5f64.sqrt()), - ] { - println!("{} {} {} {}", min, max, mode, median); - let distr = Triangular::new(min, max, mode).unwrap(); - // Test correct value at median: - assert_eq!(distr.sample(&mut half_rng), median); - } - - for &(min, max, mode) in &[ - (-1., 1., 2.), - (-1., 1., -2.), - (2., 1., 1.), - ] { - assert!(Triangular::new(min, max, mode).is_err()); - } - } - - #[test] - fn value_stability() { - let rng = crate::test::rng(860); - let distr = Triangular::new(2., 10., 3.).unwrap(); - let seq = distr.sample_iter(rng).take(5).collect::<Vec<f64>>(); - println!("seq: {:?}", seq); - let expected = vec![5.74373257511361, 7.890059162791258, - 4.7256280652553455, 2.9474808121184077, 3.058301946314053]; - assert!(seq == expected); - } -} diff --git a/rand/rand_distr/src/unit_ball.rs b/rand/rand_distr/src/unit_ball.rs deleted file mode 100644 index 9d61627..0000000 --- a/rand/rand_distr/src/unit_ball.rs +++ /dev/null @@ -1,69 +0,0 @@ -// 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. - -use rand::Rng; -use crate::{Distribution, Uniform, uniform::SampleUniform}; -use crate::utils::Float; - -/// Samples uniformly from the unit ball (surface and interior) in three -/// dimensions. -/// -/// Implemented via rejection sampling. -/// -/// -/// # Example -/// -/// ``` -/// use rand_distr::{UnitBall, Distribution}; -/// -/// let v: [f64; 3] = UnitBall.sample(&mut rand::thread_rng()); -/// println!("{:?} is from the unit ball.", v) -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct UnitBall; - -impl<N: Float + SampleUniform> Distribution<[N; 3]> for UnitBall { - #[inline] - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [N; 3] { - let uniform = Uniform::new(N::from(-1.), N::from(1.)); - let mut x1; - let mut x2; - let mut x3; - loop { - x1 = uniform.sample(rng); - x2 = uniform.sample(rng); - x3 = uniform.sample(rng); - if x1*x1 + x2*x2 + x3*x3 <= N::from(1.) { - break; - } - } - [x1, x2, x3] - } -} - -#[cfg(test)] -mod tests { - use crate::Distribution; - use super::UnitBall; - - #[test] - fn value_stability() { - let mut rng = crate::test::rng(2); - let expected = [ - [0.018035709265959987, -0.4348771383120438, -0.07982762085055706], - [0.10588569388223945, -0.4734350111375454, -0.7392104908825501], - [0.11060237642041049, -0.16065642822852677, -0.8444043930440075] - ]; - let samples: [[f64; 3]; 3] = [ - UnitBall.sample(&mut rng), - UnitBall.sample(&mut rng), - UnitBall.sample(&mut rng), - ]; - assert_eq!(samples, expected); - } -} diff --git a/rand/rand_distr/src/unit_circle.rs b/rand/rand_distr/src/unit_circle.rs deleted file mode 100644 index 5863a1a..0000000 --- a/rand/rand_distr/src/unit_circle.rs +++ /dev/null @@ -1,99 +0,0 @@ -// 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, uniform::SampleUniform}; -use crate::utils::Float; - -/// 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 v: [f64; 2] = UnitCircle.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<N: Float + SampleUniform> Distribution<[N; 2]> for UnitCircle { - #[inline] - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [N; 2] { - let uniform = Uniform::new(N::from(-1.), N::from(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 < N::from(1.) { - break; - } - } - let diff = x1*x1 - x2*x2; - [diff / sum, N::from(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); - for _ in 0..1000 { - let x: [f64; 2] = UnitCircle.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 expected = [ - [-0.9965658683520504, -0.08280380447614634], - [-0.9790853270389644, -0.20345004884984505], - [-0.8449189758898707, 0.5348943112253227], - ]; - let samples: [[f64; 2]; 3] = [ - UnitCircle.sample(&mut rng), - UnitCircle.sample(&mut rng), - UnitCircle.sample(&mut rng), - ]; - assert_eq!(samples, expected); - } -} diff --git a/rand/rand_distr/src/unit_disc.rs b/rand/rand_distr/src/unit_disc.rs deleted file mode 100644 index 97abc2f..0000000 --- a/rand/rand_distr/src/unit_disc.rs +++ /dev/null @@ -1,66 +0,0 @@ -// 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. - -use rand::Rng; -use crate::{Distribution, Uniform, uniform::SampleUniform}; -use crate::utils::Float; - -/// Samples uniformly from the unit disc in two dimensions. -/// -/// Implemented via rejection sampling. -/// -/// -/// # Example -/// -/// ``` -/// use rand_distr::{UnitDisc, Distribution}; -/// -/// let v: [f64; 2] = UnitDisc.sample(&mut rand::thread_rng()); -/// println!("{:?} is from the unit Disc.", v) -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct UnitDisc; - -impl<N: Float + SampleUniform> Distribution<[N; 2]> for UnitDisc { - #[inline] - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [N; 2] { - let uniform = Uniform::new(N::from(-1.), N::from(1.)); - let mut x1; - let mut x2; - loop { - x1 = uniform.sample(rng); - x2 = uniform.sample(rng); - if x1*x1 + x2*x2 <= N::from(1.) { - break; - } - } - [x1, x2] - } -} - -#[cfg(test)] -mod tests { - use crate::Distribution; - use super::UnitDisc; - - #[test] - fn value_stability() { - let mut rng = crate::test::rng(2); - let expected = [ - [0.018035709265959987, -0.4348771383120438], - [-0.07982762085055706, 0.7765329819820659], - [0.21450745997299503, 0.7398636984333291] - ]; - let samples: [[f64; 2]; 3] = [ - UnitDisc.sample(&mut rng), - UnitDisc.sample(&mut rng), - UnitDisc.sample(&mut rng), - ]; - assert_eq!(samples, expected); - } -} diff --git a/rand/rand_distr/src/unit_sphere.rs b/rand/rand_distr/src/unit_sphere.rs deleted file mode 100644 index 8e0c361..0000000 --- a/rand/rand_distr/src/unit_sphere.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2018-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. - -use rand::Rng; -use crate::{Distribution, Uniform, uniform::SampleUniform}; -use crate::utils::Float; - -/// Samples uniformly from the surface of the unit sphere in three dimensions. -/// -/// Implemented via a method by Marsaglia[^1]. -/// -/// -/// # Example -/// -/// ``` -/// use rand_distr::{UnitSphere, Distribution}; -/// -/// let v: [f64; 3] = UnitSphere.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 UnitSphere; - -impl<N: Float + SampleUniform> Distribution<[N; 3]> for UnitSphere { - #[inline] - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [N; 3] { - let uniform = Uniform::new(N::from(-1.), N::from(1.)); - loop { - let (x1, x2) = (uniform.sample(rng), uniform.sample(rng)); - let sum = x1*x1 + x2*x2; - if sum >= N::from(1.) { - continue; - } - let factor = N::from(2.) * (N::from(1.0) - sum).sqrt(); - return [x1 * factor, x2 * factor, N::from(1.) - N::from(2.)*sum]; - } - } -} - -#[cfg(test)] -mod tests { - use crate::Distribution; - use super::UnitSphere; - - /// 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); - for _ in 0..1000 { - let x: [f64; 3] = UnitSphere.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 expected = [ - [0.03247542860231647, -0.7830477442152738, 0.6211131755296027], - [-0.09978440840914075, 0.9706650829833128, -0.21875184231323952], - [0.2735582468624679, 0.9435374242279655, -0.1868234852870203], - ]; - let samples: [[f64; 3]; 3] = [ - UnitSphere.sample(&mut rng), - UnitSphere.sample(&mut rng), - UnitSphere.sample(&mut rng), - ]; - assert_eq!(samples, expected); - } -} diff --git a/rand/rand_distr/src/utils.rs b/rand/rand_distr/src/utils.rs deleted file mode 100644 index 75b3500..0000000 --- a/rand/rand_distr/src/utils.rs +++ /dev/null @@ -1,234 +0,0 @@ -// 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; -use core::{cmp, ops}; - -/// Trait for floating-point scalar types -/// -/// This allows many distributions to work with `f32` or `f64` parameters and is -/// potentially extensible. Note however that the `Exp1` and `StandardNormal` -/// distributions are implemented exclusively for `f32` and `f64`. -/// -/// The bounds and methods are based purely on internal -/// requirements, and will change as needed. -pub trait Float: Copy + Sized + cmp::PartialOrd - + ops::Neg<Output = Self> - + ops::Add<Output = Self> - + ops::Sub<Output = Self> - + ops::Mul<Output = Self> - + ops::Div<Output = Self> - + ops::AddAssign + ops::SubAssign + ops::MulAssign + ops::DivAssign -{ - /// The constant π - fn pi() -> Self; - /// Support approximate representation of a f64 value - fn from(x: f64) -> Self; - /// Support converting to an unsigned integer. - fn to_u64(self) -> Option<u64>; - - /// Take the absolute value of self - fn abs(self) -> Self; - /// Take the largest integer less than or equal to self - fn floor(self) -> Self; - - /// Take the exponential of self - fn exp(self) -> Self; - /// Take the natural logarithm of self - fn ln(self) -> Self; - /// Take square root of self - fn sqrt(self) -> Self; - /// Take self to a floating-point power - fn powf(self, power: Self) -> Self; - - /// Take the tangent of self - fn tan(self) -> Self; - /// Take the logarithm of the gamma function of self - fn log_gamma(self) -> Self; -} - -impl Float for f32 { - #[inline] - fn pi() -> Self { core::f32::consts::PI } - #[inline] - fn from(x: f64) -> Self { x as f32 } - #[inline] - fn to_u64(self) -> Option<u64> { - if self >= 0. && self <= ::core::u64::MAX as f32 { - Some(self as u64) - } else { - None - } - } - - #[inline] - fn abs(self) -> Self { self.abs() } - #[inline] - fn floor(self) -> Self { self.floor() } - - #[inline] - fn exp(self) -> Self { self.exp() } - #[inline] - fn ln(self) -> Self { self.ln() } - #[inline] - fn sqrt(self) -> Self { self.sqrt() } - #[inline] - fn powf(self, power: Self) -> Self { self.powf(power) } - - #[inline] - fn tan(self) -> Self { self.tan() } - #[inline] - fn log_gamma(self) -> Self { - let result = log_gamma(self.into()); - assert!(result <= ::core::f32::MAX.into()); - assert!(result >= ::core::f32::MIN.into()); - result as f32 - } -} - -impl Float for f64 { - #[inline] - fn pi() -> Self { core::f64::consts::PI } - #[inline] - fn from(x: f64) -> Self { x } - #[inline] - fn to_u64(self) -> Option<u64> { - if self >= 0. && self <= ::core::u64::MAX as f64 { - Some(self as u64) - } else { - None - } - } - - #[inline] - fn abs(self) -> Self { self.abs() } - #[inline] - fn floor(self) -> Self { self.floor() } - - #[inline] - fn exp(self) -> Self { self.exp() } - #[inline] - fn ln(self) -> Self { self.ln() } - #[inline] - fn sqrt(self) -> Self { self.sqrt() } - #[inline] - fn powf(self, power: Self) -> Self { self.powf(power) } - - #[inline] - fn tan(self) -> Self { self.tan() } - #[inline] - fn log_gamma(self) -> Self { log_gamma(self) } -} - -/// 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(crate) 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(crate) 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; - } - } -} diff --git a/rand/rand_distr/src/weibull.rs b/rand/rand_distr/src/weibull.rs deleted file mode 100644 index ddde380..0000000 --- a/rand/rand_distr/src/weibull.rs +++ /dev/null @@ -1,86 +0,0 @@ -// 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}; -use crate::utils::Float; - -/// Samples floating-point numbers according to the Weibull distribution -/// -/// # Example -/// ``` -/// use rand::prelude::*; -/// use rand_distr::Weibull; -/// -/// let val: f64 = thread_rng().sample(Weibull::new(1., 10.).unwrap()); -/// println!("{}", val); -/// ``` -#[derive(Clone, Copy, Debug)] -pub struct Weibull<N> { - inv_shape: N, - scale: N, -} - -/// Error type returned from `Weibull::new`. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Error { - /// `scale <= 0` or `nan`. - ScaleTooSmall, - /// `shape <= 0` or `nan`. - ShapeTooSmall, -} - -impl<N: Float> Weibull<N> -where OpenClosed01: Distribution<N> -{ - /// Construct a new `Weibull` distribution with given `scale` and `shape`. - pub fn new(scale: N, shape: N) -> Result<Weibull<N>, Error> { - if !(scale > N::from(0.0)) { - return Err(Error::ScaleTooSmall); - } - if !(shape > N::from(0.0)) { - return Err(Error::ShapeTooSmall); - } - Ok(Weibull { inv_shape: N::from(1.)/shape, scale }) - } -} - -impl<N: Float> Distribution<N> for Weibull<N> -where OpenClosed01: Distribution<N> -{ - fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N { - let x: N = 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.).unwrap(); - } - - #[test] - fn sample() { - let scale = 1.0; - let shape = 2.0; - let d = Weibull::new(scale, shape).unwrap(); - let mut rng = crate::test::rng(1); - for _ in 0..1000 { - let r = d.sample(&mut rng); - assert!(r >= 0.); - } - } -} diff --git a/rand/rand_distr/src/ziggurat_tables.rs b/rand/rand_distr/src/ziggurat_tables.rs deleted file mode 100644 index ca1ce30..0000000 --- a/rand/rand_distr/src/ziggurat_tables.rs +++ /dev/null @@ -1,279 +0,0 @@ -// 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]; diff --git a/rand/rand_distr/tests/uniformity.rs b/rand/rand_distr/tests/uniformity.rs deleted file mode 100644 index d0d9d97..0000000 --- a/rand/rand_distr/tests/uniformity.rs +++ /dev/null @@ -1,59 +0,0 @@ -// 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 average::Histogram; -use rand::prelude::*; - -const N_BINS: usize = 100; -const N_SAMPLES: u32 = 1_000_000; -const TOL: f64 = 1e-3; -average::define_histogram!(hist, 100); -use hist::Histogram as Histogram100; - -#[test] -fn unit_sphere() { - const N_DIM: usize = 3; - let h = Histogram100::with_const_width(-1., 1.); - let mut histograms = [h.clone(), h.clone(), h]; - let dist = rand_distr::UnitSphere; - let mut rng = rand_pcg::Pcg32::from_entropy(); - for _ in 0..N_SAMPLES { - let v: [f64; 3] = dist.sample(&mut rng); - for i in 0..N_DIM { - histograms[i].add(v[i]).map_err( - |e| { println!("v: {}", v[i]); e } - ).unwrap(); - } - } - for h in &histograms { - let sum: u64 = h.bins().iter().sum(); - println!("{:?}", h); - for &b in h.bins() { - let p = (b as f64) / (sum as f64); - assert!((p - 1.0 / (N_BINS as f64)).abs() < TOL, "{}", p); - } - } -} - -#[test] -fn unit_circle() { - use std::f64::consts::PI; - let mut h = Histogram100::with_const_width(-PI, PI); - let dist = rand_distr::UnitCircle; - let mut rng = rand_pcg::Pcg32::from_entropy(); - for _ in 0..N_SAMPLES { - let v: [f64; 2] = dist.sample(&mut rng); - h.add(v[0].atan2(v[1])).unwrap(); - } - let sum: u64 = h.bins().iter().sum(); - println!("{:?}", h); - for &b in h.bins() { - let p = (b as f64) / (sum as f64); - assert!((p - 1.0 / (N_BINS as f64)).abs() < TOL, "{}", p); - } -} |