DREAM Example 4: signal decomposition, using bi-modal posterior distribution.
#endif
srand((int) time(nullptr));
cout << "\n" << "---------------------------------------------------------------------------------------------------\n";
cout << std::scientific; cout.precision(5);
cout << "EXAMPLE 4: similar to Example 3, but the data is noisy and the multi-modal posterior comes\n"
<< " from a symmetry in the model\n"
<< " set inference problem: identify x_0, x_1, x_2 and x_3 (four) model parameters\n"
<< " from noisy data\n"
<< " model: f(x) = x_0*exp(x_1*t) + x_2*exp(x_3*t), data: d = exp(t) + 0.4*exp(3*t)\n"
<< " note the symmetry between x_1 and x_3 which results in a bi-modal posterior\n"
<< " t in [0,1], t is discretized with 64 equidistant nodes\n"
<< " likelihood is exp(-64 * (f(x) - d)^2)\n"
<< " using a sparse grid to interpolate the model\n"
<< " NOTE: 64 corresponds to the discretization error and the added noise\n" << endl;
int num_chains = 50;
int num_burnup_iterations = 1000;
int num_sample_iterations = 1000;
int num_discrete_nodes = 64;
auto model = [&](double x0, double x1, double x2, double x3, std::vector<double> &data)->
void{
double dt = 1.0 / ((double) data.size());
double t = 0.5 * dt;
for(auto &d : data){
d = x0 * std::exp(x1 * t) + x2 * std::exp(x3 * t);
t += dt;
}
};
std::vector<double> data(num_discrete_nodes);
model(1.0, 1.0, 0.4, 3.0, data);
std::vector<double> domain_a = {0.2, 0.5, 0.2, 0.5};
std::vector<double> domain_b = {1.2, 4.0, 1.2, 4.0};
grid.setDomainTransform(domain_a, domain_b);
[&](std::vector<double> const &x, std::vector<double> &y, size_t)->
void{
model(x[0], x[1], x[2], x[3], y);
},
grid, 1);
std::vector<double> initial_chains;
state.setState(initial_chains);
(num_burnup_iterations, num_sample_iterations,
(grid,
likely,
grid.getDomainInside(),
state,
);
const std::vector<double> &history = state.getHistory();
double rate_low = 0.0, scale_low = 0.0;
double rate_high = 0.0, scale_high = 0.0;
for(size_t i=0; i<history.size(); i+=4){
if (history[i+1] < history[i+3]){
scale_low += history[i];
rate_low += history[i+1];
scale_high += history[i+2];
rate_high += history[i+3];
}else{
scale_low += history[i+2];
rate_low += history[i+3];
scale_high += history[i];
rate_high += history[i+1];
}
}
double num_samples = (double) (history.size() / 4);
rate_low /= num_samples;
scale_low /= num_samples;
rate_high /= num_samples;
scale_high /= num_samples;
cout << "Acceptance rate: " << std::fixed << state.getAcceptanceRate() << "\n\n";
cout << "High dimensions and multiple modes reduce the acceptance rate,\n"
<< "and sampling parameters (e.g., differential update magnitude) can affect it either way.\n\n";
cout << "Inferred values (noise free case):\n";
cout << " low rate:" << setw(12) << std::fixed << rate_low
<< " error:" << setw(12) << std::scientific << std::abs(rate_low - 1.0) << "\n";
cout << " low scale:" << setw(12) << std::fixed << scale_low
<< " error:" << setw(12) << std::scientific << std::abs(scale_low - 1.0) << "\n\n";
cout << " high rate:" << setw(12) << std::fixed << rate_high
<< " error:" << setw(12) << std::scientific << std::abs(rate_high - 3.0) << "\n";
cout << " high scale:" << setw(12) << std::fixed << scale_high
<< " error:" << setw(12) << std::scientific << std::abs(scale_high - 0.4) << "\n\n";
cout << "\n" << "---------------------------------------------------------------------------------------------------\n";
#ifndef __TASMANIAN_DOXYGEN_SKIP