RESPOND 2.5.1
Researching Effective Strategies to Prevent Opioid Death
Loading...
Searching...
No Matches
timestep.hpp
1
2// File: timestep.hpp //
3// Project: respond //
4// Created Date: 2026-06-30 //
5// Author: Matthew Carroll //
6// ----- //
7// Last Modified: 2026-09-24 //
8// Modified By: Matthew Carroll //
9// ----- //
10// Copyright (c) 2026 Syndemics Lab at Boston Medical Center //
12#ifndef RESPOND_TIMESTEP_HPP_
13#define RESPOND_TIMESTEP_HPP_
14
15#include <memory>
16#include <ostream>
17#include <vector>
18
19#include <respond/constants.hpp>
20#include <respond/logging.hpp>
21#include <respond/logging_config.hpp>
22#include <respond/transition.hpp>
23
24namespace respond {
25
31class Timestep {
32public:
35 public:
36 TransitionSlotProxy(Timestep &owner, size_t idx)
37 : _owner(&owner), _idx(idx) {}
38
41 return &_owner->GetTransitionRefOrThrow(_idx);
42 }
43
46 return _owner->GetTransitionRefOrThrow(_idx);
47 }
48
50 operator Transition &() {
51 return _owner->GetTransitionRefOrThrow(_idx);
52 }
53
56 return *this = static_cast<const Transition &>(
57 other._owner->GetTransitionRefOrThrow(other._idx));
58 }
59
62 _owner->GetTransitionRefOrThrow(_idx);
63 _owner->_transitions[_idx] = transition.clone();
64 return *this;
65 }
66
70 operator=(const std::unique_ptr<Transition> &transition) {
71 if (!transition) {
72 LogError(_owner->_log_name,
73 "Cannot assign null model pointer to simulation "
74 "slot.");
75 throw std::invalid_argument(
76 "Error attempting to assign null model pointer.");
77 }
78 _owner->GetTransitionRefOrThrow(_idx);
79 _owner->_transitions[_idx] = transition->clone();
80 return *this;
81 }
82
83 private:
84 Timestep *_owner;
85 size_t _idx;
86 };
87
89 //
90 // Rule of Five: Copy and Move Semantics
91 //
93
97
101 [[deprecated("Use Timestep(LoggingConfig) instead")]]
102 Timestep(const std::string &log_name)
103 : Timestep(log_name, RESPOND_DEFAULT_LOG_FILE) {}
104
110 [[deprecated("Use Timestep(LoggingConfig) instead")]]
111 Timestep(const std::string &log_name, const std::string &log_filepath)
112 : Timestep(LoggingConfig{log_name, log_filepath, false}) {}
113
114 explicit Timestep(const LoggingConfig &logging_config)
115 : _log_name(logging_config.logger_name),
116 _logging_config(logging_config) {
117 if (ConfigureLogger(_logging_config) == CreationStatus::kError) {
118 throw std::runtime_error(
119 "Error attempting to initialize timestep logger.");
120 }
121 }
122
124 ~Timestep() = default;
125
129 Timestep(const Timestep &other)
130 : _log_name(other._log_name), _logging_config(other._logging_config) {
131 for (const auto &t : other._transitions) {
132 _transitions.push_back(std::move(t->clone()));
133 }
134 }
135
140 Timestep &operator=(const Timestep &other) {
141 if (this != &other) {
142 std::vector<std::unique_ptr<Transition>> transitions;
143 for (const auto &t : other._transitions) {
144 transitions.push_back(t->clone());
145 }
146 _log_name = other._log_name;
147 _logging_config = other._logging_config;
148 _transitions = std::move(transitions);
149 }
150 return *this;
151 }
152
156 Timestep(Timestep &&other) noexcept
157 : _log_name(std::move(other._log_name)),
158 _logging_config(std::move(other._logging_config)),
159 _transitions(std::move(other._transitions)) {
160 other._transitions.clear();
161 }
162
167 Timestep &operator=(Timestep &&other) noexcept {
168 if (this != &other) {
169 _log_name = std::move(other._log_name);
170 _logging_config = std::move(other._logging_config);
171 _transitions = std::move(other._transitions);
172 other._transitions.clear();
173 }
174 return *this;
175 }
176
178 //
179 // Timestep Behavior Methods: Transition Management
180 //
182
194 const std::unique_ptr<Transition> &
195 CreateTransition(const std::string &transition_name) {
196 _transitions.push_back(Transition::Create(
197 transition_name, transition_name, _logging_config));
198 return _transitions.back();
199 }
200
204 void AddTransition(const std::unique_ptr<Transition> &transition) {
205 if (!transition) {
206 LogError(_log_name,
207 "Cannot add a null transition to the timestep.");
208 throw std::invalid_argument(
209 "Error attempting to add a null transition to timestep.");
210 }
211 _transitions.push_back(transition->clone());
212 }
213
219 std::unique_ptr<Transition> RemoveTransition(size_t idx) {
220 if (idx >= _transitions.size()) {
221 LogWarning(_log_name, "Index out of range in RemoveTransition: " +
222 std::to_string(idx));
223 throw std::out_of_range(
224 "Error attempting to RemoveTransition by index.");
225 }
226 auto removed_transition = std::move(_transitions[idx]);
227 _transitions.erase(_transitions.begin() + idx);
228 return removed_transition;
229 }
230
236 void AddMatrixToTransition(const size_t &idx,
237 const Eigen::Ref<const Eigen::MatrixXd> &m) {
238 if (idx >= _transitions.size()) {
239 LogError(_log_name,
240 "Index out of range in AddMatrixToTransition: " +
241 std::to_string(idx));
242 throw std::out_of_range(
243 "Error attempting to AddMatrixToTransition by index.");
244 }
245 _transitions[idx]->AddMatrix(m);
246 }
247
254 void AddMatrixToTransition(const std::string &transition_name,
255 const Eigen::Ref<const Eigen::MatrixXd> &m) {
256 for (size_t i = 0; i < _transitions.size(); ++i) {
257 if (_transitions[i]->GetName() == transition_name) {
258 _transitions[i]->AddMatrix(m);
259 return;
260 }
261 }
262 LogError(_log_name, "Transition not found in AddMatrixToTransition: " +
263 transition_name);
264 throw std::invalid_argument(
265 "Error attempting to AddMatrixToTransition by name: " +
266 transition_name);
267 }
268
270 //
271 // Getters and Setters for Transitions and Metadata
272 //
274
280 const std::unique_ptr<Transition> &GetTransition(const size_t &idx) const {
281 if (idx >= _transitions.size()) {
282 LogError(_log_name, "Index out of range in GetTransition: " +
283 std::to_string(idx));
284 throw std::out_of_range(
285 "Error attempting to GetTransition by index.");
286 }
287 return _transitions[idx];
288 }
289
295 const std::unique_ptr<Transition> &
296 GetTransition(const std::string &transition_name) const {
297 for (const auto &t : _transitions) {
298 if (t->GetName() == transition_name) {
299 return t;
300 }
301 }
302 LogError(_log_name,
303 "Transition not found in GetTransition: " + transition_name);
304 throw std::invalid_argument(
305 "Error attempting to GetTransition by name.");
306 }
307
313 std::vector<std::unique_ptr<Transition>> GetTransitions() const {
314 std::vector<std::unique_ptr<Transition>> _ret;
315 for (const auto &t : _transitions) {
316 _ret.push_back(t->clone());
317 }
318 return _ret;
319 }
320
324 std::vector<std::string> GetTransitionNames() const {
325 std::vector<std::string> names;
326 for (const auto &t : _transitions) {
327 names.push_back(t->GetName());
328 }
329 return names;
330 }
331
333 //
334 // Logging and Output Methods
335 //
337
345 GetTransitionRefOrThrow(idx);
346 return TransitionSlotProxy(*this, idx);
347 }
348
353 const Transition &operator[](size_t idx) const {
354 return GetTransitionRefOrThrow(idx);
355 }
356
367 friend std::ostream &operator<<(std::ostream &os, const Timestep &other) {
368 os << "Timestep with the following transitions:\n";
369 for (const auto &t : other._transitions) {
370 os << " - " << t->GetName() << "\n";
371 }
372 return os;
373 }
374
382 bool operator==(const Timestep &other) const {
383 if (_transitions.size() != other._transitions.size()) {
384 return false;
385 }
386 for (size_t i = 0; i < _transitions.size(); ++i) {
387 if (_transitions[i]->GetName() !=
388 other._transitions[i]->GetName()) {
389 return false;
390 }
391 if (_transitions[i]->GetMatrices().size() !=
392 other._transitions[i]->GetMatrices().size()) {
393 return false;
394 }
395 for (size_t j = 0; j < _transitions[i]->GetMatrices().size(); ++j) {
396 if (!_transitions[i]->GetMatrices()[j].isApprox(
397 other._transitions[i]->GetMatrices()[j])) {
398 return false;
399 }
400 }
401 }
402 return true;
403 }
404
412 bool operator!=(const Timestep &other) const { return !(*this == other); }
413
414private:
415 Transition &GetTransitionRefOrThrow(size_t idx) {
416 if (idx >= _transitions.size()) {
417 LogError(_log_name, "Index out of range in transition access: " +
418 std::to_string(idx));
419 throw std::out_of_range("Error attempting to access transition by "
420 "index.");
421 }
422 return *_transitions[idx];
423 }
424
425 const Transition &GetTransitionRefOrThrow(size_t idx) const {
426 if (idx >= _transitions.size()) {
427 LogError(_log_name, "Index out of range in transition access: " +
428 std::to_string(idx));
429 throw std::out_of_range("Error attempting to access transition by "
430 "index.");
431 }
432 return *_transitions[idx];
433 }
434
435 std::string _log_name;
436 LoggingConfig _logging_config;
437 std::vector<std::unique_ptr<Transition>> _transitions;
438};
439} // namespace respond
440
441#endif // RESPOND_TIMESTEP_HPP_
Proxy for mutable model slot access with clone-based assignment.
Definition: timestep.hpp:34
Transition * operator->()
Access the underlying model pointer for member access.
Definition: timestep.hpp:40
Transition & operator*()
Dereference to the underlying model.
Definition: timestep.hpp:45
TransitionSlotProxy & operator=(const TransitionSlotProxy &other)
Replace this slot by cloning from another proxy's model.
Definition: timestep.hpp:55
TransitionSlotProxy & operator=(const Transition &transition)
Replace this slot by cloning from a model reference.
Definition: timestep.hpp:61
TransitionSlotProxy & operator=(const std::unique_ptr< Transition > &transition)
Replace this slot by cloning from a model unique_ptr.
Definition: timestep.hpp:70
Represents a single timestep in a simulation, managing a collection of transitions....
Definition: timestep.hpp:31
const std::unique_ptr< Transition > & GetTransition(const size_t &idx) const
Retrieves a constant reference to a transition in this timestep by index.
Definition: timestep.hpp:280
friend std::ostream & operator<<(std::ostream &os, const Timestep &other)
Overloaded stream insertion operator for Timestep. Outputs the names of all transitions in the timest...
Definition: timestep.hpp:367
Timestep(const std::string &log_name)
Default constructor for Timestep with specified logger name. Initializes with default log file path.
Definition: timestep.hpp:102
Timestep & operator=(const Timestep &other)
Copy assignment operator for Timestep. Creates a deep copy of the transitions.
Definition: timestep.hpp:140
void AddTransition(const std::unique_ptr< Transition > &transition)
Adds a transition to the timestep. The transition is cloned and managed by the timestep.
Definition: timestep.hpp:204
void AddMatrixToTransition(const size_t &idx, const Eigen::Ref< const Eigen::MatrixXd > &m)
Adds a matrix to an existing transition in this timestep by index.
Definition: timestep.hpp:236
void AddMatrixToTransition(const std::string &transition_name, const Eigen::Ref< const Eigen::MatrixXd > &m)
Adds a matrix to an existing transition in this timestep by name.
Definition: timestep.hpp:254
std::vector< std::string > GetTransitionNames() const
Gets a vector of the names of all transitions in this timestep.
Definition: timestep.hpp:324
bool operator==(const Timestep &other) const
Overloaded equality operator for Timestep. Compares two Timestep instances for equality based on thei...
Definition: timestep.hpp:382
Timestep & operator=(Timestep &&other) noexcept
Move assignment operator for Timestep. Transfers ownership of transitions.
Definition: timestep.hpp:167
const std::unique_ptr< Transition > & CreateTransition(const std::string &transition_name)
Creates a transition of the specified type and adds it to this timestep.
Definition: timestep.hpp:195
const std::unique_ptr< Transition > & GetTransition(const std::string &transition_name) const
Gets a constant reference to a transition in this timestep by name.
Definition: timestep.hpp:296
bool operator!=(const Timestep &other) const
Overloaded inequality operator for Timestep. Compares two Timestep instances for inequality based on ...
Definition: timestep.hpp:412
Timestep(Timestep &&other) noexcept
Move constructor for Timestep. Transfers ownership of transitions.
Definition: timestep.hpp:156
Timestep()
Default constructor for Timestep. Initializes with default logger.
Definition: timestep.hpp:96
std::unique_ptr< Transition > RemoveTransition(size_t idx)
Removes a transition from this timestep by index and returns it.
Definition: timestep.hpp:219
const Transition & operator[](size_t idx) const
Const index-based transition access.
Definition: timestep.hpp:353
std::vector< std::unique_ptr< Transition > > GetTransitions() const
Gets a vector of unique_ptrs to all transitions in this timestep. The returned vector contains deep c...
Definition: timestep.hpp:313
Timestep(const std::string &log_name, const std::string &log_filepath)
Default constructor for Timestep with specified logger name and log file path.
Definition: timestep.hpp:111
TransitionSlotProxy operator[](size_t idx)
Mutable index-based transition access.
Definition: timestep.hpp:344
~Timestep()=default
Destructor for Timestep. Default implementation.
Timestep(const Timestep &other)
Copy constructor for Timestep. Creates a deep copy of the transitions.
Definition: timestep.hpp:129
Abstract base class representing a state transition operation. Transitions apply transformation matri...
Definition: transition.hpp:33
virtual std::unique_ptr< Transition > clone() const =0
Creates a deep copy of this transition.
static std::unique_ptr< Transition > Create(const std::string &type, const std::string &name=RESPOND_DEFAULT_TRANSITION_NAME, const std::string &log_name=RESPOND_DEFAULT_LOG, const std::string &log_file=RESPOND_DEFAULT_LOG_FILE)
Creates a transition of the specified type.
Describes the logging destination used by a library object.
Definition: logging_config.hpp:21