fugue-ppl 0.2.0

Monadic PPL with numerically stable inference and comprehensive diagnostics.
Documentation
# `core` module

## Overview

The core module provides the fundamental building blocks for probabilistic programming in Fugue. It defines the core abstractions that enable type-safe, composable probabilistic models through monadic composition, unique addressing, and a rich set of probability distributions.

## Quick Start

```rust
# use fugue::*;

// Create a simple Bayesian model
let model = prob! {
    let mu <- sample(addr!("mu"), Normal::new(0.0, 1.0).unwrap());
    let is_outlier <- sample(addr!("outlier"), Bernoulli::new(0.1).unwrap());  // Returns bool!
    let sigma = if is_outlier { 5.0 } else { 1.0 };  // Natural boolean usage
    observe(addr!("y"), Normal::new(mu, sigma).unwrap(), 2.5);
    pure(mu)
};
```

## Components

### `address.rs` - Site Addressing

- `Address`: Unique identifiers for random choice sites
- `addr!` macro: Creates addresses from names and optional indices
- `scoped_addr!` macro: Creates hierarchical addresses with scoping

```rust
# use fugue::*;
let a1 = addr!("mu");           // Address("mu")
let a2 = addr!("x", 5);         // Address("x#5")
let a3 = scoped_addr!("layer1", "weight"); // Address("layer1::weight")
```

### `distribution.rs` - Type-Safe Probability Distributions

- `Distribution<T>` trait: Generic interface for distributions over any type `T`
- **Type-safe sampling**: Each distribution returns its natural type
  - `Bernoulli` → `bool` (no more f64 comparisons!)
  - `Poisson`, `Binomial` → `u64` (natural counting)
  - `Categorical` → `usize` (safe array indexing)
  - `Normal`, `Beta`, etc. → `f64` (continuous values)
- Built-in distributions: Normal, Uniform, LogNormal, Exponential, Beta, Gamma, Bernoulli, Categorical, Binomial, Poisson
- All distributions support sampling and log-density evaluation

```rust
# use fugue::*;
# use rand::thread_rng;
# let mut rng = thread_rng();
// Continuous distribution
let normal = Normal::new(0.0, 1.0).unwrap();
let x: f64 = normal.sample(&mut rng);
let logp = normal.log_prob(&x);

// Discrete distributions now type-safe!
let coin = Bernoulli::new(0.5).unwrap();
let flip: bool = coin.sample(&mut rng);  // Returns bool directly!
let prob = coin.log_prob(&flip);

let counter = Poisson::new(3.0).unwrap();
let count: u64 = counter.sample(&mut rng);  // Returns u64 directly!

let choice = Categorical::new(vec![0.3, 0.5, 0.2]).unwrap();
let idx: usize = choice.sample(&mut rng);  // Returns usize for safe indexing!
```

### `model.rs` - Monadic Model Representation

**Key Types/Functions:**

- `Model<A>`: The core probabilistic program type
- `pure`, `bind`, `map`, `and_then`: Monadic operations
- `sample`, `observe`, `factor`: Primitive operations
- `zip`, `sequence_vec`, `traverse_vec`, `guard`: Combinators

**Example:**

```rust
# use fugue::*;
let model = prob! {
    let mu <- sample(addr!("mu"), Normal::new(0.0, 1.0).unwrap());  // Returns f64
    let is_outlier <- sample(addr!("outlier"), Bernoulli::new(0.1).unwrap());  // Returns bool!
    let sigma = if is_outlier { 5.0 } else { 1.0 };  // Natural boolean usage
    observe(addr!("y"), Normal::new(mu, sigma).unwrap(), 2.5);
    pure(mu)
};
```

### `numerical.rs` - Numerical Stability

**Key Functions:**

- `log_sum_exp`: Numerically stable log-sum-exp computation
- `safe_ln`: Safe logarithm with validation
- `log1p_exp`: Stable computation of log(1 + exp(x))
- `normalize_log_probs`: Normalize log probabilities

**Example:**

```rust
# use fugue::*;
let log_probs = vec![-1.0, -2.0, -0.5];
let normalized = normalize_log_probs(&log_probs);
```

## Common Patterns

### Sequential Model Building

Build complex models step-by-step using monadic composition.

```rust
# use fugue::*;
let hierarchical_model = prob! {
    let global_mu <- sample(addr!("global_mu"), Normal::new(0.0, 1.0).unwrap());
    let local_effects <- plate!(i in 0..10 => {
        sample(addr!("local", i), Normal::new(global_mu, 0.1).unwrap())
    });
    pure((global_mu, local_effects))
};
```

### Conditional Logic with Type-Safe Distributions

Leverage type safety for cleaner conditional models.

```rust
# use fugue::*;
# let observed_value = 1.5;
let mixture_model = prob! {
    let component <- sample(addr!("component"), Categorical::new(vec![0.3, 0.7]).unwrap()); // Returns usize!
    let mu = match component {
        0 => -2.0,
        1 => 2.0,
        _ => 0.0,
    };
    let x <- sample(addr!("x"), Normal::new(mu, 1.0).unwrap());
    observe(addr!("y"), Normal::new(x, 0.1).unwrap(), observed_value);
    pure((component, x))
};
```

### Macro-Driven Development

**`prob!` - Do-notation Style Composition:**

```rust
# use fugue::*;
let model = prob! {
    let x <- sample(addr!("x"), Normal::new(0.0, 1.0).unwrap());
    let y = x * 2.0;  // Regular let binding
    observe(addr!("obs"), Normal::new(y, 0.1).unwrap(), 1.5);
    pure(x)
};
```

**`plate!` - Vectorized Operations:**

```rust
# use fugue::*;
let model = plate!(i in 0..10 => {
    sample(addr!("x", i), Normal::new(0.0, 1.0).unwrap())
});
```

## Performance Considerations

- **Memory**: Models are zero-cost abstractions that compile to efficient code
- **Computation**: Distributions use numerically stable algorithms
- **Best Practices**:
  - Use `plate!` for vectorized operations instead of manual loops
  - Prefer specific imports over wildcard imports in performance-critical code
  - Use the appropriate distribution type for your data (e.g., `u64` for counts)

## Integration

**Related Modules:**

- [`inference`]../inference/README.md: Use core models with MCMC, SMC, VI, and ABC algorithms
- [`runtime`]../runtime/README.md: Execute models with different handlers and trace management
- [`error`]../error.rs: Comprehensive error handling for distribution validation

**See Also:**

- Main documentation: [API docs]https://docs.rs/fugue

## Extension Points

How to extend the core module:

1. **Custom Distributions**: Implement the `Distribution<T>` trait for new probability distributions
2. **Model Combinators**: Add new higher-order functions that operate on `Model<A>`
3. **Addressing Schemes**: Extend the address system for complex hierarchical models
4. **Numerical Functions**: Add domain-specific numerical stability functions

## Design Principles

- **Monadic**: Models compose via bind/map following monad laws
- **Pure**: No side effects; interpretation happens at runtime
- **Typed**: Strong typing prevents many modeling errors
- **Addressable**: Every random choice has a unique, stable address
- **Extensible**: Easy to add new distributions and combinators