suppressPackageStartupMessages(library(knitr))
for (f in list.files("../R", pattern = "\\.R$", full.names = TRUE)) source(f)
# The explorer's own data file, read as the explorer reads it (R/site.R)
G <- read_site_grid_js("explorer/grid.js")
hl <- read.csv("data/headlines.csv")
printed <- read.csv("data/printed-tables.csv")
h <- function(v, q, col = "reproduced") hl[[col]][hl$version == v & hl$quantity == q]
ss <- formals(compute_npv_mc_ssrn)
num <- function(x, d = 1, plus = FALSE) {
s <- formatC(abs(x), format = "f", digits = d, big.mark = ",")
ifelse(x < 0, paste0("−", s), if (plus) paste0("+", s) else s)
}
words <- function(n) c("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten")[n]
dollars <- function(x) gsub("$", "\\$", x, fixed = TRUE) # a literal $ in a markdown table cell
md_table <- function(d) {
d[] <- lapply(d, dollars)
cat("\n\n::: {.table-scroll}\n\n", paste(kable(d, format = "pipe", align = "l"), collapse = "\n"),
"\n\n:::\n\n", sep = "")
}
main <- site_grid_js_cell(G, from = "nber")[["mean_npv"]]
seeded <- h("nber", "mc_mean_npv")
# the first version's Monte Carlo: the explorer's "ssrn" setting
first <- site_grid_js_cell(G, from = "ssrn")[["mean_npv"]]
# the first version's Table 9, recomputed (the explorer cannot fix the revenue at one value)
t9 <- compute_npv_table9()
p9 <- printed[printed$table == "table9" & printed$column == "npv", ]
t9$printed <- p9$printed[match(paste0(t9$scenario, "@", t9$r), p9$row)]
# the repository's 2% case (NPV_plots/npv_decomposition_2pct.pdf prints -67.2): no OPA setting;
# hand-built inputs so that f = 1 - WT/baseline equals the script's 0.554 (as in
# feedback/scenario-tests-2026-10-15/jr-sensitivity.R, case 5)
base2 <- 0.02 * ss$baseline_revenue / 0.05
two_pct <- compute_npv_table9(baseline = base2,
scenarios = list(two_pct = list(label = "2%", WT = (1 - 0.554) * base2, C = 4.55)), r_values = 0.03)$npv
match_word <- function(printed, ...) if (any(round(c(...), 1) == printed)) "Match" else "No match"
nine <- list(six_confirmed = "Six departures", central = "Central", lit_calibrated = "Literature calibrated")
rows9 <- lapply(names(nine), function(s) {
x <- t9[t9$scenario == s, ]
x <- x[order(x$r), ]
data.frame(
Variation = sprintf("%s: revenue $%sB, income tax $%sB a year, share lost %s%%", nine[[s]],
sub("0$", "", formatC(x$WT[1], format = "f", digits = 2)),
sub("0$", "", formatC(x$C[1], format = "f", digits = 2)), num(100 * x$f[1], 1)),
Source = "SSRN, Table 9",
Printed = paste(num(x$printed, 1, plus = TRUE), collapse = " / "),
`This OPA` = paste(num(x$npv, 2, plus = TRUE), collapse = " / "),
Result = if (all(round(x$npv, 1) == x$printed)) "Match" else "No match",
`How to set it` = "R code", check.names = FALSE)
})
dl <- function(k, i) G$dials[[which(vapply(G$dials, `[[`, "", "key") == k)]]$labels[[i + 1L]]
sl <- unlist(G$named$ssrn); names(sl) <- vapply(G$dials, `[[`, "", "key")
results <- rbind(
data.frame(Variation = "Main assumptions, for reference", Source = "NBER, p.35",
Printed = num(h("nber", "mc_mean_npv", "printed"), 1),
`This OPA` = sprintf("%s (seeded run %s)", num(main, 2), num(seeded, 2)),
Result = match_word(h("nber", "mc_mean_npv", "printed"), main, seeded),
`How to set it` = "Explorer, as it opens", check.names = FALSE),
data.frame(Variation = sprintf("Revenue drawn from $%sB to $%sB, and the share lost tied to the revenue (f = 1 − revenue / %s)",
dl("wt_lo", sl[["wt_lo"]]), dl("wt_hi", sl[["wt_hi"]]), ss$baseline_revenue),
Source = "SSRN, p.20", Printed = num(h("ssrn", "mc_mean_npv", "printed"), 1),
`This OPA` = num(first, 2), Result = match_word(h("ssrn", "mc_mean_npv", "printed"), first),
`How to set it` = sprintf("Explorer: from the main setting, set the lowest revenue to %s, the highest to %s and the share lost to \"%s\"",
dl("wt_lo", sl[["wt_lo"]]), dl("wt_hi", sl[["wt_hi"]]), dl("f", sl[["f"]])),
check.names = FALSE),
do.call(rbind, rows9),
data.frame(Variation = "Tax rate 2% instead of 5%, central inputs, r − g of 3%",
Source = "Authors' repository, a plot", Printed = num(-67.2, 1), `This OPA` = "none",
Result = "Cannot be set", `How to set it` = "None", check.names = FALSE))
n_printed <- nrow(results) - 2 # the variations the papers print
n_match <- sum(results$Result[2:(n_printed + 1)] == "Match")
settings <- site_checks_table(G)