DREAM Example 5: signal decomposition, finding the best fit.
#endif
srand((int) time(nullptr));
cout << "\n" << "---------------------------------------------------------------------------------------------------\n";
cout << std::scientific; cout.precision(5);
cout << "EXAMPLE 5: infer the frequency and magnitude of two signals from noisy data\n"
<< " the model has 5 parameters: f(x_1 ... x_5) = sum x_k sin(k * pi * t)\n"
<< " data = 2.0 * sin(2 * pi * t) + sin(4 * pi * t) + noise\n"
<< " t in [0, 1], t is discretized using 64 equidistant nodes\n"
<< " we use two different likelihood functions,"
<< "corresponding to l-2 and l-1 norms\n"
<< " we are looking for the mode of the posterior,"
<< "i.e., the optimal fit to the data\n\n";
constexpr double pi = 3.14159265358979323846;
int num_dimensions = 5;
int num_chains = 50;
int num_burnup_iterations = 1000;
int num_sample_iterations = 1000;
int num_discrete_nodes = 64;
auto model = [&](std::vector<double> const &x, std::vector<double> &y)->
void{
double dt = 1.0 / ((double) y.size());
double t = 0.5 * dt;
for(auto &output : y){
output = 0.0;
int frequency = 1;
for(auto const &weight : x)
output += weight * std::sin(double(frequency++) * t * pi);
t += dt;
}
};
auto batch_model = [&](std::vector<double> const &x, std::vector<double> &y)->
void{
int num_samples = (int) x.size() / num_dimensions;
y.resize(num_samples * num_discrete_nodes);
int num_threads = std::min((int) std::thread::hardware_concurrency(), 4);
std::vector<std::thread> workers(num_threads);
for(int start = 0; start<num_threads; start++){
workers[start] = std::thread([&, start]()->
void{
for(int i=start; i<num_samples; i+=num_threads){
std::vector<double> single_input(&x[i*num_dimensions],
&x[i*num_dimensions] + num_dimensions);
std::vector<double> single_output(num_discrete_nodes);
model(single_input, single_output);
std::copy(single_output.begin(), single_output.end(),
&y[i*num_discrete_nodes]);
}
});
}
for(auto &w : workers) w.join();
};
std::vector<double> signal = {0.0, 2.0, 0.0, 1.0, 0.0};
std::vector<double> data(num_discrete_nodes);
model(signal, data);
std::vector<double> lower(num_dimensions, 0.0);
std::vector<double> upper(num_dimensions, 3.0);
state.setState(initial_chains);
(num_burnup_iterations, num_sample_iterations,
(batch_model,
likely,
state,
);
std::vector<double> solution = state.getApproximateMode();
cout << "Using Gaussian likelihood, the computed solution is:\n"
<< " computed: " << std::fixed;
for(auto x : solution) cout << setw(13) << x;
cout << "\n error: " << std::scientific;
for(int i=0; i<num_dimensions; i++) cout << setw(13) << std::abs(solution[i] - signal[i]);
cout << "\n\n";
auto model_likelihood = [&](std::vector<double> const &x,
std::vector<double> &y)->
void{
int num_samples = (int) x.size() / num_dimensions;
int num_threads = std::min((int) std::thread::hardware_concurrency(), 4);
std::vector<std::thread> workers(num_threads);
for(int start = 0; start<num_threads; start++){
workers[start] = std::thread([&, start]()->
void{
for(int i=start; i<num_samples; i+=num_threads){
std::vector<double> single_input(&x[i*num_dimensions],
&x[i*num_dimensions] + num_dimensions);
std::vector<double> single_output(num_discrete_nodes);
model(single_input, single_output);
y[i] = 0.0;
for(int j=0; j<num_discrete_nodes; j++)
y[i] += std::abs(single_output[j] - data[j]);
y[i] = - double(num_discrete_nodes/2) * y[i];
}
});
}
for(auto &w : workers) w.join();
};
state.setState(initial_chains);
(num_burnup_iterations, num_sample_iterations,
(model_likelihood,
state,
);
solution = state.getApproximateMode();
cout << "Using l-1 likelihood, the computed solution is:\n"
<< " computed: " << std::fixed;
for(auto x : solution) cout << setw(13) << x;
cout << "\n error: " << std::scientific;
for(int i=0; i<num_dimensions; i++) cout << setw(13) << std::abs(solution[i] - signal[i]);
cout << "\n\n";
#ifndef __TASMANIAN_DOXYGEN_SKIP