Skip to content

Commit 34d70fd

Browse files
committed
Use a relative tolerance in is_constant
1 parent fd910fe commit 34d70fd

3 files changed

Lines changed: 30 additions & 1 deletion

File tree

‎R/helpers.R‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,11 @@ release_questions <- function() {
277277
}
278278
# nocov end
279279

280+
# `x` is constant if `max(x) - min(x)` is at most `tol` times the largest
281+
# absolute value in `x`. Default is `.Machine$double.eps`.
280282
is_constant <- function(x, tol = .Machine$double.eps) {
281-
abs(max(x) - min(x)) < tol
283+
r <- range(x)
284+
spread <- r[2] - r[1]
285+
# the equality check covers all-zero and all-infinite x
286+
r[1] == r[2] || (is.finite(spread) && spread <= tol * max(abs(r)))
282287
}

‎tests/testthat/test_0_helpers.R‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,15 @@ test_that("loo_cores works", {
9191
expect_warning(expect_equal(loo_cores(10), 2), "deprecated")
9292
options(loo.cores = NULL)
9393
})
94+
95+
test_that("is_constant uses a tolerance relative to the magnitude of x", {
96+
expect_true(is_constant(rep(0, 5)))
97+
expect_true(is_constant(rep(1e-300, 5)))
98+
expect_true(is_constant(rep(-Inf, 5)))
99+
expect_true(is_constant(c(1, 1 + .Machine$double.eps)))
100+
expect_false(is_constant(c(1e-20, 2e-20)))
101+
expect_false(is_constant(c(1e-300, 2e-300)))
102+
expect_false(is_constant(c(-Inf, 2)))
103+
expect_false(is_constant(c(1, 2)))
104+
expect_true(is.na(is_constant(c(1, NA))))
105+
})

‎tests/testthat/test_E_loo.R‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,15 @@ test_that("weighted variance works", {
245245
x <- 1e8 + c(-1, 0, 1)
246246
expect_equal(.wvar(x, rep(1 / 3, 3)), 1)
247247
})
248+
249+
test_that("E_loo pareto_k does not depend on the scale of x", {
250+
# posterior::pareto_khat() of h * r also needs the relative tolerance
251+
# with an older posterior it returns NA here
252+
skip_if(posterior:::is_constant(c(1e-20, 2e-20)),
253+
"posterior::is_constant() has an absolute tolerance")
254+
k <- E_loo(x, psis_mat, type = "mean", log_ratios = log_rats)$pareto_k
255+
for (s in c(1e-20, 1e-200)) {
256+
k_s <- E_loo(s * x, psis_mat, type = "mean", log_ratios = log_rats)$pareto_k
257+
expect_equal(k_s, k, tolerance = 1e-10)
258+
}
259+
})

0 commit comments

Comments
 (0)