12#ifndef RESPOND_HISTORY_HPP_
13#define RESPOND_HISTORY_HPP_
15#include <respond/constants.hpp>
16#include <respond/logging.hpp>
17#include <respond/logging_config.hpp>
32enum class HistoryMode :
int {
42inline HistoryMode GetDefaultHistoryMode(
const std::string &name) {
43 if (name ==
"intervention_admission" || name ==
"total_overdose" ||
44 name ==
"fatal_overdose" || name ==
"background_death") {
45 return HistoryMode::kAccumulated;
47 return HistoryMode::kSnapshot;
76 History(
const std::string &name,
const HistoryMode &mode)
83 [[deprecated(
"Use History(name, mode, LoggingConfig) instead")]]
84 History(
const std::string &name,
const HistoryMode &mode,
85 const std::string &log_name)
92 [[deprecated(
"Use History(name, LoggingConfig) instead")]]
93 History(
const std::string &name,
const std::string &log_name)
94 :
History(name, GetDefaultHistoryMode(name),
102 [[deprecated(
"Use History(name, LoggingConfig) instead")]]
103 History(
const std::string &name,
const std::string &log_name,
104 const std::string &log_filepath)
105 :
History(name, GetDefaultHistoryMode(name),
114 [[deprecated(
"Use History(name, mode, LoggingConfig) instead")]]
115 History(
const std::string &name,
const HistoryMode &mode,
116 const std::string &log_name,
const std::string &log_filepath)
120 :
History(name, GetDefaultHistoryMode(name), logging_config) {}
122 History(
const std::string &name,
const HistoryMode &mode,
123 const LoggingConfig &logging_config)
124 : _name(name), _mode(mode), _log_name(logging_config.logger_name),
125 _logging_config(logging_config) {
126 if (ConfigureLogger(_logging_config) == CreationStatus::kError) {
127 throw std::runtime_error(
128 "Error attempting to initialize history logger.");
141 _log_name = other._log_name;
142 _logging_config = other._logging_config;
151 if (
this != &other) {
155 _log_name = other._log_name;
156 _logging_config = other._logging_config;
167 : _timesteps(std::move(other._timesteps)),
168 _states(std::move(other._states)), _name(std::move(other._name)),
169 _log_name(std::move(other._log_name)),
170 _logging_config(std::move(other._logging_config)), _mode(other._mode),
171 _pending_state(std::move(other._pending_state)) {}
177 if (
this != &other) {
178 _timesteps = std::move(other._timesteps);
179 _states = std::move(other._states);
180 _name = std::move(other._name);
181 _log_name = std::move(other._log_name);
182 _logging_config = std::move(other._logging_config);
184 _pending_state = std::move(other._pending_state);
202 void AddState(
const Eigen::Ref<const Eigen::VectorXd> &state,
205 timestep = GetNextTimestep();
208 const auto insertion_point =
209 std::lower_bound(_timesteps.begin(), _timesteps.end(), timestep);
211 static_cast<size_t>(insertion_point - _timesteps.begin());
212 if (insertion_point != _timesteps.end() &&
213 *insertion_point == timestep) {
214 _states[index] = state;
218 _timesteps.insert(insertion_point, timestep);
219 _states.insert(_states.begin() +
static_cast<std::ptrdiff_t
>(index),
226 if (_mode != HistoryMode::kAccumulated) {
227 LogWarning(_log_name,
"AccumulateState called on non-accumulated "
228 "history, adding state instead: " +
234 if (_pending_state.size() == 0) {
235 _pending_state = state;
238 _pending_state += state;
245 if (_mode != HistoryMode::kAccumulated) {
247 "FlushPendingState called on non-accumulated history, "
248 "no pending state to flush: " +
253 Eigen::VectorXd value;
254 if (_pending_state.size() > 0) {
255 value = _pending_state;
258 "FlushPendingState called with no pending state, "
259 "recording zero vector: " +
261 value = Eigen::VectorXd::Zero(state_size);
265 _pending_state.resize(0);
272 _pending_state.resize(0);
288 std::map<int, Eigen::VectorXd> state_map;
289 for (
size_t index = 0; index < _timesteps.size(); ++index) {
290 state_map[_timesteps[index]] = _states[index];
316 if (_timesteps.empty()) {
317 LogWarning(_log_name,
318 "GetLatestRecordedTimestep called on empty history: " +
322 return _timesteps.back();
334 std::vector<Eigen::VectorXd> ret;
335 if (_states.empty()) {
336 LogWarning(_log_name,
337 "GetStateAsVector called on empty history: " + _name);
340 int default_size = _states.front().size();
342 for (
size_t index = 0; index < _timesteps.size(); ++index) {
343 const int recorded_timestep = _timesteps[index];
344 const auto &recorded_state = _states[index];
345 while (recorded_timestep > tstep) {
346 ret.push_back(GetZeroVector(default_size));
349 ret.push_back(recorded_state);
365 return _name == other._name && _log_name == other._log_name &&
366 _logging_config.logger_name ==
367 other._logging_config.logger_name &&
368 _logging_config.file_path == other._logging_config.file_path &&
369 _logging_config.use_shared_sink ==
370 other._logging_config.use_shared_sink &&
380 friend std::ostream &operator<<(std::ostream &os,
const History &history) {
381 os <<
"History(name=" << history._name <<
", timesteps=[";
382 for (
const auto &t : history._timesteps) {
385 os <<
"], pending_state=" << history._pending_state.transpose() <<
")";
391 std::string _log_name;
393 LoggingConfig _logging_config;
399 std::vector<int> _timesteps;
401 std::vector<Eigen::VectorXd> _states;
403 Eigen::VectorXd _pending_state;
408 int GetNextTimestep() {
409 if (_timesteps.empty()) {
412 return _timesteps.back() + 1;
418 Eigen::VectorXd GetZeroVector(
const int &size)
const {
419 return Eigen::VectorXd::Zero(size);
Tracks and manages state vector history over time. History records state snapshots at discrete timest...
Definition: history.hpp:54
History(const std::string &name, const std::string &log_name)
Constructs a history with a specified name and logger.
Definition: history.hpp:93
std::string GetName() const
Retrieves the identifier name of this history.
Definition: history.hpp:327
History & operator=(const History &other)
Copy assignment operator implementing the Rule of Five.
Definition: history.hpp:150
Eigen::VectorXd GetPendingState() const
Retrieves the pending accumulated state.
Definition: history.hpp:311
const std::vector< Eigen::VectorXd > & GetRecordedStates() const
Retrieves the recorded state vectors without densifying gaps.
Definition: history.hpp:301
History(const std::string &name, const HistoryMode &mode)
Constructs a history with a specified name and mode.
Definition: history.hpp:76
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:103
History & operator=(History &&other) noexcept
Move assignment operator implementing the Rule of Five.
Definition: history.hpp:176
~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:84
History()
Default constructor initializing a history with the default name "state" and default mode based on th...
Definition: history.hpp:64
void Clear()
Clears all recorded state history.
Definition: history.hpp:269
History(const std::string &name)
Constructs a history with a specified name, using the default mode based on that name.
Definition: history.hpp:70
History(const History &other)
Copy constructor implementing the Rule of Five. Creates an independent copy of the history state and ...
Definition: history.hpp:137
int GetLatestRecordedTimestep() const
Retrieves the latest recorded timestep.
Definition: history.hpp:315
std::map< int, Eigen::VectorXd > GetStateMap() const
Retrieves the complete state map (timestep -> state vector).
Definition: history.hpp:287
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:115
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:333
bool operator!=(const History &other) const
Inequality comparison operator.
Definition: history.hpp:378
History(History &&other) noexcept
Move constructor implementing the Rule of Five.
Definition: history.hpp:166
void FlushPendingState(int timestep, Eigen::Index state_size)
Flushes pending accumulated state into a recorded timestep.
Definition: history.hpp:244
HistoryMode GetHistoryMode() const
Retrieves the configured history recording mode.
Definition: history.hpp:307
bool HasPendingState() const
Indicates whether an accumulated history has pending state.
Definition: history.hpp:277
void AccumulateState(const Eigen::Ref< const Eigen::VectorXd > &state)
Adds a contribution to an accumulated history.
Definition: history.hpp:225
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:202
bool operator==(const History &other) const
Equality comparison operator.
Definition: history.hpp:364
const std::vector< int > & GetRecordedTimesteps() const
Retrieves the recorded timesteps without densifying gaps.
Definition: history.hpp:297
Describes the logging destination used by a library object.
Definition: logging_config.hpp:21