12#ifndef RESPOND_HISTORY_HPP_
13#define RESPOND_HISTORY_HPP_
15#include <respond/constants.hpp>
16#include <respond/logging.hpp>
29enum class HistoryMode :
int {
39inline HistoryMode GetDefaultHistoryMode(
const std::string &name) {
40 if (name ==
"intervention_admission" || name ==
"total_overdose" ||
41 name ==
"fatal_overdose" || name ==
"background_death") {
42 return HistoryMode::kAccumulated;
44 return HistoryMode::kSnapshot;
67 :
History(name, GetDefaultHistoryMode(name)) {}
72 History(
const std::string &name,
const HistoryMode &mode)
73 :
History(name, mode, RESPOND_DEFAULT_LOG, RESPOND_DEFAULT_LOG_FILE) {}
79 History(
const std::string &name,
const HistoryMode &mode,
80 const std::string &log_name)
81 :
History(name, mode, log_name, RESPOND_DEFAULT_LOG_FILE) {}
86 History(
const std::string &name,
const std::string &log_name)
87 :
History(name, GetDefaultHistoryMode(name), log_name,
88 RESPOND_DEFAULT_LOG_FILE) {}
95 History(
const std::string &name,
const std::string &log_name,
96 const std::string &log_filepath)
97 :
History(name, GetDefaultHistoryMode(name), log_name, log_filepath) {}
105 History(
const std::string &name,
const HistoryMode &mode,
106 const std::string &log_name,
const std::string &log_filepath)
107 : _name(name), _mode(mode), _log_name(log_name) {
108 CreateFileLogger(log_name, log_filepath);
120 _log_name = other._log_name;
129 if (
this != &other) {
133 _log_name = other._log_name;
144 _timesteps = std::move(other._timesteps);
145 _states = std::move(other._states);
147 _log_name = other._log_name;
149 _pending_state = std::move(other._pending_state);
156 if (
this != &other) {
157 _timesteps = std::move(other._timesteps);
158 _states = std::move(other._states);
160 _log_name = other._log_name;
162 _pending_state = std::move(other._pending_state);
179 void AddState(
const Eigen::Ref<const Eigen::VectorXd> &state,
182 timestep = GetNextTimestep();
185 const auto existing =
186 std::find(_timesteps.begin(), _timesteps.end(), timestep);
187 if (existing != _timesteps.end()) {
189 static_cast<size_t>(existing - _timesteps.begin());
190 _states[index] = state;
194 _timesteps.push_back(timestep);
195 _states.push_back(state);
201 if (_mode != HistoryMode::kAccumulated) {
202 LogWarning(_log_name,
"AccumulateState called on non-accumulated "
203 "history, adding state instead: " +
209 if (_pending_state.size() == 0) {
210 _pending_state = state;
213 _pending_state += state;
220 if (_mode != HistoryMode::kAccumulated) {
222 "FlushPendingState called on non-accumulated history, "
223 "no pending state to flush: " +
228 Eigen::VectorXd value;
229 if (_pending_state.size() > 0) {
230 value = _pending_state;
233 "FlushPendingState called with no pending state, "
234 "recording zero vector: " +
236 value = Eigen::VectorXd::Zero(state_size);
240 _pending_state.resize(0);
247 _pending_state.resize(0);
263 std::map<int, Eigen::VectorXd> state_map;
264 for (
size_t index = 0; index < _timesteps.size(); ++index) {
265 state_map[_timesteps[index]] = _states[index];
291 if (_timesteps.empty()) {
292 LogWarning(_log_name,
293 "GetLatestRecordedTimestep called on empty history: " +
297 return _timesteps.back();
309 std::vector<Eigen::VectorXd> ret;
310 if (_states.empty()) {
311 LogWarning(_log_name,
312 "GetStateAsVector called on empty history: " + _name);
315 int default_size = _states.front().size();
317 for (
size_t index = 0; index < _timesteps.size(); ++index) {
318 const int recorded_timestep = _timesteps[index];
319 const auto &recorded_state = _states[index];
320 while (recorded_timestep > tstep) {
321 ret.push_back(GetZeroVector(default_size));
324 ret.push_back(recorded_state);
340 return _name == other._name && _log_name == other._log_name &&
350 friend std::ostream &operator<<(std::ostream &os,
const History &history) {
351 os <<
"History(name=" << history._name <<
", timesteps=[";
352 for (
const auto &t : history._timesteps) {
355 os <<
"], pending_state=" << history._pending_state.transpose() <<
")";
361 std::string _log_name;
367 std::vector<int> _timesteps;
369 std::vector<Eigen::VectorXd> _states;
371 Eigen::VectorXd _pending_state;
376 int GetNextTimestep() {
377 if (_timesteps.empty()) {
380 return _timesteps.back() + 1;
386 Eigen::VectorXd GetZeroVector(
const int &size)
const {
387 return Eigen::VectorXd::Zero(size);
Tracks and manages state vector history over time. History records state snapshots at discrete timest...
Definition: history.hpp:51
History(const std::string &name, const std::string &log_name)
Constructs a history with a specified name and logger.
Definition: history.hpp:86
std::string GetName() const
Retrieves the identifier name of this history.
Definition: history.hpp:302
History & operator=(const History &other)
Copy assignment operator implementing the Rule of Five.
Definition: history.hpp:128
Eigen::VectorXd GetPendingState() const
Retrieves the pending accumulated state.
Definition: history.hpp:286
const std::vector< Eigen::VectorXd > & GetRecordedStates() const
Retrieves the recorded state vectors without densifying gaps.
Definition: history.hpp:276
History(const std::string &name, const HistoryMode &mode)
Constructs a history with a specified name and mode.
Definition: history.hpp:72
History(const std::string &name, const std::string &log_name, const std::string &log_filepath)
Constructs a history with a specified name, logger, and log file path.
Definition: history.hpp:95
History & operator=(History &&other) noexcept
Move assignment operator implementing the Rule of Five.
Definition: history.hpp:155
~History()=default
Destructor (default).
History(const std::string &name, const HistoryMode &mode, const std::string &log_name)
Constructs a history with a specified name, mode, and logger.
Definition: history.hpp:79
History()
Default constructor initializing a history with the default name "state" and default mode based on th...
Definition: history.hpp:61
void Clear()
Clears all recorded state history.
Definition: history.hpp:244
History(const std::string &name)
Constructs a history with a specified name, using the default mode based on that name.
Definition: history.hpp:66
History(const History &other)
Copy constructor implementing the Rule of Five. Creates an independent copy of the history state and ...
Definition: history.hpp:116
int GetLatestRecordedTimestep() const
Retrieves the latest recorded timestep.
Definition: history.hpp:290
std::map< int, Eigen::VectorXd > GetStateMap() const
Retrieves the complete state map (timestep -> state vector).
Definition: history.hpp:262
History(const std::string &name, const HistoryMode &mode, const std::string &log_name, const std::string &log_filepath)
Constructs a history with a specified name, mode, logger, and log file path.
Definition: history.hpp:105
std::vector< Eigen::VectorXd > GetStateAsVector() const
Converts the sparse history map to a contiguous vector of states. Gaps in timesteps are filled with z...
Definition: history.hpp:308
bool operator!=(const History &other) const
Inequality comparison operator.
Definition: history.hpp:348
History(History &&other) noexcept
Move constructor implementing the Rule of Five.
Definition: history.hpp:143
void FlushPendingState(int timestep, Eigen::Index state_size)
Flushes pending accumulated state into a recorded timestep.
Definition: history.hpp:219
HistoryMode GetHistoryMode() const
Retrieves the configured history recording mode.
Definition: history.hpp:282
bool HasPendingState() const
Indicates whether an accumulated history has pending state.
Definition: history.hpp:252
void AccumulateState(const Eigen::Ref< const Eigen::VectorXd > &state)
Adds a contribution to an accumulated history.
Definition: history.hpp:200
void AddState(const Eigen::Ref< const Eigen::VectorXd > &state, int timestep=-1)
Records a state vector at a specific or automatic timestep.
Definition: history.hpp:179
bool operator==(const History &other) const
Equality comparison operator.
Definition: history.hpp:339
const std::vector< int > & GetRecordedTimesteps() const
Retrieves the recorded timesteps without densifying gaps.
Definition: history.hpp:272