# Bayesian Inference — Conjugate Prior Updates
Online Bayesian rate estimation with credible intervals.
O(1) per update, 16-32 bytes, pure arithmetic.
| Update cost | ~3 cycles |
| Types | `BetaBinomialF64/F32`, `GammaPoissonF64/F32` |
| Memory | 32 bytes (f64) |
| Priming | After 1 observation |
| Output | `mean()`, `variance()`, `credible_interval()` |
| Feature | none (core), `std\|libm` for `credible_interval` |
## What They Do
Conjugate priors give you Bayesian rate estimation for free.
Instead of just a point estimate ("success rate = 73%"), you get
a full posterior distribution with uncertainty ("success rate =
73% ± 4% at 95% confidence").
**Beta-Binomial** — for success/failure rates. Each observation
is binary (success or failure). The posterior is a Beta distribution
that gets sharper with more data.
**Gamma-Poisson** — for event rates. Each observation is a count
over some exposure time. The posterior is a Gamma distribution.
Both update in O(1) — just increment two parameters.
## When to Use Them
**Use Beta-Binomial when:**
- You're tracking a binary outcome rate (fill rate, error rate, uptime)
- You need confidence intervals, not just point estimates
- You want a principled way to combine prior knowledge with data
**Use Gamma-Poisson when:**
- You're tracking an event rate (messages/sec, orders/min)
- You need uncertainty on the rate estimate
- Events arrive in batches with varying observation windows
**Don't use these when:**
- You need smoothed values → use [EMA](ema.md) (cheaper, no Bayesian overhead)
- You need change detection → use [CUSUM](cusum.md)
- Your data is continuous, not count-based → use [Welford](welford.md)
## How They Work
### Beta-Binomial
```
Prior: Beta(α₀, β₀)
On success: α += 1
On failure: β += 1
Posterior mean = α / (α + β)
Posterior variance = αβ / ((α+β)²(α+β+1))
Credible interval: normal approximation
mean ± z * sqrt(variance)
(accurate for n > 30)
```
### Gamma-Poisson
```
Prior: Gamma(α₀, β₀)
On observing k events in t time units:
α += k
β += t
Posterior rate = α / β
Posterior variance = α / β²
```
## Configuration
### Beta-Binomial
```rust
use nexus_stats::estimation::BetaBinomialF64;
// Uniform prior (no prior knowledge)
let mut rate = BetaBinomialF64::new();
// Informative prior (strong belief rate ≈ 0.7)
let mut rate = BetaBinomialF64::with_prior(70.0, 30.0);
// Observe outcomes:
rate.observe(true); // success
rate.observe(false); // failure
// Batch update:
rate.observe_batch(95, 5); // 95 successes, 5 failures
println!("rate: {:.3}", rate.mean());
println!("95% CI: {:?}", rate.credible_interval(0.95));
```
### Gamma-Poisson
```rust
use nexus_stats::estimation::GammaPoissonF64;
let mut event_rate = GammaPoissonF64::new();
// Observed 15 events in 3 seconds
event_rate.observe(15, 3.0);
// Observed 22 events in 5 seconds
event_rate.observe(22, 5.0);
println!("rate: {:.1} events/sec", event_rate.rate());
println!("95% CI: {:?}", event_rate.credible_interval(0.95));
```
## Examples by Domain
### Monitoring — Error Rate with Confidence
```rust
let mut errors = BetaBinomialF64::new();
// Per request:
errors.observe(request_succeeded);
if let Some((lo, hi)) = errors.credible_interval(0.95) {
let error_rate = 1.0 - errors.mean();
// "Error rate: 2.3% (95% CI: 1.8% - 3.1%)"
// The CI tells you how much data you have.
// Wide CI → need more observations before acting.
}
```
### Networking — Packet Rate Estimation
```rust
let mut packet_rate = GammaPoissonF64::new();
// Per measurement window (1 second):
packet_rate.observe(packets_received, 1.0);
// Rate estimate stabilizes after a few windows.
// CI narrows as you accumulate more exposure time.
```
## Credible Interval Accuracy
The credible interval uses a normal approximation to the
Beta/Gamma posterior. This is accurate for moderate sample sizes
(n > 30) but can be poor for very small n or extreme rates
(near 0 or 1).
For n < 30, the true posterior is skewed and the symmetric normal
CI over-covers on one side, under-covers on the other. Use these
numbers for monitoring, not statistical inference at small n.
## Performance
| `observe()` | ~3 cycles |
| `mean()` | ~3 cycles |
| `credible_interval()` | ~15 cycles (includes sqrt + rational approx) |