---
title: "De-heaping density estimation with adheaping"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{De-heaping density estimation with adheaping}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 6, fig.height = 3.5)
library(adheaping)
```

## Heaping and the identifiability limit

Heaped and rounded data concentrate on a coarse grid of round numbers and defeat kernel
density estimation, which renders the rounding marks as spurious modes. Rounding to a grid of
width `D` is exactly convolution of the density with a width-`D` box followed by lattice
sampling, so in the characteristic-function domain the density is recovered by dividing out the
known box (a continuous generalization of Sheppard's correction) inside the grid-Nyquist band
`|w| < pi/D`. Beyond that band the density is not identifiable from the heaped data alone.

## A worked example

We draw a bimodal sample, round it to a grid of `0.5`, and compare the naive kernel estimate
with the tuning-free combined de-heaping estimator.

```{r}
set.seed(20260627)
n <- 4000
x <- ifelse(runif(n) < 0.5, rnorm(n, -1.2, 0.5), rnorm(n, 1.2, 0.5))
D <- 0.5
y <- D * round(x / D)
grid <- seq(-6, 6, length.out = 2048)

f_true  <- 0.5 * dnorm(grid, -1.2, 0.5) + 0.5 * dnorm(grid, 1.2, 0.5)
f_naive <- naive_kde(y, grid)
f_adk   <- adkde(y, D, grid)
attr(f_adk, "pick")   # which component the band-capacity gate selected
```

```{r, echo = FALSE}
plot(grid, f_true, type = "l", lwd = 2, xlab = "x", ylab = "density", xlim = c(-3, 3))
lines(grid, f_naive, col = "grey55", lty = 3, lwd = 1.6)
lines(grid, as.numeric(f_adk), col = "#b2182b", lwd = 1.8)
legend("topright", c("truth", "naive KDE", "adkde (combined)"),
       col = c("black", "grey55", "#b2182b"), lty = c(1, 3, 1), lwd = 1.8, bty = "n")
```

The naive estimate carries the rounding comb; the combined estimator recovers the smooth
bimodal density.

## Reading the grid and the heaped fraction

The grid and the fraction of a sample that is heaped are read directly from the rounding comb,
and the grid is detected blind as a group-matched atom in the spectral basis.

```{r}
heap_grid(y, grid, near = D)                 # locate the grid from the comb tooth
heap_detect(y = D * round(x / D), span = c(-12.8, 12.8))$D_hat  # blind spectral detection
```

## Baselines

Faithful base-R replicas of the measurement-error deconvolution and Heitjan-Rubin
multiple-imputation methods are provided (`deconv_kde`, `heitjan_mi`), and the real
`Kernelheaping` stochastic EM is wrapped by `sem_kde` when that package is installed.
