integral 0.1.2

Native-Rust Gaussian integrals for quantum mechanics (driver + public API).
Documentation
//! Permanent guard: prove the force hooks and `Auto` dispatch route to the
//! *claimed* engine, not a silent fallback, and that `select_engine`'s thresholds
//! have no off-by-one. The two engines are independent f64 recurrences whose
//! round-off differs on near-cancellation tail elements, so their outputs are
//! NOT bit-identical — that lets us fingerprint which one actually ran.
//!
//! A permanent dispatch-routing guard.

use integral::{select_engine, Basis, Engine, Shell};

/// True iff every element is bit-for-bit equal.
fn bit_identical(a: &[f64], b: &[f64]) -> bool {
    a.len() == b.len() && a.iter().zip(b).all(|(x, y)| x.to_bits() == y.to_bits())
}

/// A contracted shell with `k` primitives (so contraction_degree can be tuned).
fn shell(l: usize, c: [f64; 3], k: usize, base: f64) -> Shell {
    let exps: Vec<f64> = (0..k).map(|i| base * (1.7f64).powi(i as i32)).collect();
    let coeffs: Vec<f64> = (0..k).map(|i| 0.3 + 0.1 * i as f64).collect();
    Shell::new(l, c, exps, coeffs).unwrap()
}

#[test]
fn engines_are_not_bit_identical_so_fingerprinting_is_valid() {
    // Sanity: on a high-L quartet the two engines genuinely differ in round-off.
    let b = Basis::new(vec![
        shell(4, [0.0, 0.0, 0.0], 1, 0.9),
        shell(4, [0.5, -0.3, 0.2], 1, 1.3),
        shell(4, [-0.4, 0.6, -0.1], 1, 0.7),
        shell(4, [0.2, 0.4, 0.8], 1, 1.1),
    ]);
    let os = b.eri_block_with(Engine::OsHgp, 0, 1, 2, 3);
    let rys = b.eri_block_with(Engine::Rys, 0, 1, 2, 3);
    assert!(
        !bit_identical(&os, &rys),
        "engines bit-identical — fingerprint distinguisher would be invalid"
    );
}

#[test]
fn auto_routes_to_the_engine_select_engine_names() {
    // Build quartets straddling every documented threshold and confirm Auto's
    // output is bit-identical to the engine select_engine() names, and NOT to the
    // other. contraction_degree = product of n_prim across the four shells.
    let geo = [
        [0.0, 0.0, 0.0],
        [0.6, -0.3, 0.2],
        [-0.4, 0.5, -0.2],
        [0.2, 0.3, 0.7],
    ];
    // (l per shell, k per shell) chosen to straddle every recalibrated boundary
    // (0–5 ⇒ deg≥1 OS; 6–16 ⇒ deg≥16 OS; ≥17 ⇒ Rys).
    let cases: &[([usize; 4], [usize; 4])] = &[
        ([0, 0, 0, 0], [1, 1, 1, 1]), // lt0  deg1   -> OS  (always)
        ([1, 1, 1, 1], [1, 1, 1, 1]), // lt4  deg1   -> OS  (0–5 band)
        ([2, 1, 1, 1], [1, 1, 1, 1]), // lt5  deg1   -> OS  (0–5 boundary top, was Rys)
        ([2, 2, 1, 1], [1, 1, 1, 1]), // lt6  deg1   -> Rys (6–16 band, below 16)
        ([2, 2, 1, 1], [2, 2, 2, 2]), // lt6  deg16  -> OS  (6–16 deg boundary)
        ([2, 2, 2, 2], [2, 1, 2, 2]), // lt8  deg8   -> Rys (below 16)
        ([2, 2, 2, 2], [2, 2, 2, 2]), // lt8  deg16  -> OS  (boundary, was Rys<81)
        ([3, 3, 3, 3], [2, 2, 2, 2]), // lt12 deg16  -> OS  (cap relaxed, was Rys)
        ([3, 3, 3, 3], [1, 1, 1, 1]), // lt12 deg1   -> Rys (5–16 band, below 16)
        ([4, 4, 4, 4], [2, 2, 2, 2]), // lt16 deg16  -> OS  (top of relaxed cap)
        ([4, 4, 4, 5], [2, 2, 2, 2]), // lt17 deg16  -> Rys (≥17: always Rys)
    ];
    for (ls, ks) in cases {
        let shells: Vec<Shell> = (0..4)
            .map(|i| shell(ls[i], geo[i], ks[i], 0.8 + 0.1 * i as f64))
            .collect();
        let b = Basis::new(shells);
        let lt: usize = ls.iter().sum();
        let deg: usize = ks.iter().product();
        let picked = select_engine(lt, deg);
        let auto = b.eri_block_with(Engine::Auto, 0, 1, 2, 3);
        let os = b.eri_block_with(Engine::OsHgp, 0, 1, 2, 3);
        let rys = b.eri_block_with(Engine::Rys, 0, 1, 2, 3);
        let (same_as, other) = match picked {
            Engine::OsHgp => (&os, &rys),
            _ => (&rys, &os),
        };
        assert!(
            bit_identical(&auto, same_as),
            "lt={lt} deg={deg}: select={picked:?} but Auto not bit-identical to it"
        );
        // And Auto differs from the other engine (proves it didn't run the other).
        // Only assert when the two engines actually differ for this quartet.
        if !bit_identical(&os, &rys) {
            assert!(
                !bit_identical(&auto, other),
                "lt={lt} deg={deg}: Auto matches the NON-selected engine"
            );
        }
        // And both engines still agree to tolerance (engine transparency).
        let peak = rys.iter().fold(0.0f64, |m, &r| m.max(r.abs()));
        for (o, r) in os.iter().zip(&rys) {
            assert!(
                (o - r).abs() <= 1e-9 * peak.max(1.0) + 1e-10,
                "lt={lt} deg={deg}: engines disagree {o} vs {r}"
            );
        }
        eprintln!("lt={lt:2} deg={deg:4} -> {picked:?}  (auto fingerprint OK)");
    }
}

#[test]
fn select_engine_boundaries_exhaustive() {
    // Off-by-one check of every threshold edge.
    // Band 0–5: OS always (down to deg 1).
    for lt in 0..=5 {
        assert_eq!(select_engine(lt, 1), Engine::OsHgp, "lt={lt} deg1");
        assert_eq!(
            select_engine(lt, usize::MAX),
            Engine::OsHgp,
            "lt={lt} highdeg"
        );
    }
    // Band 6–16: OS once deg ≥ 16; Rys below. Edge at deg 15/16.
    for lt in 6..=16 {
        assert_eq!(select_engine(lt, 1), Engine::Rys, "lt={lt} deg1");
        assert_eq!(select_engine(lt, 15), Engine::Rys, "lt={lt} deg15");
        assert_eq!(select_engine(lt, 16), Engine::OsHgp, "lt={lt} deg16");
    }
    // Band ≥ 17: always Rys, regardless of contraction. Edge at lt 16/17.
    for lt in 17..=24 {
        assert_eq!(select_engine(lt, usize::MAX), Engine::Rys, "lt={lt} highL");
    }
}