DiffEq - Modern C++ ODE Integration Library 1.0.0
High-performance C++ library for solving ODEs with async signal processing
Loading...
Searching...
No Matches
timeout_decorator.hpp
1#pragma once
2
3#include "integrator_decorator.hpp"
4#include <chrono>
5#include <future>
6#include <functional>
7#include <stdexcept>
8#include <string>
9#include <thread>
10
11namespace diffeq::core::composable {
12
17 std::chrono::milliseconds timeout_duration{5000};
18 bool throw_on_timeout{true};
19 bool enable_progress_callback{false};
20 std::chrono::milliseconds progress_interval{100};
21 std::function<bool(double, double, std::chrono::milliseconds)> progress_callback;
22
23 // Validation settings
24 bool validate_timeout_duration{true};
25 std::chrono::milliseconds min_timeout_duration{10}; // Minimum 10ms
26 std::chrono::milliseconds max_timeout_duration{std::chrono::hours{24}}; // Maximum 24h
27
32 void validate() const {
33 if (validate_timeout_duration) {
34 if (timeout_duration < min_timeout_duration) {
35 throw std::invalid_argument(
36 "Timeout duration " + std::to_string(timeout_duration.count()) +
37 "ms is below minimum " + std::to_string(min_timeout_duration.count()) + "ms");
38 }
39 if (timeout_duration > max_timeout_duration) {
40 throw std::invalid_argument(
41 "Timeout duration " + std::to_string(timeout_duration.count()) +
42 "ms exceeds maximum " + std::to_string(max_timeout_duration.count()) + "ms");
43 }
44 }
45
46 if (enable_progress_callback && !progress_callback) {
47 throw std::invalid_argument("Progress callback enabled but no callback provided");
48 }
49
50 if (progress_interval <= std::chrono::milliseconds{0}) {
51 throw std::invalid_argument("Progress interval must be positive");
52 }
53 }
54};
55
60 bool completed{false};
61 std::chrono::milliseconds elapsed_time{0};
62 double final_time{0.0};
63 std::string error_message;
64 bool user_cancelled{false};
65 size_t progress_callbacks_made{0};
66
67 bool is_success() const { return completed && error_message.empty() && !user_cancelled; }
68 bool is_timeout() const { return !completed && error_message.find("timeout") != std::string::npos; }
69 bool is_user_cancelled() const { return user_cancelled; }
70 bool is_error() const { return !completed && !error_message.empty() && !is_timeout(); }
71
75 std::string status_description() const {
76 if (is_success()) return "Integration completed successfully";
77 if (is_timeout()) return "Integration timed out";
78 if (is_user_cancelled()) return "Integration cancelled by user";
79 if (is_error()) return "Integration failed: " + error_message;
80 return "Integration status unknown";
81 }
82};
83
99template<system_state S>
101private:
102 TimeoutConfig config_;
103
104public:
111 explicit TimeoutDecorator(std::unique_ptr<AbstractIntegrator<S>> integrator,
113 : IntegratorDecorator<S>(std::move(integrator)), config_(std::move(config)) {
114 config_.validate();
115 }
116
124 TimeoutResult integrate_with_timeout(typename IntegratorDecorator<S>::state_type& state,
125 typename IntegratorDecorator<S>::time_type dt,
126 typename IntegratorDecorator<S>::time_type end_time) {
127 const auto start_time = std::chrono::high_resolution_clock::now();
128 TimeoutResult result;
129 result.final_time = this->current_time();
130
131 try {
132 if (config_.enable_progress_callback && config_.progress_callback) {
133 result = integrate_with_progress_monitoring(state, dt, end_time, start_time);
134 } else {
135 result = integrate_with_simple_timeout(state, dt, end_time, start_time);
136 }
137
138 } catch (const std::exception& e) {
139 result.completed = false;
140 result.error_message = "Integration failed: " + std::string(e.what());
141 }
142
143 const auto end_time_clock = std::chrono::high_resolution_clock::now();
144 result.elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(
145 end_time_clock - start_time);
146
147 // Handle timeout according to configuration
148 if (!result.completed && config_.throw_on_timeout && result.is_timeout()) {
149 throw std::runtime_error(result.error_message);
150 }
151
152 return result;
153 }
154
158 void integrate(typename IntegratorDecorator<S>::state_type& state,
159 typename IntegratorDecorator<S>::time_type dt,
160 typename IntegratorDecorator<S>::time_type end_time) override {
161 auto result = integrate_with_timeout(state, dt, end_time);
162 if (!result.is_success() && config_.throw_on_timeout) {
163 throw std::runtime_error(result.status_description());
164 }
165 }
166
170 TimeoutConfig& config() { return config_; }
171 const TimeoutConfig& config() const { return config_; }
172
178 void update_config(TimeoutConfig new_config) {
179 new_config.validate();
180 config_ = std::move(new_config);
181 }
182
183private:
187 TimeoutResult integrate_with_simple_timeout(
188 typename IntegratorDecorator<S>::state_type& state,
189 typename IntegratorDecorator<S>::time_type dt,
190 typename IntegratorDecorator<S>::time_type end_time,
191 std::chrono::high_resolution_clock::time_point start_time) {
192
193 TimeoutResult result;
194
195 auto future = std::async(std::launch::async, [this, &state, dt, end_time]() {
196 this->wrapped_integrator_->integrate(state, dt, end_time);
197 });
198
199 if (future.wait_for(config_.timeout_duration) == std::future_status::timeout) {
200 result.completed = false;
201 result.error_message = "Integration timed out after " +
202 std::to_string(config_.timeout_duration.count()) + "ms";
203 } else {
204 future.get(); // May throw if integration failed
205 result.completed = true;
206 result.final_time = this->current_time();
207 }
208
209 return result;
210 }
211
215 TimeoutResult integrate_with_progress_monitoring(
216 typename IntegratorDecorator<S>::state_type& state,
217 typename IntegratorDecorator<S>::time_type dt,
218 typename IntegratorDecorator<S>::time_type end_time,
219 std::chrono::high_resolution_clock::time_point start_time) {
220
221 TimeoutResult result;
222
223 auto future = std::async(std::launch::async, [this, &state, dt, end_time]() {
224 this->wrapped_integrator_->integrate(state, dt, end_time);
225 });
226
227 auto last_progress_check = start_time;
228 auto timeout_deadline = start_time + config_.timeout_duration;
229
230 // Monitor progress until completion or timeout
231 while (true) {
232 auto now = std::chrono::high_resolution_clock::now();
233 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
234
235 // Check if integration completed
236 if (future.wait_for(std::chrono::milliseconds{1}) == std::future_status::ready) {
237 future.get(); // May throw if integration failed
238 result.completed = true;
239 result.final_time = this->current_time();
240 break;
241 }
242
243 // Check for timeout
244 if (now >= timeout_deadline) {
245 result.completed = false;
246 result.error_message = "Integration timed out after " +
247 std::to_string(config_.timeout_duration.count()) + "ms";
248 break;
249 }
250
251 // Check if time for progress callback
252 if (now - last_progress_check >= config_.progress_interval) {
253 double current_time = this->current_time();
254 bool should_continue = config_.progress_callback(
255 current_time, static_cast<double>(end_time), elapsed);
256
257 result.progress_callbacks_made++;
258 last_progress_check = now;
259
260 // Check for user cancellation
261 if (!should_continue) {
262 result.completed = false;
263 result.user_cancelled = true;
264 result.error_message = "Integration cancelled by user";
265 break;
266 }
267 }
268
269 // Brief sleep to avoid busy waiting
270 std::this_thread::sleep_for(std::chrono::milliseconds{1});
271 }
272
273 return result;
274 }
275};
276
277} // namespace diffeq::core::composable
Base decorator interface for integrator enhancements.
Timeout decorator - adds timeout protection to any integrator.
void update_config(TimeoutConfig new_config)
Update timeout configuration with validation.
TimeoutResult integrate_with_timeout(typename IntegratorDecorator< S >::state_type &state, typename IntegratorDecorator< S >::time_type dt, typename IntegratorDecorator< S >::time_type end_time)
Main timeout-protected integration method.
void integrate(typename IntegratorDecorator< S >::state_type &state, typename IntegratorDecorator< S >::time_type dt, typename IntegratorDecorator< S >::time_type end_time) override
Override standard integrate to use timeout protection.
TimeoutDecorator(std::unique_ptr< AbstractIntegrator< S > > integrator, TimeoutConfig config={})
Construct timeout decorator.
TimeoutConfig & config()
Access and modify timeout configuration.
Timeout configuration for integration protection.
void validate() const
Validate configuration parameters.
Result information for timeout-protected integration.
std::string status_description() const
Get human-readable status description.