--- title: "Handling Platform Differences in Snapshots" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Handling Platform Differences in Snapshots} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(resultcheck) ``` ## The problem: floating-point noise across platforms Numerical computations in R can produce results that differ at very high decimal places depending on the platform, compiler, or the version of libraries like BLAS/LAPACK. For example, a centering attribute from `scale()` might be `2.41e-17` on one machine and `1.63e-17` on another — both are effectively zero, but a naïve snapshot comparison treats them as different. `resultcheck` provides two complementary mechanisms to handle this: 1. **`[ignored]` line markers** — mark specific lines in a snapshot file as known discrepancies that should always be skipped. 2. **`snapshot.precision` in `_resultcheck.yml`** — round all floating-point numbers to a fixed number of decimal places before comparing or storing snapshots. --- ## Feature 1: `[ignored]` line markers ### How it works Open any `.md` snapshot file under `tests/_resultcheck_snaps/` and replace the entire content of a volatile line with the literal text `[ignored]`. On every subsequent run, that line position is masked before the comparison takes place, so differences there will never trigger a failure. When you update a snapshot interactively, the `[ignored]` markers are automatically preserved in the new file. ### Step-by-step example Suppose your `PCA.R` script produces a snapshot that includes lines like: ``` ..- attr(*, "scaled:center")= num 2.41e-17 ..- attr(*, "scaled:center")= num 2.98e-17 ``` and these values fluctuate slightly between platforms. Open the snapshot file at `tests/_resultcheck_snaps/PCA/panel_data_pca.md` and change those specific lines to: ``` [ignored] [ignored] ``` Save the file. The snapshot now looks like this (abbreviated): ```markdown # Snapshot: data.frame ## Structure 'data.frame': 1071 obs. of 30 variables: ... $ us : num [1:1071, 1] NA -0.423 -0.697 ... [ignored] ..- attr(*, "scaled:scale")= num 1.22 $ eu : num [1:1071, 1] NA -0.783 -0.711 ... [ignored] ..- attr(*, "scaled:scale")= num 1.37 ``` From now on, `run_in_sandbox("code/PCA.R", sandbox)` will not raise an error regardless of what those two lines contain in any new run, while every other line continues to be verified. ### Rules * The **entire line** must be `[ignored]` (leading/trailing whitespace is stripped before the check, so indentation does not matter). * Lines are matched by **position** within the snapshot file, so adding or removing other lines shifts the positions. If the overall structure of the output changes materially, update the snapshot interactively first, then re-apply the `[ignored]` markers to the new file. * `[ignored]` markers are **preserved automatically** when you update a snapshot: `resultcheck` copies each `[ignored]` line from the stored snapshot into the freshly generated one before writing it to disk. --- ## Feature 2: Numeric precision in `_resultcheck.yml` ### How it works Add a `snapshot.precision` key to the `_resultcheck.yml` file at the root of your project. Before storing or comparing a snapshot, every floating-point number in the text representation is rounded to that many decimal places. Integer-like tokens (e.g. index ranges such as `[1:1071]`) are left unchanged. ```yaml # _resultcheck.yml snapshot: precision: 10 ``` With `precision: 10`, both `2.41e-17` and `1.63e-17` round to `0`, so the snapshots compare as equal. ### Step-by-step example 1. Add `precision` to `_resultcheck.yml`: ```yaml snapshot: precision: 10 ``` 2. Delete the outdated snapshot (or run interactively and accept the update when prompted) so that the stored file is regenerated with rounded values. 3. Re-run the script via `run_in_sandbox()`. The comparison will now succeed whenever the effective difference is smaller than `0.5 × 10^{-precision}`. ### Choosing a precision value | Situation | Suggested precision | |-----------|-------------------| | Machine-epsilon noise (`1e-15` to `1e-17`) | 10 | | Monte-Carlo / bootstrap variance | 4–6 | | Monetary amounts (cents) | 2 | A higher value is more sensitive (closer to exact comparison); a lower value is more forgiving. ### Backward compatibility If your project already has snapshot files stored before `precision` was configured, `resultcheck` also rounds the **stored** snapshot numbers during comparison. This means setting `precision` will immediately suppress floating-point noise in existing snapshots without needing to regenerate them. --- ## Using both features together The two features are independent and compose naturally: * Use **`[ignored]`** when a line's value is entirely unreliable across runs (e.g. a random seed, a memory address, or a platform-specific constant that carries no scientific meaning). * Use **`precision`** when values are meaningful but may differ in the last few decimal places due to floating-point arithmetic. For the PCA example in the problem statement, either approach resolves the failure. Using `precision: 10` is the lower-maintenance option because it requires no manual edits to snapshot files; `[ignored]` offers surgical control when only a handful of lines are volatile while the rest must be exact.