Summary
OS-specific snapshot variants exist for JAGS MCMC output because JAGS does not produce bit-for-bit identical results across different operating systems, even when using identical random number generator (RNG) seeds, algorithms, and model specifications.
Key Findings
1. Linux and Windows Are Identical
All snapshot files for Linux and Windows are 100% identical (0 byte differences):
# Verified for all snapshot files:
diff tests/testthat/_snaps/linux/run_mod/*.csv tests/testthat/_snaps/windows/run_mod/*.csv
# Result: No differences foundThis suggests: - Linux and Windows use similar or identical: - Floating-point arithmetic implementations - Mathematical library implementations (libm) - Compiler optimization strategies - JAGS binary compilation settings
2. macOS Differs from Linux/Windows
macOS (darwin) snapshots diverge from Linux/Windows, starting at specific iterations:
Example from kinetics.csv: - Iterations 1-18: All three platforms identical - Iteration 19: Divergence begins for parameter alpha[6,1] (person 6) - Darwin: alpha[6,1] = 0.0183156 - Linux/Windows: alpha[6,1] = 0.0160759
The divergence affects all parameters for person 6 from iteration 19 onwards: - alpha[6,1]: 0.0183156 vs 0.0160759 - shape[6,1]: 1.36788 vs 1.33649 - t1[6,1]: 2.71828 vs 3.34814 - y0[6,1]: 2.71828 vs 5.30265 - y1[6,1]: 1099.35 vs 578.7
3. RNG State Is Identical Across Platforms
Despite the divergence in MCMC samples, the RNG state is identical across all platforms:
".RNG.state" <- c(15587, 26869, 21639)
This confirms that: - The RNG seed and algorithm are working correctly - The RNG produces the same random numbers on all platforms - The divergence occurs in the MCMC sampling algorithm, not the RNG
Root Cause Analysis
Why JAGS Produces Platform-Dependent Results
JAGS uses the random numbers from the RNG in complex mathematical operations (log, exp, pow, step functions, etc.) that involve:
-
Floating-Point Arithmetic
- IEEE 754 allows platform-specific implementations
- Different CPUs may use different precision (x87 80-bit vs SSE 64-bit on x86)
- Rounding modes can differ
- Order of operations affects accumulated rounding errors
- Mathematical Function Libraries
-
Compiler Optimizations
- Different compilers (GCC, Clang, MSVC) optimize differently
- Instruction reordering can change accumulation of rounding errors
- Vectorization strategies differ (SSE, AVX on different platforms)
- Fast math flags can affect precision
-
MCMC Chain Propagation
- Small differences in early iterations propagate
- Iteration 19 is where accumulated differences cross a threshold
- Subsequent iterations build on these differences
Why adapt=0 Doesn’t Eliminate Differences
The test uses adapt = 0 to minimize platform differences, but this only disables JAGS’s adaptive tuning of proposal distributions. It doesn’t eliminate: - Floating-point precision differences - Mathematical library implementation differences - Compiler optimization differences
Current Snapshot Strategy
The repository currently maintains:
-
Base snapshots (
tests/testthat/_snaps/run_mod/) - Match Linux/Windows -
darwin variants (
tests/testthat/_snaps/darwin/run_mod/) - macOS-specific -
linux variants ((Removed in consolidation)tests/testthat/_snaps/linux/run_mod/) - Identical to base -
windows variants ((Removed in consolidation)tests/testthat/_snaps/windows/run_mod/) - Identical to linux
This was redundant because: - Windows snapshots duplicated Linux snapshots - Linux snapshots duplicated base snapshots - Only darwin snapshots provide unique value
Implemented Solution
Option 1: Consolidate Redundant Snapshots
We removed duplicate snapshots for Linux and Windows, keeping only: - Base snapshots (no variant) - Used by Linux and Windows - darwin variants - Used by macOS only
Benefits: - Eliminates ~50% of snapshot file duplication - Easier maintenance (fewer files to update) - Clearer intent (darwin is the special case)
Implementation:
# In test files, use conditional variant:
variant = if (system_os() == "darwin") "darwin" else NULLAlternative Options Considered
Option 2: Use Statistical Tolerance Checks
Replace exact snapshot matching with statistical tests that check: - Parameter distributions are similar (K-S test, Wasserstein distance) - Posterior means within tolerance - Convergence diagnostics (Rhat, ESS) are acceptable
Pros: - Platform-agnostic testing - Focuses on statistical validity, not bit-exact reproduction - More robust to JAGS version updates
Cons: - Harder to detect subtle regressions - Requires defining appropriate tolerances - May miss important changes
Option 3: Keep All OS Variants
Maintain all three OS variants.
Pros: - Explicit documentation of platform behavior
Cons: - High maintenance burden - Redundant data storage - Confusing for contributors
Conclusion
The OS-specific snapshot variants exist because JAGS MCMC sampling is inherently platform-dependent due to differences in floating-point arithmetic, mathematical library implementations, and compiler optimizations. However, Linux and Windows produce identical results, making their separate variants redundant.
We adopted Option 1 (consolidate snapshots) to reduce duplication while maintaining test coverage for the genuine macOS differences.