---
title: "GRIMMER basics"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{GRIMMER basics}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
bibliography: references.bib
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
# Print enough significant digits that values like `10.46` are not
# abbreviated to `10.5` in the output tibbles:
options(pillar.sigfig = 4)
```

```{r setup, include = FALSE}
library(scrutiny)
```

Granularity-related inconsistency of means mapped to error repeats, or GRIMMER, tests whether a reported mean and standard deviation (SD) of integer data are possible given the reported sample size [@anaya2016b; @allard2018]. It extends GRIM [@brown_grim_2017]: the mean must pass GRIM, and the SD must be achievable by a sample of integers whose sum is one of those that GRIM allows for the mean. scrutiny implements Allard's Analytic-GRIMMER algorithm.

The GRIMMER functions work like their GRIM counterparts, so this vignette follows `vignette("grim")` and is shorter where the two tests do not differ. It covers the basics; `vignette("grimmer-in-depth")` goes further.

## Basic GRIMMER testing

### Single cases: `grimmer()`

To test whether a mean of 7.3 and an SD of 2.51 are consistent with a sample size of 12:

```{r}
grimmer(x = 7.3, sd = 2.51, n = 12, digits_x = 1, digits_sd = 2, items_averaged = 1, data_type = "integer")
```

`digits_x` and `digits_sd` are the numbers of decimal places of the reported mean and SD. As in `grim()`, they must be given because numeric values lose trailing zeros. So must `items_averaged` and `data_type`; see `vignette("grim")`.

The SD is taken to be a sample SD, which divides by $n - 1$ (`sd_meaning = "sd_sample"`). That is what nearly all software reports by default: R, SPSS, Stata, SAS, Excel, and pandas. NumPy's `np.std()` is the main exception and reports the population SD, which divides by $n$. If the data may have been analyzed with it, set `sd_meaning = "sd_pop"`; see `vignette("grimmer-in-depth")`.

### Many cases: `grimmer_map()`

Enter the reported values into a data frame and call `grimmer_map()` on it:

```{r}
flying_pigs1 <- tibble::tribble(
  ~x   , ~sd  , ~n ,
   8.9 , 2.81 , 25 ,
   2.6 , 2.05 , 25 ,
   7.2 , 2.89 , 25 ,
   3.6 , 3.11 , 25 ,
   9.2 , 7.13 , 25 ,
  10.4 , 2.53 , 25 ,
   7.3 , 3.14 , 25
)

grimmer_map(flying_pigs1, digits_x = 1, digits_sd = 2, items_averaged = 1, data_type = "integer")
```

`consistency` is the test result, and `reason` states which part of the test an inconsistent value set failed. A value set passes GRIMMER if it passes GRIM and the three tests of @allard2018:

1.  The reconstructed sum of squared observations must be an integer, and one that integers with the reconstructed sum can reach. scrutiny adds this second part to Allard's test: for example, no 11 integers with a sum of 40 have a sum of squares below 148, which is that of seven 4s and four 3s. For fewer than five values, some larger sums of squares are impossible, too.
2.  The reconstructed SD must match the reported one. Test 1 implies this, so it never appears as a reason.
3.  The sum of squares must have the same parity (odd or even) as the sum.

Consistent value sets are marked `"Passed all"`.

### Scale items

For a multi-item scale, give the number of items as an `items_averaged` argument or column, as in `grim_map()`. Taken as single items, half of these value sets from a three-item scale are wrongly flagged:

```{r}
flying_pigs2 <- tibble::tribble(
  ~x   , ~sd  , ~n ,
  5.90 , 2.19 , 40 ,
  5.71 , 1.42 , 40 ,
  3.50 , 1.81 , 40 ,
  3.82 , 2.43 , 40 ,
  4.61 , 1.92 , 40 ,
  5.24 , 2.51 , 40
)

flying_pigs2 |>
  grimmer_map(digits_x = 2, digits_sd = 2, items_averaged = 1, data_type = "integer")

flying_pigs2 |>
  grimmer_map(digits_x = 2, digits_sd = 2, items_averaged = 3, data_type = "integer")
```

## Explaining consistency results

`explain_print()` explains the results of `grimmer_map()` step by step, as for GRIM. Here is the inconsistent value set from above:

```{r}
flying_pigs1 |>
  grimmer_map(digits_x = 1, digits_sd = 2, items_averaged = 1, data_type = "integer") |>
  dplyr::filter(!consistency) |>
  explain_print()
```

`explain_map()` adds the explanations as an `explanation` column instead, and `grimmer_explain()` explains a single value set. To see the test rather than read it, draw one value set with `grimmer_plot_line()`; see `vignette("grimmer-in-depth")`.

## Summaries with `audit()`

```{r}
flying_pigs1 |>
  grimmer_map(digits_x = 1, digits_sd = 2, items_averaged = 1, data_type = "integer") |>
  audit()
```

- `all_cases`, `incon_cases`, `emp_incon`: the total number of value sets, the number of inconsistent ones, and their ratio.
- `fail_grim`, `fail_test1`, `fail_test3`: the number of value sets that failed GRIM or GRIMMER's first or third test.

## Interpreting results

An inconsistency means that an assumption of the test is false or that a number was reported incorrectly, often for a benign reason. What to rule out before drawing conclusions is discussed in [the section on interpreting GRIM results](https://trustworthyresear.ch/chapters/granularity_methods.html#sec-grim-interpreting) of @hussey_trustworthiness_2026. The same reasoning applies to GRIMMER.

## Going further

`vignette("grimmer-in-depth")` covers SDs that are population SDs or standard errors, bounded scales, the means and SDs behind a test result with `grimmer_values()` and `grimmer_plot_line()`, plots of many value sets with `grim_plot_grid()`, values around the reported ones with `grimmer_map_seq()`, and unknown group sizes with `grimmer_map_total_n()`.

# References
