StochTree 0.5.0.9000
Loading...
Searching...
No Matches
bcf_sampler.h
1
5#ifndef STOCHTREE_BCF_SAMPLER_H_
6#define STOCHTREE_BCF_SAMPLER_H_
7
8#include <stochtree/bcf.h>
9#include <stochtree/container.h>
10#include <stochtree/data.h>
11#include <stochtree/ensemble.h>
12#include <stochtree/leaf_model.h>
13#include <stochtree/linear_regression.h>
14#include <stochtree/partition_tracker.h>
15#include <stochtree/prior.h>
16#include <stochtree/probit.h>
17#include <stochtree/random_effects.h>
18#include <stochtree/tree_sampler.h>
19#include <stochtree/variance_model.h>
20#include <iomanip>
21#include <memory>
22#include <sstream>
23#include <string>
24#include <type_traits>
25#include <variant>
26#include <vector>
27
28namespace StochTree {
29
31 public:
32 // If continuation is true, the sampler warm-starts the active mu and tau forests from
33 // the last retained samples already present in `samples` (rather than initializing them
34 // to root), and the existing forest containers are preserved so that new samples are
35 // appended to them.
36 //
37 // If warmstart_source is non-null (and continuation is false), this is a FRESH run whose forests /
38 // scalars / tau_0 / adaptive-coding / rfx are seeded from an EXTERNAL model's samples
39 // (*warmstart_source) at warmstart_sample_num (1-indexed). This backs bcf(previous_model_json=...):
40 // the destination `samples` containers are fresh, but the active forests are reconstituted from the
41 // previous model's retained sample. Same-scale is assumed (no leaf rescale); the previous model's
42 // y_std is used to convert its stored global variance / tau_0 back to standardized space. The
43 // borrowed pointer need only outlive this constructor call.
46
47 // Main entry point for running the BCF GFR sampler
48 // If num_chains > 0, captures snapshots of the last num_chains GFR states for fork_chains()
49 void run_gfr(BCFSamples& samples, int num_gfr, bool keep_gfr, int num_chains = 0);
50
51 // Run a single chain of the BCF MCMC sampler
52 void run_mcmc(BCFSamples& samples, int num_burnin, int keep_every, int num_mcmc);
53
54 // Run num_chains independent MCMC chains sequentually based on GFR snapshots captured by run_gfr() or re-initialized from root
55 void run_mcmc_chains(BCFSamples& samples, int num_chains, int num_burnin, int keep_every, int num_mcmc);
56
57 // Post-process samples by extracting test set predictions and running any necessary transformations
58 void postprocess_samples(BCFSamples& samples, int start_sample = 0);
59
60 // Serialize the internal RNG state to a string. std::mt19937 round-trips losslessly through
61 // its stream operators, so this captures the exact position in the random stream -- used to
62 // persist RNG state across a sample() / continue_sampling() boundary for bit-identical results.
63 std::string GetRngState() const {
64 std::ostringstream oss;
65 oss << rng_;
66 return oss.str();
67 }
68
69 // Restore the internal RNG state from a string produced by GetRngState(). Resumes the random
70 // stream at exactly the captured position. Must be called after construction (InitializeState
71 // unconditionally re-seeds rng_) and before any sampling draws.
72 void SetRngState(const std::string& state) {
73 std::istringstream iss(state);
74 iss >> rng_;
75 }
76
77 // Regenerate the probit latent outcome for a continuation warm-start. The latent is not persisted
78 // (it is re-drawn each MCMC iteration), so this draws a fresh z ~ p(z | y, mu + Z*tau + rfx + tau_0)
79 // to place the residual in a valid, stationary state before the first continued draw. No-op unless
80 // the model uses a probit link. MUST be called after SetRngState so the draw comes from the resumed
81 // (or user-re-seeded) stream rather than the pre-seed RNG.
82 void RegenerateProbitLatent(BCFSamples& samples);
83
84 private:
86 void InitializeState(BCFSamples& samples, bool continuation = false);
87 bool initialized_ = false;
88
90 void RestoreStateFromGFRSnapshot(BCFSamples& samples, int snapshot_index);
91
97 void WarmStartResetFromSample(BCFSamples& samples, BCFSamples& source, int idx);
98
100 void RestoreStateDefault();
101
103 void RunOneIteration(BCFSamples& samples, bool gfr, bool keep_sample, bool write_snapshot = false);
104
106 void SampleParametricTreatmentEffect();
107
109 void SampleAdaptiveCodingParameters();
110
112 BCFConfig& config_;
113 BCFData& data_;
114
117 BCFSamples* warmstart_source_ = nullptr;
118 int warmstart_sample_num_ = 0;
119
121 GaussianConstantLeafModel mu_leaf_model_;
122 std::variant<GaussianUnivariateRegressionLeafModel, GaussianMultivariateRegressionLeafModel> tau_leaf_model_;
123 LogLinearVarianceLeafModel variance_leaf_model_;
124
126 std::unique_ptr<TreeEnsemble> mu_forest_;
127 std::unique_ptr<ForestTracker> mu_forest_tracker_;
128 std::unique_ptr<TreePrior> tree_prior_mu_;
129 std::unique_ptr<TreeEnsemble> tau_forest_;
130 std::unique_ptr<ForestTracker> tau_forest_tracker_;
131 std::unique_ptr<TreePrior> tree_prior_tau_;
132 double init_val_mu_;
133 double init_val_tau_;
134 std::vector<double> init_val_tau_vec_;
135
137 std::unique_ptr<TreeEnsemble> variance_forest_;
138 std::unique_ptr<ForestTracker> variance_forest_tracker_;
139 std::unique_ptr<TreePrior> tree_prior_variance_;
140 bool has_variance_forest_ = false;
141 double init_val_variance_;
142
144 std::unique_ptr<MultivariateRegressionRandomEffectsModel> random_effects_model_;
145 std::unique_ptr<RandomEffectsTracker> random_effects_tracker_;
146 std::unique_ptr<RandomEffectsDataset> random_effects_dataset_;
147 bool has_random_effects_ = false;
148
150 std::unique_ptr<ColumnVector> residual_;
151 std::unique_ptr<ColumnVector> outcome_raw_;
152 std::unique_ptr<ForestDataset> forest_dataset_;
153 std::unique_ptr<ForestDataset> forest_dataset_test_;
154 bool has_test_ = false;
155
157 std::mt19937 rng_;
158
160 double global_variance_;
161 double leaf_scale_mu_;
162 double leaf_scale_tau_;
163 std::vector<double> leaf_scale_tau_multivariate_;
164
166 std::vector<double> model_preds_;
167
169 std::vector<double> tau_raw_sum_preds_;
170
171 // Global error scale model
172 std::unique_ptr<GlobalHomoskedasticVarianceModel> var_model_;
173 bool sample_sigma2_global_ = false;
174
175 // Leaf scale models
176 std::unique_ptr<LeafNodeHomoskedasticVarianceModel> leaf_scale_model_mu_;
177 bool sample_sigma2_leaf_mu_ = false;
178 std::unique_ptr<LeafNodeHomoskedasticVarianceModel> leaf_scale_model_tau_;
179 bool sample_sigma2_leaf_tau_ = false;
180
181 // Treatment intercept term
182 double tau_0_scalar_;
183 std::vector<double> tau_0_vector_;
184 bool sample_tau_0_ = false;
185
186 // Adaptive coding parameters
187 double b_0_;
188 double b_1_;
189 bool adaptive_coding_ = false;
190 std::vector<double> tau_basis_vector_train_;
191 std::vector<double> tau_basis_vector_test_;
192
194 struct GFROneIterationVisitorTau {
195 BCFSampler& sampler;
196 BCFSamples& samples;
197 bool keep_sample;
200 *sampler.tau_forest_, *sampler.tau_forest_tracker_, *samples.tau_forests, model,
201 *sampler.forest_dataset_, *sampler.residual_, *sampler.tree_prior_tau_, sampler.rng_,
202 sampler.config_.var_weights_tau, sampler.config_.sweep_update_indices_tau, sampler.global_variance_, sampler.config_.feature_types,
203 sampler.config_.cutpoint_grid_size, /*keep_forest=*/keep_sample,
204 /*pre_initialized=*/true, /*backfitting=*/true,
205 /*num_features_subsample=*/sampler.config_.num_features_subsample_tau, sampler.config_.num_threads);
206 }
209 *sampler.tau_forest_, *sampler.tau_forest_tracker_, *samples.tau_forests, model,
210 *sampler.forest_dataset_, *sampler.residual_, *sampler.tree_prior_tau_, sampler.rng_,
211 sampler.config_.var_weights_tau, sampler.config_.sweep_update_indices_tau, sampler.global_variance_, sampler.config_.feature_types,
212 sampler.config_.cutpoint_grid_size, /*keep_forest=*/keep_sample,
213 /*pre_initialized=*/true, /*backfitting=*/true,
214 /*num_features_subsample=*/sampler.config_.num_features_subsample_tau, sampler.config_.num_threads,
215 sampler.config_.leaf_dim_tau);
216 }
217 };
218
220 struct MCMCOneIterationVisitorTau {
221 BCFSampler& sampler;
222 BCFSamples& samples;
223 bool keep_sample;
226 *sampler.tau_forest_, *sampler.tau_forest_tracker_, *samples.tau_forests, model,
227 *sampler.forest_dataset_, *sampler.residual_, *sampler.tree_prior_tau_, sampler.rng_,
228 sampler.config_.var_weights_tau, sampler.config_.sweep_update_indices_tau, sampler.global_variance_, /*keep_forest=*/keep_sample,
229 /*pre_initialized=*/true, /*backfitting=*/true,
230 /*num_threads=*/sampler.config_.num_threads);
231 }
234 *sampler.tau_forest_, *sampler.tau_forest_tracker_, *samples.tau_forests, model,
235 *sampler.forest_dataset_, *sampler.residual_, *sampler.tree_prior_tau_, sampler.rng_,
236 sampler.config_.var_weights_tau, sampler.config_.sweep_update_indices_tau, sampler.global_variance_, /*keep_forest=*/keep_sample,
237 /*pre_initialized=*/true, /*backfitting=*/true,
238 /*num_threads=*/sampler.config_.num_threads, sampler.config_.leaf_dim_tau);
239 }
240 };
241
243 struct ScaleUpdateVisitor {
244 BCFSampler& sampler;
245 double leaf_scale;
246 void operator()(GaussianConstantLeafModel& model) {
247 model.SetScale(leaf_scale);
248 }
250 model.SetScale(leaf_scale);
251 }
253 // No-op for multivariate regression leaf model since scale is a vector
254 }
255 void operator()(CloglogOrdinalLeafModel& model) {
256 // No-op for cloglog ordinal leaf model since scale is not a variance parameter
257 }
258 };
259
260 struct TauForestResetVisitor {
261 BCFSampler& sampler;
262 BCFSamples& samples;
263 TreeEnsemble& forest;
265 sampler.tau_forest_->ReconstituteFromForest(forest);
266 sampler.tau_forest_tracker_->ReconstituteFromForest(forest, *sampler.forest_dataset_, *sampler.residual_, true);
267 sampler.tau_forest_tracker_->UpdatePredictions(sampler.tau_forest_.get(), *sampler.forest_dataset_.get());
268 }
270 sampler.tau_forest_->ReconstituteFromForest(forest);
271 sampler.tau_forest_tracker_->ReconstituteFromForest(forest, *sampler.forest_dataset_, *sampler.residual_, true);
272 sampler.tau_forest_tracker_->UpdatePredictions(sampler.tau_forest_.get(), *sampler.forest_dataset_.get());
273 }
274 };
275
277 struct GFRSnapshot {
278 // Forest state
279 std::unique_ptr<TreeEnsemble> mu_forest;
280 std::unique_ptr<TreeEnsemble> tau_forest;
281 std::unique_ptr<TreeEnsemble> variance_forest; // null if no variance forest
282
283 // Global parameters
284 double sigma2;
285 double leaf_scale_mu;
286 double leaf_scale_tau;
287 std::vector<double> leaf_scale_tau_multivariate;
288
289 // Treatment intercept
290 double tau_0_scalar;
291 std::vector<double> tau_0_vector;
292
293 // Adaptive coding
294 double b_0;
295 double b_1;
296
297 // Residual (incorporates forest + RFX contributions for a given sampler iteration)
298 std::vector<double> residual;
299
300 // Heteroskedastic variance model state
301 std::vector<double> variance_weights; // forest_dataset_ var_weights at snapshot time; only valid when variance_forest != null
302
303 // RFX model state (only populated when has_random_effects_)
304 Eigen::VectorXd rfx_working_parameter;
305 Eigen::MatrixXd rfx_group_parameters;
306 Eigen::MatrixXd rfx_group_parameter_covariance;
307 Eigen::MatrixXd rfx_working_parameter_covariance;
308 double rfx_variance_prior_shape;
309 double rfx_variance_prior_scale;
310 };
311
313 std::vector<GFRSnapshot> gfr_snapshots_;
314};
315
316} // namespace StochTree
317
318#endif // STOCHTREE_BCF_SAMPLER_H_
Definition bcf_sampler.h:30
Marginal likelihood and posterior computation for complementary log-log ordinal BART model.
Definition leaf_model.h:1123
Marginal likelihood and posterior computation for gaussian homoskedastic constant leaf outcome model.
Definition leaf_model.h:458
Marginal likelihood and posterior computation for gaussian homoskedastic constant leaf outcome model.
Definition leaf_model.h:797
Marginal likelihood and posterior computation for gaussian homoskedastic constant leaf outcome model.
Definition leaf_model.h:626
Marginal likelihood and posterior computation for heteroskedastic log-linear variance model.
Definition leaf_model.h:942
Class storing a "forest," or an ensemble of decision trees.
Definition ensemble.h:31
static void GFRSampleOneIter(TreeEnsemble &active_forest, ForestTracker &tracker, ForestContainer &forests, LeafModel &leaf_model, ForestDataset &dataset, ColumnVector &residual, TreePrior &tree_prior, std::mt19937 &gen, std::vector< double > &variable_weights, std::vector< int > &sweep_update_indices, double global_variance, std::vector< FeatureType > &feature_types, int cutpoint_grid_size, bool keep_forest, bool pre_initialized, bool backfitting, int num_features_subsample, int num_threads, LeafSuffStatConstructorArgs &... leaf_suff_stat_args)
Definition tree_sampler.h:816
A collection of random number generation utilities.
Definition bart.h:15
Definition bcf.h:54
Definition bcf.h:23
Definition bcf.h:145