Doxygen 1.9.8
Toolkit for Adaptive Stochastic Modeling and Non-Intrusive ApproximatioN: Tasmanian v8.2
 
Loading...
Searching...
No Matches
tsgDreamSample.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017, Miroslav Stoyanov
3 *
4 * This file is part of
5 * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN
6 *
7 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
12 * and the following disclaimer in the documentation and/or other materials provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
20 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
21 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED.
25 * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT,
26 * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE.
27 * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF,
28 * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE.
29 */
30
31#ifndef __TASMANIAN_DREAM_SAMPLE_HPP
32#define __TASMANIAN_DREAM_SAMPLE_HPP
33
34#include "tsgDreamState.hpp"
36#include "tsgDreamCorePDF.hpp"
37
60namespace TasDREAM{
61
69using DreamDomain = std::function<bool(std::vector<double> const &x)>;
70
75inline DreamDomain hypercube(std::vector<double> const &lower, std::vector<double> const &upper){
76 return [=](const std::vector<double> &x)->bool{
77 auto il = lower.begin(), iu = upper.begin();
78 for(auto v : x) if ((v < *il++) || (v > *iu++)) return false;
79 return true;
80 };
81}
82
89inline void no_update(std::vector<double> &){}
90
97inline double const_one(){ return 1.0; }
98
110template<int weight_percent>
111double const_percent(){ return ((double) weight_percent) / 100.0; }
112
120inline void uniform_prior(TypeSamplingForm, const std::vector<double> &, std::vector<double> &values){ values.clear(); }
121
142using DreamPDF = std::function<void(const std::vector<double> &candidates, std::vector<double> &values)>;
143
157using DreamModel = std::function<void(const std::vector<double> &candidates, std::vector<double> &outputs)>;
158
175using DreamLikelihood = std::function<void(TypeSamplingForm form, const std::vector<double> &model_outputs, std::vector<double> &likely)>;
176
187using DreamPrior = std::function<void(TypeSamplingForm form, const std::vector<double> &candidates, std::vector<double> &values)>;
188
200using DreamMergedLikelyModel = std::function<void(const std::vector<double> &candidates, std::vector<double> &values)>;
201
259template<TypeSamplingForm form = regform>
261 DreamLikelihood likelihood,
262 DreamPrior prior){
263 return [=](const std::vector<double> &candidates, std::vector<double> &values)->void{
264 std::vector<double> model_outs;
265 model(candidates, model_outs);
266 likelihood(form, model_outs, values);
267
268 std::vector<double> prior_vals(values.size());
269 prior(form, candidates, prior_vals);
270
271 auto iv = values.begin();
272 if (form == regform){
273 for(auto p : prior_vals) *iv++ *= p;
274 }else{
275 for(auto p : prior_vals) *iv++ += p;
276 }
277 };
278}
279
290template<TypeSamplingForm form = regform>
292 DreamPrior prior){
293 return [=](const std::vector<double> &candidates, std::vector<double> &values)->void{
294 likelihood_model(candidates, values);
295
296 std::vector<double> prior_vals(values.size());
297 prior(form, candidates, prior_vals);
298
299 auto iv = values.begin();
300 if (form == regform){
301 for(auto p : prior_vals) *iv++ *= p;
302 }else{
303 for(auto p : prior_vals) *iv++ += p;
304 }
305 };
306}
307
308
413template<TypeSamplingForm form = regform>
414void SampleDREAM(int num_burnup, int num_collect,
415 DreamPDF probability_distribution,
416 DreamDomain inside,
417 TasmanianDREAM &state,
418 std::function<void(std::vector<double> &x)> independent_update = no_update,
419 std::function<double(void)> differential_update = const_one,
420 std::function<double(void)> get_random01 = tsgCoreUniform01){
421
422 size_t num_chains = (size_t) state.getNumChains(), num_dimensions = (size_t) state.getNumDimensions();
423 double unitlength = (double) num_chains;
424
425 if (num_chains == 0) return; // no sampling with a null state
426
427 if (!state.isStateReady()) throw std::runtime_error("ERROR: DREAM sampling requires that the setState() has been called first on the TasmanianDREAM.");
428
429 if (!state.isPDFReady()) // initialize probability density (if not initialized already)
430 state.setPDFvalues(probability_distribution);
431
432 if (num_collect > 0) // pre-allocate memory for the new history
433 state.expandHistory(num_collect);
434
435 int total_iterations = std::max(num_burnup, 0) + std::max(num_collect, 0);
436 for(int t = 0; t < total_iterations; t++){
437 std::vector<double> candidates, values;
438 candidates.reserve(num_chains * num_dimensions);
439 values.reserve(num_chains);
440
441 std::vector<bool> valid(num_chains, true); // keep track whether the samples need to be evaluated
442
443 for(size_t i=0; i<num_chains; i++){
444 std::vector<double> propose(num_dimensions);
445
446 size_t jindex = (size_t) (get_random01() * unitlength);
447 size_t kindex = (size_t) (get_random01() * unitlength);
448 if (jindex >= num_chains) jindex = num_chains - 1; // this is needed in case get_random01() returns 1
449 if (kindex >= num_chains) jindex = num_chains - 1;
450
451 state.getIJKdelta(i, jindex, kindex, differential_update(), propose); // propose = s_i + w ( s_k - s_j)
452 independent_update(propose); // propose += correction
453
454 if (inside(propose)){
455 candidates.insert(candidates.end(), propose.begin(), propose.end());
456 values.resize(values.size() + 1);
457 }else{
458 valid[i] = false;
459 }
460 }
461
462 if (!candidates.empty()) // block the pathological case of all proposals leaving the domain
463 probability_distribution(candidates, values);
464
465 std::vector<double> new_state(num_chains * num_dimensions), new_values(num_chains);
466
467 auto icand = candidates.begin(); // loop over all candidates and values, accept or reject
468 auto ival = values.begin();
469
470 size_t accepted = 0;
471
472 for(size_t i=0; i<num_chains; i++){
473 bool keep_new = valid[i]; // if not valid, automatically reject
474 if (valid[i]){ // apply random test
475 if (*ival > state.getPDFvalue(i)){ // if the new value has higher probability, automatically accept
476 keep_new = true;
477 }else{
478 if (form == regform){
479 keep_new = (*ival / state.getPDFvalue(i) >= get_random01()); // keep if the new value has higher probability
480 }else{
481 keep_new = (*ival - state.getPDFvalue(i) >= log(get_random01()));
482 }
483 //std::cout << "Trsh = " << *ival / state.getPDFvalue(i) << " " << ((keep_new) ? "Accept" : "Reject") << std:: endl;
484 }
485 }
486
487 if (keep_new){
488 std::copy_n(icand, num_dimensions, new_state.begin() + i * num_dimensions);
489 new_values[i] = *ival;
490 accepted++; // accepted one more proposal
491 }else{ // reject and reuse the old state
492 state.getChainState((int) i, &*(new_state.begin() + i * num_dimensions));
493 new_values[i] = state.getPDFvalue(i);
494 }
495
496 if (valid[i]){ // kept or rejected, if this sample was valid then move to the next sample in the list
497 std::advance(icand, num_dimensions);
498 ival++;
499 }
500 }
501
502 state.setState(new_state);
503 state.setPDFvalues(new_values);
504
505 if (t >= num_burnup)
506 state.saveStateHistory(accepted);
507 }
508}
509
510
520template<TypeSamplingForm form = regform>
521void SampleDREAM(int num_burnup, int num_collect,
522 DreamPDF probability_distribution,
523 DreamDomain inside,
524 TasmanianDREAM &state,
525 TypeDistribution dist, double magnitude,
526 std::function<double(void)> differential_update = const_one,
527 std::function<double(void)> get_random01 = tsgCoreUniform01){
528 if (dist == dist_uniform){
529 SampleDREAM<form>(num_burnup, num_collect, probability_distribution, inside, state,
530 [&](std::vector<double> &x)->void{ applyUniformUpdate(x, magnitude, get_random01); }, differential_update, get_random01);
531 }else if (dist == dist_gaussian){
532 SampleDREAM<form>(num_burnup, num_collect, probability_distribution, inside, state,
533 [&](std::vector<double> &x)->void{ applyGaussianUpdate(x, magnitude, get_random01); }, differential_update, get_random01);
534 }else{ // assuming none
535 SampleDREAM<form>(num_burnup, num_collect, probability_distribution, inside, state, no_update, differential_update, get_random01);
536 }
537}
538
539}
540
541#endif
Contains the current state and the history of the DREAM chains.
Definition tsgDreamState.hpp:70
double getPDFvalue(size_t i) const
Return the value of the probability_distribution of the i-th chain.
Definition tsgDreamState.hpp:155
void saveStateHistory(size_t num_accepted)
Appends the current state to the history.
int getNumDimensions() const
Return the number of dimensions.
Definition tsgDreamState.hpp:91
void setPDFvalues(const std::vector< double > &new_values)
Set the current set of pdf values to the new_values.
bool isStateReady() const
Return true if the state has already been initialized with setState().
Definition tsgDreamState.hpp:98
void getChainState(size_t i, double *x) const
Return the state of the i-th chain, store an array x of size at least num_dimensions.
Definition tsgDreamState.hpp:147
void expandHistory(int num_snapshots)
Allocate (expand) internal storage for the history snapshots, avoids reallocating data when saving a ...
void getIJKdelta(size_t i, size_t j, size_t k, double w, std::vector< double > &x) const
Used by the DREAM sampler, , where s indicates the current i, j, and k-th state vectors.
int getNumChains() const
Return the number of chains.
Definition tsgDreamState.hpp:93
bool isPDFReady() const
Return true if the pdf values have already been initialized with setPDF().
Definition tsgDreamState.hpp:100
void setState(const std::vector< double > &new_state)
Set the current DREAM state to the new_state.
TypeDistribution
Indicates a specific probability distribution for the associated function.
Definition tsgDreamEnumerates.hpp:102
TypeSamplingForm
Describes whether sampling should be done with the regular or logarithm form of the probability densi...
Definition tsgDreamEnumerates.hpp:90
@ dist_gaussian
Gaussian or Normal distribution defined by mean and variance.
Definition tsgDreamEnumerates.hpp:107
@ dist_uniform
Uniform distribution.
Definition tsgDreamEnumerates.hpp:104
@ regform
Use the standard form for the probability density.
Definition tsgDreamEnumerates.hpp:92
void applyGaussianUpdate(std::vector< double > &x, double magnitude, std::function< double(void)> get_random01=tsgCoreUniform01)
Add a correction to every entry in x, sue Gaussian distribution with zero mean and standard deviation...
Definition tsgDreamCoreRandom.hpp:77
double tsgCoreUniform01()
Default random sampler, using rand() divided by RAND_MAX.
Definition tsgDreamCoreRandom.hpp:61
void applyUniformUpdate(std::vector< double > &x, double magnitude, std::function< double(void)> get_random01=tsgCoreUniform01)
Add a correction to every entry in x, use uniform samples over (-magnitude, magnitude).
Definition tsgDreamCoreRandom.hpp:67
std::function< void(const std::vector< double > &candidates, std::vector< double > &values)> DreamMergedLikelyModel
Generic signature for a combination of a likelihood and a model.
Definition tsgDreamSample.hpp:200
double const_percent()
Template that returns a constant based on the percentage, i.e., weight_percent / 100....
Definition tsgDreamSample.hpp:111
void no_update(std::vector< double > &)
Dummy function that does not make any changes to the vector as default for the independent_update() i...
Definition tsgDreamSample.hpp:89
std::function< void(const std::vector< double > &candidates, std::vector< double > &outputs)> DreamModel
Generic model signature used by Tasmanian.
Definition tsgDreamSample.hpp:157
void SampleDREAM(int num_burnup, int num_collect, DreamPDF probability_distribution, DreamDomain inside, TasmanianDREAM &state, std::function< void(std::vector< double > &x)> independent_update=no_update, std::function< double(void)> differential_update=const_one, std::function< double(void)> get_random01=tsgCoreUniform01)
Core template for the sampling algorithm.
Definition tsgDreamSample.hpp:414
DreamDomain hypercube(std::vector< double > const &lower, std::vector< double > const &upper)
Make a lambda that matches the inside signature in SampleDREAM(), test if the vector x is in the hype...
Definition tsgDreamSample.hpp:75
DreamPDF posterior(DreamModel model, DreamLikelihood likelihood, DreamPrior prior)
Combines the three components of a Bayesian posterior into a single distribution.
Definition tsgDreamSample.hpp:260
void uniform_prior(TypeSamplingForm, const std::vector< double > &, std::vector< double > &values)
Uniform prior distribution for both regular and log form.
Definition tsgDreamSample.hpp:120
double const_one()
Dummy function that returns 1.0, used as default for the differential_update() in SampleDREAM().
Definition tsgDreamSample.hpp:97
std::function< void(const std::vector< double > &candidates, std::vector< double > &values)> DreamPDF
Generic probability distribution used by Tasmanian.
Definition tsgDreamSample.hpp:142
std::function< void(TypeSamplingForm form, const std::vector< double > &model_outputs, std::vector< double > &likely)> DreamLikelihood
Generic likelihood signature used by Tasmanian.
Definition tsgDreamSample.hpp:175
std::function< void(TypeSamplingForm form, const std::vector< double > &candidates, std::vector< double > &values)> DreamPrior
Generic signature for the prior distributions used by Tasmanian.
Definition tsgDreamSample.hpp:187
std::function< bool(std::vector< double > const &x)> DreamDomain
Generic test function whether a sample belongs in the domain.
Definition tsgDreamSample.hpp:69
Encapsulates the Tasmanian DREAM module.
Definition TasmanianDREAM.hpp:80
Gives the unscaled formulas for several probability distributions.
Core random sampling methods.
The container class holding the DREAM history.