DREAM Example 3: signal decomposition, using bi-modal posterior distribution.
#endif
srand((int) time(nullptr));
cout << "\n" << "---------------------------------------------------------------------------------------------------\n";
cout << "EXAMPLE 3: set the inference problem: identify x_0 and x_1 model parameters\n"
<< " from data (noise free example)\n"
<< " model: f(x) = sin(x_0*M_PI*t + x_1),\n"
<< " data: d = sin(5*M_PI*t + 0.3*M_PI) + sin(10*M_PI*t + 0.1*M_PI)\n"
<< " compared to Example 2, the data is a superposition of two signals\n"
<< " and the posterior is multi-modal\n"
<< " -- problem setup --\n"
<< " t in [0,1], t is discretized with 32 equidistant nodes\n"
<< " the likelihood is exp(- 16 * (f(x) - d)^2)\n"
<< " using a sparse grid to interpolate the model\n"
<< " NOTE: 16 = 32/2 corresponds to the discretization error in t\n\n";
constexpr double pi = 3.14159265358979323846;
int num_chains = 500;
int num_burnup_iterations = 1000;
int num_sample_iterations = 300;
int num_discrete_nodes = 32;
auto model = [&](double x0, double x1, std::vector<double> &data)->
void{
double dt = 1.0 / ((double) data.size());
double t = 0.5 * dt;
for(auto &d : data){
d = std::sin(x0 * pi * t + x1);
t += dt;
}
};
std::vector<double> signal1(num_discrete_nodes),
signal2(num_discrete_nodes),
data(num_discrete_nodes);
model( 5.0, 0.3 * pi, signal1);
model(10.0, 0.1 * pi, signal2);
std::transform(signal1.begin(), signal1.end(), signal2.begin(),
data.begin(), std::plus<double>());
std::vector<double> domain_a = { 1.0, -0.1};
std::vector<double> domain_b = {12.0, 1.7};
grid.setDomainTransform(domain_a, domain_b);
[&](std::vector<double> const &x, std::vector<double> &y, size_t)->
void{
model(x[0], x[1], y);
},
grid, 1);
(num_burnup_iterations, num_sample_iterations,
(grid,
likely,
grid.getDomainInside(),
state,
);
const std::vector<double> &history = state.getHistory();
double frequency_low = 0.0, correction_low = 0.0;
double frequency_high = 0.0, correction_high = 0.0;
int num_low = 0, num_high = 0;
for(size_t i=0; i<history.size(); i+=2){
if (history[i] < 6.5){
frequency_low += history[i];
correction_low += history[i+1];
num_low++;
}else{
frequency_high += history[i];
correction_high += history[i+1];
num_high++;
}
}
frequency_low /= (double)(num_low);
correction_low /= (double)(num_low);
frequency_high /= (double)(num_high);
correction_high /= (double)(num_high);
cout.precision(5);
cout << "Inferred values:\n"
<< " low frequency:" << setw(12) << std::fixed << frequency_low
<< " error:" << setw(12) << std::scientific << std::abs(frequency_low - 5.0) << "\n"
<< " low correction:" << setw(12) << std::fixed << correction_low
<< " error:" << setw(12) << std::scientific << std::abs(correction_low - 0.3 * pi)
<< "\n\n"
<< " high frequency:" << setw(12) << std::fixed << frequency_high
<< " error:" << setw(12) << std::scientific << std::abs(frequency_high - 10.0) << "\n"
<< " high correction:" << setw(12) << std::fixed << correction_high
<< " error:" << setw(12) << std::scientific << std::abs(correction_high - 0.1 * pi)
<< "\n\n";
cout << "\n" << "---------------------------------------------------------------------------------------------------\n";
#ifndef __TASMANIAN_DOXYGEN_SKIP