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-07-23 //
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/transition.hpp>
22
23namespace respond {
24
30class Timestep {
31public:
34 public:
35 TransitionSlotProxy(Timestep &owner, size_t idx)
36 : _owner(&owner), _idx(idx) {}
37
40 return &_owner->GetTransitionRefOrThrow(_idx);
41 }
42
45 return _owner->GetTransitionRefOrThrow(_idx);
46 }
47
49 operator Transition &() {
50 return _owner->GetTransitionRefOrThrow(_idx);
51 }
52
55 return *this = static_cast<const Transition &>(
56 other._owner->GetTransitionRefOrThrow(other._idx));
57 }
58
61 _owner->GetTransitionRefOrThrow(_idx);
62 _owner->_transitions[_idx] = transition.clone();
63 return *this;
64 }
65
69 operator=(const std::unique_ptr<Transition> &transition) {
70 if (!transition) {
71 LogError(_owner->_log_name,
72 "Cannot assign null model pointer to simulation "
73 "slot.");
74 throw std::invalid_argument(
75 "Error attempting to assign null model pointer.");
76 }
77 _owner->GetTransitionRefOrThrow(_idx);
78 _owner->_transitions[_idx] = transition->clone();
79 return *this;
80 }
81
82 private:
83 Timestep *_owner;
84 size_t _idx;
85 };
86
88 //
89 // Rule of Five: Copy and Move Semantics
90 //
92
95 Timestep() : Timestep(RESPOND_DEFAULT_LOG) {}
96
100 Timestep(const std::string &log_name)
101 : Timestep(log_name, RESPOND_DEFAULT_LOG_FILE) {}
102
108 Timestep(const std::string &log_name, const std::string &log_filepath)
109 : _log_name(log_name) {
110 CreateFileLogger(log_name, log_filepath);
111 }
112
114 ~Timestep() = default;
115
119 Timestep(const Timestep &other) {
120 _transitions.clear();
121 for (const auto &t : other._transitions) {
122 _transitions.push_back(std::move(t->clone()));
123 }
124 }
125
130 Timestep &operator=(const Timestep &other) {
131 if (this != &other) {
132 _transitions.clear();
133 for (const auto &t : other._transitions) {
134 _transitions.push_back(std::move(t->clone()));
135 }
136 }
137 return *this;
138 }
139
143 Timestep(Timestep &&other) noexcept
144 : _transitions(std::move(other._transitions)) {
145 other._transitions.clear();
146 }
147
152 Timestep &operator=(Timestep &&other) noexcept {
153 if (this != &other) {
154 _transitions = std::move(other._transitions);
155 other._transitions.clear();
156 }
157 return *this;
158 }
159
161 //
162 // Timestep Behavior Methods: Transition Management
163 //
165
177 const std::unique_ptr<Transition> &
178 CreateTransition(const std::string &transition_name) {
179 _transitions.push_back(
180 Transition::Create(transition_name, transition_name, _log_name));
181 return _transitions.back();
182 }
183
187 void AddTransition(const std::unique_ptr<Transition> &transition) {
188 _transitions.push_back(transition->clone());
189 }
190
196 std::unique_ptr<Transition> RemoveTransition(size_t idx) {
197 if (idx >= _transitions.size()) {
198 LogWarning(_log_name, "Index out of range in RemoveTransition: " +
199 std::to_string(idx));
200 throw std::out_of_range(
201 "Error attempting to RemoveTransition by index.");
202 }
203 auto removed_transition = std::move(_transitions[idx]);
204 _transitions.erase(_transitions.begin() + idx);
205 return removed_transition;
206 }
207
213 void AddMatrixToTransition(const size_t &idx,
214 const Eigen::Ref<const Eigen::MatrixXd> &m) {
215 if (idx >= _transitions.size()) {
216 LogError(_log_name,
217 "Index out of range in AddMatrixToTransition: " +
218 std::to_string(idx));
219 throw std::out_of_range(
220 "Error attempting to AddMatrixToTransition by index.");
221 }
222 _transitions[idx]->AddMatrix(m);
223 }
224
230 void AddMatrixToTransition(const std::string &transition_name,
231 const Eigen::Ref<const Eigen::MatrixXd> &m) {
232 for (size_t i = 0; i < _transitions.size(); ++i) {
233 if (_transitions[i]->GetName() == transition_name) {
234 _transitions[i]->AddMatrix(m);
235 return;
236 }
237 }
238 LogWarning(_log_name,
239 "Transition not found in AddMatrixToTransition: " +
240 transition_name);
241 }
242
244 //
245 // Getters and Setters for Transitions and Metadata
246 //
248
254 const std::unique_ptr<Transition> &GetTransition(const size_t &idx) const {
255 if (idx >= _transitions.size()) {
256 LogError(_log_name, "Index out of range in GetTransition: " +
257 std::to_string(idx));
258 throw std::out_of_range(
259 "Error attempting to GetTransition by index.");
260 }
261 return _transitions[idx];
262 }
263
269 const std::unique_ptr<Transition> &
270 GetTransition(const std::string &transition_name) const {
271 for (const auto &t : _transitions) {
272 if (t->GetName() == transition_name) {
273 return t;
274 }
275 }
276 LogError(_log_name,
277 "Transition not found in GetTransition: " + transition_name);
278 throw std::invalid_argument(
279 "Error attempting to GetTransition by name.");
280 }
281
287 std::vector<std::unique_ptr<Transition>> GetTransitions() const {
288 std::vector<std::unique_ptr<Transition>> _ret;
289 for (const auto &t : _transitions) {
290 _ret.push_back(t->clone());
291 }
292 return _ret;
293 }
294
298 std::vector<std::string> GetTransitionNames() const {
299 std::vector<std::string> names;
300 for (const auto &t : _transitions) {
301 names.push_back(t->GetName());
302 }
303 return names;
304 }
305
307 //
308 // Logging and Output Methods
309 //
311
319 GetTransitionRefOrThrow(idx);
320 return TransitionSlotProxy(*this, idx);
321 }
322
327 const Transition &operator[](size_t idx) const {
328 return GetTransitionRefOrThrow(idx);
329 }
330
341 friend std::ostream &operator<<(std::ostream &os, const Timestep &other) {
342 os << "Timestep with the following transitions:\n";
343 for (const auto &t : other._transitions) {
344 os << " - " << t->GetName() << "\n";
345 }
346 return os;
347 }
348
356 bool operator==(const Timestep &other) const {
357 if (_transitions.size() != other._transitions.size()) {
358 return false;
359 }
360 for (size_t i = 0; i < _transitions.size(); ++i) {
361 if (_transitions[i]->GetName() !=
362 other._transitions[i]->GetName()) {
363 return false;
364 }
365 if (_transitions[i]->GetMatrices().size() !=
366 other._transitions[i]->GetMatrices().size()) {
367 return false;
368 }
369 for (size_t j = 0; j < _transitions[i]->GetMatrices().size(); ++j) {
370 if (!_transitions[i]->GetMatrices()[j].isApprox(
371 other._transitions[i]->GetMatrices()[j])) {
372 return false;
373 }
374 }
375 }
376 return true;
377 }
378
386 bool operator!=(const Timestep &other) const { return !(*this == other); }
387
388private:
389 Transition &GetTransitionRefOrThrow(size_t idx) {
390 if (idx >= _transitions.size()) {
391 LogError(_log_name, "Index out of range in transition access: " +
392 std::to_string(idx));
393 throw std::out_of_range("Error attempting to access transition by "
394 "index.");
395 }
396 return *_transitions[idx];
397 }
398
399 const Transition &GetTransitionRefOrThrow(size_t idx) const {
400 if (idx >= _transitions.size()) {
401 LogError(_log_name, "Index out of range in transition access: " +
402 std::to_string(idx));
403 throw std::out_of_range("Error attempting to access transition by "
404 "index.");
405 }
406 return *_transitions[idx];
407 }
408
409 std::string _log_name;
410 std::vector<std::unique_ptr<Transition>> _transitions;
411};
412} // namespace respond
413
414#endif // RESPOND_TIMESTEP_HPP_
Proxy for mutable model slot access with clone-based assignment.
Definition: timestep.hpp:33
Transition * operator->()
Access the underlying model pointer for member access.
Definition: timestep.hpp:39
Transition & operator*()
Dereference to the underlying model.
Definition: timestep.hpp:44
TransitionSlotProxy & operator=(const TransitionSlotProxy &other)
Replace this slot by cloning from another proxy's model.
Definition: timestep.hpp:54
TransitionSlotProxy & operator=(const Transition &transition)
Replace this slot by cloning from a model reference.
Definition: timestep.hpp:60
TransitionSlotProxy & operator=(const std::unique_ptr< Transition > &transition)
Replace this slot by cloning from a model unique_ptr.
Definition: timestep.hpp:69
Represents a single timestep in a simulation, managing a collection of transitions....
Definition: timestep.hpp:30
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:254
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:341
Timestep(const std::string &log_name)
Default constructor for Timestep with specified logger name. Initializes with default log file path.
Definition: timestep.hpp:100
Timestep & operator=(const Timestep &other)
Copy assignment operator for Timestep. Creates a deep copy of the transitions.
Definition: timestep.hpp:130
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:187
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:213
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:230
std::vector< std::string > GetTransitionNames() const
Gets a vector of the names of all transitions in this timestep.
Definition: timestep.hpp:298
bool operator==(const Timestep &other) const
Overloaded equality operator for Timestep. Compares two Timestep instances for equality based on thei...
Definition: timestep.hpp:356
Timestep & operator=(Timestep &&other) noexcept
Move assignment operator for Timestep. Transfers ownership of transitions.
Definition: timestep.hpp:152
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:178
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:270
bool operator!=(const Timestep &other) const
Overloaded inequality operator for Timestep. Compares two Timestep instances for inequality based on ...
Definition: timestep.hpp:386
Timestep(Timestep &&other) noexcept
Move constructor for Timestep. Transfers ownership of transitions.
Definition: timestep.hpp:143
Timestep()
Default constructor for Timestep. Initializes with default logger.
Definition: timestep.hpp:95
std::unique_ptr< Transition > RemoveTransition(size_t idx)
Removes a transition from this timestep by index and returns it.
Definition: timestep.hpp:196
const Transition & operator[](size_t idx) const
Const index-based transition access.
Definition: timestep.hpp:327
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:287
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:108
TransitionSlotProxy operator[](size_t idx)
Mutable index-based transition access.
Definition: timestep.hpp:318
~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:119
Abstract base class representing a state transition operation. Transitions apply transformation matri...
Definition: transition.hpp:32
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.