Program Listing for File Node.hpp
↰ Return to documentation for file (lib/Node.hpp
)
#pragma once
#include <iostream>
#include <map>
#include "utils.hpp"
#include "Indicator.hpp"
#include "exceptions.hpp"
#include <limits.h>
#include "definitions.h"
#include <Eigen/Dense>
class Node {
public:
std::string name = "";
double mean = 0;
double std = 1;
std::vector<double> generated_latent_sequence = {};
int period = 1;
DataAggregationLevel agg_level = DataAggregationLevel::MONTHLY;
// Utilized only for head nodes with period > 1
int tot_observations = 0;
Eigen::VectorXd fourier_coefficients;
Eigen::VectorXd best_fourier_coefficients;
std::vector<double> fourier_freqs;
double best_rmse = std::numeric_limits<double>::infinity();
int n_components = 0;
int best_n_components = 0;
bool rmse_is_reducing = true;
// Partition i refer to the midpoint between partitions i and (i+1) % period
// Access:
// {partition --> [data value]}
std::unordered_map<int, std::vector<double>> between_bin_midpoints;
// Access:
// {partition --> ([time step], [data value])}
std::unordered_map<int, std::pair<std::vector<int>, std::vector<double>>> partitioned_data = {};
std::unordered_map<int, std::pair<std::vector<int>, std::vector<double>>> partitioned_absolute_change = {};
std::unordered_map<int, std::pair<std::vector<int>, std::vector<double>>> partitioned_relative_change = {};
std::unordered_map<int, std::pair<double, double>> partition_mean_std = {};
std::vector<double> absolute_change_medians = {};
std::vector<double> relative_change_medians = {};
std::vector<double> centers = {};
std::vector<double> spreads = {};
std::vector<double> changes = {};
std::vector<double> generated_latent_centers_for_a_period;
std::vector<double> generated_latent_spreads_for_a_period;
std::string center_measure = "mean"; // median or mean
std::string model = "center"; // center, absolute_change, relative_change
// Tracks whether bounds are available for this node
bool has_max = false;
bool has_min = false;
// Latent space bounds
double max_val = std::numeric_limits<double>::max();
double min_val = std::numeric_limits<double>::min();
// Observation space bounds for the first indicator attached to this node
// latent bound = observation bound / scaling factor
double max_val_obs = std::numeric_limits<double>::max();
double min_val_obs = std::numeric_limits<double>::min();
bool visited;
LatentVar rv;
std::string to_string() { return this->name; }
std::vector<Indicator> indicators;
// Maps each indicator name to its index in the indicators vector
std::map<std::string, int> nameToIndexMap;
int add_indicator(std::string indicator, std::string source) {
// TODO: What if this indicator already exists?
// At the moment only the last indicator is recorded
// in the nameToIndexMap map
// What if this indicator already exists?
//*Loren: We just say it's already attached and do nothing.
// As of right now, we are only attaching one indicator per node but even
// if we were attaching multiple indicators to one node, I can't yet think
// of a case where the numerical id (i.e. the order) matters. If we do come
// across that case, we will just write a function that swaps ids.*
if (delphi::utils::in(this->nameToIndexMap,indicator)) {
std::cout << indicator << " already attached to " << name << std::endl;
return -1;
}
this->nameToIndexMap[indicator] = this->indicators.size();
this->indicators.push_back(Indicator(indicator, source));
return this->indicators.size() - 1;
}
void delete_indicator(std::string indicator) {
if (delphi::utils::in(this->nameToIndexMap, indicator)) {
int ind_index = this->nameToIndexMap.at(indicator);
this->nameToIndexMap.clear();
this->indicators.erase(this->indicators.begin() + ind_index);
// The values of the map object have to align with the vecter indexes.
for (unsigned long int i = 0; i < this->indicators.size(); i++) {
this->nameToIndexMap.at(this->indicators[i].get_name()) = i;
}
}
else {
std::cout << "There is no indicator " << indicator << "attached to "
<< name << std::endl;
}
}
Indicator& get_indicator(std::string indicator) {
try {
return this->indicators[this->nameToIndexMap.at(indicator)];
}
catch (const std::out_of_range& oor) {
throw IndicatorNotFoundException(indicator);
}
}
void replace_indicator(std::string indicator_old,
std::string indicator_new,
std::string source) {
auto map_entry = this->nameToIndexMap.extract(indicator_old);
if (map_entry) // indicator_old is in the map
{
// Update the map entry and add the new indicator
// in place of the old indicator
map_entry.key() = indicator_new;
this->nameToIndexMap.insert(move(map_entry));
this->indicators[map_entry.mapped()] = Indicator(indicator_new, source);
}
else // indicator_old is not attached to this node
{
std::cout << "Node::replace_indicator - indicator " << indicator_old
<< " is not attached to node " << name << std::endl;
std::cout << "\tAdding indicator " << indicator_new << " afresh\n";
this->add_indicator(indicator_new, source);
}
}
// Utility function that clears the indicators vector and the name map.
void clear_indicators() {
this->indicators.clear();
this->nameToIndexMap.clear();
}
void print_indicators() {
for (auto [ind, id] : this->nameToIndexMap) {
std::cout << ind << " -> " << id << std::endl;
}
std::cout << std::endl;
}
void clear_state();
void compute_bin_centers_and_spreads(const std::vector<int> &ts_sequence,
const std::vector<double> &mean_sequence);
void linear_interpolate_between_bin_midpoints(std::vector<int> &ts_sequence,
std::vector<double> &mean_sequence);
};