Program Listing for File Node.cpp
↰ Return to documentation for file (lib/Node.cpp
)
#include "Node.hpp"
using namespace std;
void Node::clear_state()
{
this->generated_latent_sequence.clear();
this->tot_observations = 0;
this->fourier_coefficients.resize(0);
this->best_fourier_coefficients.resize(0);
this->fourier_freqs.clear();
this->best_rmse = std::numeric_limits<double>::infinity();
this->n_components = 0;
this->best_n_components = 0;
this->rmse_is_reducing = true;
this->between_bin_midpoints.clear();
this->partitioned_data.clear();
this->partitioned_absolute_change.clear();
this->partitioned_relative_change.clear();
this->partition_mean_std.clear();
this->absolute_change_medians.clear();
this->relative_change_medians.clear();
this->centers.clear();
this->spreads.clear();
this->changes.clear();
this->generated_latent_centers_for_a_period.clear();
this->generated_latent_spreads_for_a_period.clear();
}
void Node::compute_bin_centers_and_spreads(const vector<int> &ts_sequence,
const vector<double> &mean_sequence) {
double center;
vector<int> filled_observation_timesteps_within_a_period;
this->centers = vector<double>(this->period + 1);
this->spreads = vector<double>(this->period);
this->generated_latent_centers_for_a_period = vector<double>(this->period, 0);
this->generated_latent_spreads_for_a_period = vector<double>(this->period, 0);
for (const auto & [ partition, data ] : this->partitioned_data) {
if (this->center_measure.compare("mean") == 0) {
center = delphi::utils::mean(data.second);
} else {
center = delphi::utils::median(data.second);
}
this->centers[partition] = center;
double spread = 0;
if (data.second.size() > 1) {
if (this->center_measure.compare("mean") == 0) {
spread = delphi::utils::standard_deviation(center,
data.second);
} else {
spread = delphi::utils::median_absolute_deviation(center,
data.second);
}
}
this->spreads[partition] = spread;
if (!data.first.empty()) {
this->generated_latent_centers_for_a_period[partition]
= center;
this->generated_latent_spreads_for_a_period[partition]
= spread;
filled_observation_timesteps_within_a_period.push_back(
partition);
}
}
sort(filled_observation_timesteps_within_a_period.begin(),
filled_observation_timesteps_within_a_period.end());
// Linear interpolate values for the empty bins within a period
if (filled_observation_timesteps_within_a_period.size() > 1) {
// There are more than one bin with data. We could linear interpolate
// between them.
for (int i = 0; i < filled_observation_timesteps_within_a_period.size();
i++) {
int observation_timestep_within_a_period_start =
filled_observation_timesteps_within_a_period[i];
int observation_timestep_within_a_period_end =
filled_observation_timesteps_within_a_period
[(i + 1) %
filled_observation_timesteps_within_a_period.size()];
// Compute the number of empty bins between two consecutive bins
// with data.
int num_missing_observation_timesteps = 0;
if (observation_timestep_within_a_period_end >
observation_timestep_within_a_period_start) {
num_missing_observation_timesteps =
observation_timestep_within_a_period_end -
observation_timestep_within_a_period_start - 1;
}
else {
num_missing_observation_timesteps =
(this->period - 1 -
observation_timestep_within_a_period_start) +
observation_timestep_within_a_period_end;
}
// Linear interpolate centers and spreads for empty bins
for (int missing_observation_timestep = 1;
missing_observation_timestep <= num_missing_observation_timesteps;
missing_observation_timestep++) {
this->generated_latent_centers_for_a_period
[(observation_timestep_within_a_period_start +
missing_observation_timestep) % this->period] =
((num_missing_observation_timesteps -
missing_observation_timestep + 1) *
this->generated_latent_centers_for_a_period
[observation_timestep_within_a_period_start] +
(missing_observation_timestep) *
this->generated_latent_centers_for_a_period
[observation_timestep_within_a_period_end]) /
(num_missing_observation_timesteps + 1);
this->generated_latent_spreads_for_a_period
[(observation_timestep_within_a_period_start +
missing_observation_timestep) % this->period] =
((num_missing_observation_timesteps -
missing_observation_timestep + 1) *
this->generated_latent_spreads_for_a_period
[observation_timestep_within_a_period_start] +
(missing_observation_timestep) *
this->generated_latent_spreads_for_a_period
[observation_timestep_within_a_period_end]) /
(num_missing_observation_timesteps + 1);
}
}
} else if (filled_observation_timesteps_within_a_period.size() == 1) {
// There is only one bin with data. Copy the center and spread of that
// bin to all the other bins.
for (int observation_timestep = 0;
observation_timestep < this->generated_latent_centers_for_a_period.size();
observation_timestep++) {
this->generated_latent_centers_for_a_period[observation_timestep] =
this->generated_latent_centers_for_a_period
[filled_observation_timesteps_within_a_period[0]];
this->generated_latent_spreads_for_a_period[observation_timestep] =
this->generated_latent_spreads_for_a_period
[filled_observation_timesteps_within_a_period[0]];
}
}
this->changes = vector<double>(this->centers.size(), 0.0);
this->centers[this->period] = this->centers[0];
if (this->model.compare("center") != 0) {
// model == absolute_change
adjacent_difference(this->centers.begin(), this->centers.end(),
this->changes.begin());
if (this->model.compare("relative_change") == 0) {
transform(this->centers.begin(),
this->centers.end() - 1,
this->changes.begin() + 1,
this->changes.begin() + 1,
[&](double start_value, double abs_change) {
return abs_change / (start_value + 1);
});
}
}
// Experiment: First calculate adjacent changes, then partition changes
// and compute the center of each changes partition
/*
// Absolute changes
vector<double> absolute_change = vector<double>(mean_sequence.size());
adjacent_difference(mean_sequence.begin(),
mean_sequence.end(),
absolute_change.begin());
// Relative changes
vector<double> relative_change = vector<double>(mean_sequence.size() - 1);
transform(mean_sequence.begin(), mean_sequence.end() - 1,
absolute_change.begin() + 1, relative_change.begin(),
[&](double start_value, double abs_change)
{return abs_change / (start_value + 1);});
// Partition changes
for (int ts = 0; ts < relative_change.size(); ts++) {
int partition = ts % this->period;
this->partitioned_absolute_change[partition].first.push_back(ts_sequence[ts]);
this->partitioned_absolute_change[partition].second.push_back(absolute_change[ts + 1]);
this->partitioned_relative_change[partition].first.push_back(ts_sequence[ts]);
this->partitioned_relative_change[partition].second.push_back(relative_change[ts]);
}
// Compute partition centers
//this->changes = vector<double>(this->period + 1);
for (const auto & [ partition, data ] : this->partitioned_absolute_change) {
double partition_median = delphi::utils::median(data.second);
this->changes[partition + 1] = partition_median;
}
//for (const auto & [ partition, data ] : this->partitioned_relative_change) {
// double partition_median = delphi::utils::median(data.second);
// this->changes[partition + 1] = partition_median;
//}
// Experimenting with zero centering the centers
//vector<double> only_changes = vector<double>(this->changes.begin() + 1, this->changes.end());
//double change_mean = delphi::utils::mean(only_changes);
//transform(this->changes.begin() + 1, this->changes.end(),
// this->changes.begin() + 1,
// [&](double val){return val - change_mean;});
*/
}
void Node::linear_interpolate_between_bin_midpoints(
std::vector<int> &ts_sequence,
std::vector<double> &mean_sequence) {
for (int mean_seq_idx = 0; mean_seq_idx < ts_sequence.size() - 1;
mean_seq_idx++) {
if (ts_sequence[mean_seq_idx] == ts_sequence[mean_seq_idx + 1] - 1) {
// We have two consecutive time points with observations. So, we
// could compute a between bin midpoint. We place the midpoints
// between bin b and bin (b+1) % period in midpoint bin b.
int partition = ts_sequence[mean_seq_idx] % this->period;
this->between_bin_midpoints[partition].push_back(
(mean_sequence[mean_seq_idx] +
mean_sequence[mean_seq_idx + 1]) / 2.0);
}
}
}