1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//! `ordofp_bayes` - Probabilistic Programming for `OrdoFP`
//!
//! > *"Probabilitas est ratio incertitudinis."*
//! > — Probability is the measure of uncertainty. (Modern)
//!
//! This crate provides Bayesian inference algorithms for probabilistic programming,
//! using functional abstractions, as part of the `OrdoFP` ecosystem.
//!
//! Adapted third-party algorithms are inventoried in `ORIGINAL_SOURCE.md`
//! in this crate and the repo-root `THIRD_PARTY_NOTICES.md`.
//!
//! # Features
//!
//! - Sequential Monte Carlo (SMC)
//! - Metropolis-Hastings (MCMC)
//! - Importance Sampling
//! - Parallel particle generation via Rayon (`rayon` feature)
//!
//! # Performance
//!
//! Weight calculations are written as tight slice loops that LLVM
//! auto-vectorizes; there is no explicit SIMD (`std::simd`) code in this
//! crate.
//!
//! # Example
//!
//! ```rust
//! use ordofp_bayes::distributions::Normal;
//! use ordofp_bayes::{Distribution, MetropolisHastings};
//! use rand::SeedableRng;
//! use rand::rngs::StdRng;
//! use std::sync::atomic::{AtomicU64, Ordering};
//!
//! // Give every closure call its own seed, so the 1000 draws below are
//! // genuinely independent samples rather than 1000 copies of one number.
//! static SEED: AtomicU64 = AtomicU64::new(1);
//! fn next_seed() -> u64 {
//! SEED.fetch_add(1, Ordering::Relaxed)
//! }
//!
//! // Define a simple model: sample once from a prior distribution.
//! let mut rng = StdRng::seed_from_u64(42);
//! // Note: `MetropolisHastings::infer` draws `iterations` independent
//! // samples via resampling rather than running an MCMC chain, so
//! // `burn_in` (the `100` below) has no effect on this code path — it
//! // only matters for `infer_traceable`'s trace-based chain.
//! let mh = MetropolisHastings::new(1000, 100);
//!
//! // Run inference
//! let samples: Vec<f64> = mh.infer(
//! || {
//! let mut local_rng = StdRng::seed_from_u64(next_seed());
//! Normal::new(0.0, 1.0).sample(&mut local_rng)
//! },
//! &mut rng,
//! );
//! assert_eq!(samples.len(), 1000);
//! // Real sampling variation: 1000 draws from a continuous Normal are not
//! // all identical (this cannot flake — the odds of a false failure are
//! // astronomically small).
//! assert!(samples.windows(2).any(|w| w[0] != w[1]));
//! ```
extern crate alloc;
pub use ;
pub use ;