From c8cfb8dbb1e8444ccd24cb2903c033b1bc4b4722 Mon Sep 17 00:00:00 2001 From: Aki Vehtari Date: Tue, 11 Aug 2026 13:41:32 +0300 Subject: [PATCH 1/2] fix standalone gqs rng seed use --- src/cmdstan/command.hpp | 3 +- .../interface/generated_quantities_test.cpp | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/cmdstan/command.hpp b/src/cmdstan/command.hpp index 44adb63079..bce28e5fed 100644 --- a/src/cmdstan/command.hpp +++ b/src/cmdstan/command.hpp @@ -392,9 +392,10 @@ int command(int argc, const char *argv[]) { fitted_params_vec.emplace_back( fitted_params.samples.block(0, col_offset, num_rows, num_cols)); } + // `id` offsets the RNG per chain, as it does for the sampler methods return_code = stan::services::standalone_generate( model, num_chains, fitted_params_vec, random_seed, interrupt, logger, - sample_writers); + sample_writers, id); // ---- generate_quantities end ---- // } else if (user_method->arg("laplace")) { // ---- laplace start ---- // diff --git a/src/test/interface/generated_quantities_test.cpp b/src/test/interface/generated_quantities_test.cpp index e035e1f79d..376fea86f6 100644 --- a/src/test/interface/generated_quantities_test.cpp +++ b/src/test/interface/generated_quantities_test.cpp @@ -112,6 +112,43 @@ TEST_F(CmdStan, generate_quantities_same_in_out_multi_path_diff) { ASSERT_TRUE(out.hasError); } +// `id` must offset the RNG, as it does for the sample method: two runs that +// differ only in `id` must not produce identical generated quantities. This +// is the launch pattern CmdStanR and CmdStanPy use for parallel chains. +TEST_F(CmdStan, generate_quantities_chain_id_rng) { + std::vector out_id_1 + = {"src", "test", "test-models", "gq_id_1.csv"}; + std::vector out_id_2 + = {"src", "test", "test-models", "gq_id_2.csv"}; + auto run_gq = [&](const std::vector &out_path, int id) { + std::stringstream ss; + ss << convert_model_path(bern_gq_model) + << " data file=" << convert_model_path(bern_data) + << " output file=" << convert_model_path(out_path) + << " random seed=12345 id=" << id + << " method=generate_quantities fitted_params=" + << convert_model_path(bern_fitted_params); + run_command_output out = run_command(ss.str()); + EXPECT_FALSE(out.hasError) << out.output; + }; + auto csv_body = [](const std::string &path) { + std::ifstream in(path.c_str()); + std::stringstream out; + std::string line; + while (std::getline(in, line)) { + if (!line.empty() && line[0] != '#') + out << line << "\n"; + } + return out.str(); + }; + run_gq(out_id_1, 1); + run_gq(out_id_2, 2); + std::string body_1 = csv_body(convert_model_path(out_id_1)); + std::string body_2 = csv_body(convert_model_path(out_id_2)); + ASSERT_FALSE(body_1.empty()); + EXPECT_NE(body_1, body_2); +} + TEST_F(CmdStan, generate_quantities_non_scalar_good) { std::stringstream ss; ss << convert_model_path(gq_non_scalar_model) From af22d732f3cd723c6b78ec5a9bd1a677af079726 Mon Sep 17 00:00:00 2001 From: Aki Vehtari Date: Tue, 11 Aug 2026 17:19:06 +0300 Subject: [PATCH 2/2] drop a comment Co-authored-by: Brian Ward --- src/cmdstan/command.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmdstan/command.hpp b/src/cmdstan/command.hpp index bce28e5fed..d8c2c264c0 100644 --- a/src/cmdstan/command.hpp +++ b/src/cmdstan/command.hpp @@ -392,7 +392,6 @@ int command(int argc, const char *argv[]) { fitted_params_vec.emplace_back( fitted_params.samples.block(0, col_offset, num_rows, num_cols)); } - // `id` offsets the RNG per chain, as it does for the sampler methods return_code = stan::services::standalone_generate( model, num_chains, fitted_params_vec, random_seed, interrupt, logger, sample_writers, id);