.. _program_listing_file_lib_Node.cpp: Program Listing for File Node.cpp ================================= |exhale_lsh| :ref:`Return to documentation for file ` (``lib/Node.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: 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::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 &ts_sequence, const vector &mean_sequence) { double center; vector filled_observation_timesteps_within_a_period; this->centers = vector(this->period + 1); this->spreads = vector(this->period); this->generated_latent_centers_for_a_period = vector(this->period, 0); this->generated_latent_spreads_for_a_period = vector(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(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 absolute_change = vector(mean_sequence.size()); adjacent_difference(mean_sequence.begin(), mean_sequence.end(), absolute_change.begin()); // Relative changes vector relative_change = vector(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(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 only_changes = vector(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 &ts_sequence, std::vector &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); } } }