Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions R/args.R
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,10 @@ process_init_approx <- function(init, num_procs, model_variables = NULL,
exp(log_weights - max(log_weights)), tail = "right", r_eff = 1,
return_k = FALSE, verbose = FALSE
)
# posterior <= 1.7.1 can return weights of about -2e-16 when many weights
# underflow to 0. Remove this once the minimum posterior version includes
# stan-dev/posterior#468.
weights <- pmax(weights, 0)
}
if (num_candidates < nrow(draws_df)) {
# Collapse duplicate candidates to one row, summing their weights so a vector
Expand Down
34 changes: 34 additions & 0 deletions tests/testthat/test-fit-init.R
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,40 @@ test_that("Pathfinder fit initializations use the intended weights", {
expect_equal(pareto_smooth_calls, 2L)
})

test_that("Pathfinder init weights are not negative after Pareto smoothing", {
# Most log weights are far below the maximum, so exp() underflows to 0 for
# them. posterior::pareto_smooth() can then return weights of about -2e-16
# (posterior <= 1.7.1), which resample_draws() rejects. The mock gives those
# weights whatever the installed posterior version. Remove this test with
# the clamp once the minimum posterior version includes
# stan-dev/posterior#468.
lp <- c(-1000 - seq_len(350), -seq(0, 60, length.out = 50))
pathfinder_fit <- structure(
list(
draws = function(format) posterior::as_draws_df(data.frame(
theta = seq_along(lp),
lp__ = lp,
lp_approx__ = 0
)),
metadata = function() list(
num_paths = 10,
psis_resample = FALSE,
calculate_lp = TRUE
),
return_codes = function() 0
),
class = "CmdStanPathfinder"
)
local_mocked_bindings(
pareto_smooth = function(x, ...) x - 1e-16,
.package = "posterior"
)
local_mocked_bindings(process_init = function(init, ...) init)

inits <- process_init.CmdStanPathfinder(pathfinder_fit, 4)
expect_equal(posterior::ndraws(inits), 4)
})

test_that("Pathfinder init candidates are distinct target parameter vectors", {
draws <- posterior::as_draws_df(data.frame(
theta = c(1, 1, 2, 3),
Expand Down
Loading