antimeme / docs / salib

Quickstart

Sobol’ indices for the Ishigami function in five minutes.


The Ishigami function is the standard test problem for sensitivity analysis methods. It has three inputs, nonlinear interactions, and closed-form Sobol’ indices — so you know immediately whether your estimates are right.

The model

The Ishigami function maps three independent uniform inputs x_i \sim \mathcal{U}(-\pi, \pi) to a scalar:

f(\mathbf{x}) = \sin(x_1) + 7\sin^2(x_2) + 0.1\, x_3^4 \sin(x_1)

The x_3^4 \sin(x_1) interaction term makes this a hard test: x_3 contributes nothing to first-order variance but has a large total-effect index through its interaction with x_1.

Closed-form indices

With a = 7 and b = 0.1, the analytic Sobol’ indices are:

Factor S_i (first-order) S_{Ti} (total-effect)
x_1 0.3139 0.5576
x_2 0.4424 0.4424
x_3 0.0000 0.2437

x_3 has zero first-order effect but 24% total effect — all of it through the x_1 x_3 interaction. Any estimator that handles this correctly is working.

Dependencies

[dependencies]
salib = "0.1"

This pulls in salib-core, salib-samplers, and salib-estimators by default.

Code

use std::f64::consts::PI;
use salib::*;
use salib::samplers::{SobolSampler, build_saltelli_matrix};
use salib::estimators::estimate_saltelli2010;

fn main() {
    // 1. Define the problem: three uniform factors on [-π, π].
    let problem = ProblemBuilder::new()
        .factor("x1", Distribution::Uniform { lo: -PI, hi: PI })
        .factor("x2", Distribution::Uniform { lo: -PI, hi: PI })
        .factor("x3", Distribution::Uniform { lo: -PI, hi: PI })
        .build()
        .unwrap();

    // 2. Generate quasi-random samples.
    //    Sobol' sequence, 8192 base samples, Saltelli cross-matrix design.
    let mut rng = RngState::from_seed([0u8; 32]);
    let sampler = SobolSampler::minimal(2 * problem.dim());
    let saltelli = build_saltelli_matrix(
        &sampler, 8192, false, &mut rng
    ).unwrap();

    // 3. Evaluate the model and estimate indices.
    let indices = estimate_saltelli2010(&saltelli, |x| {
        x[0].sin()
            + 7.0 * x[1].sin().powi(2)
            + 0.1 * x[2].powi(4) * x[0].sin()
    });

    println!("{indices}");
}

Output

Sobol' Indices (Saltelli 2010)
──────────────────────────────────────────
Factor          S1        ST
x1          0.3143    0.5559
x2          0.4427    0.4420
x3         -0.0042    0.2455

Verify: Compare against the closed-form values above. S_1 estimates are within 0.005 of the analytic values at N = 8192. S_T estimates are within 0.002. S_1 for x_3 is slightly negative — expected Monte Carlo noise around the true value of zero.

What just happened

Three things, each handled by a different crate.

Sampling (salib-samplers): A Sobol’ quasi-random sequence generated N = 8192 base samples in the unit hypercube, then the Saltelli cross-matrix design produced the A, B, and A_B^{(i)} matrices needed for the variance decomposition — (d + 2) \times N = 40{,}960 model evaluations total.

Evaluation: The closure ran the Ishigami function on each row of the combined matrix. salib does not own your model — any Fn(&[f64]) -> f64 works.

Estimation (salib-estimators): The Saltelli 2010 estimator computed first-order indices S_i and total-effect indices S_{Ti} from the A, B, A_B^{(i)} output vectors using the formulas in Saltelli et al. (2010).

Next