22
33#include " integrator_decorator.hpp"
44#include < vector>
5- #include < execution>
65#include < thread>
76#include < algorithm>
87#include < ranges>
98#include < type_traits>
109
10+ // Check for parallel execution support
11+ #if defined(__cpp_lib_execution) && __cpp_lib_execution >= 201902L
12+ #include < execution>
13+ #define PARALLEL_EXECUTION_AVAILABLE
14+ #endif
15+
1116namespace diffeq ::core::composable {
1217
1318/* *
@@ -120,13 +125,20 @@ class ParallelDecorator : public IntegratorDecorator<S> {
120125
121126 // Parallel processing
122127 try {
128+ #ifdef PARALLEL_EXECUTION_AVAILABLE
123129 std::for_each (std::execution::par_unseq,
124130 std::ranges::begin (states), std::ranges::end (states),
125131 [this , dt, end_time](auto & state) {
126132 // Create thread-local copy of integrator
127133 auto local_integrator = this ->create_copy ();
128134 local_integrator->integrate (state, dt, end_time);
129135 });
136+ #else
137+ // Sequential fallback for platforms without parallel execution support
138+ for (auto & state : states) {
139+ this ->wrapped_integrator_ ->integrate (state, dt, end_time);
140+ }
141+ #endif
130142 } catch (const std::exception& e) {
131143 // Fall back to sequential processing if parallel fails
132144 for (auto & state : states) {
@@ -170,6 +182,7 @@ class ParallelDecorator : public IntegratorDecorator<S> {
170182
171183 // Parallel processing
172184 try {
185+ #ifdef PARALLEL_EXECUTION_AVAILABLE
173186 std::for_each (std::execution::par_unseq,
174187 std::views::iota (0UL , num_simulations).begin (),
175188 std::views::iota (0UL , num_simulations).end (),
@@ -179,6 +192,14 @@ class ParallelDecorator : public IntegratorDecorator<S> {
179192 local_integrator->integrate (state, dt, end_time);
180193 results[i] = processor (state);
181194 });
195+ #else
196+ // Sequential fallback for platforms without parallel execution support
197+ for (size_t i = 0 ; i < num_simulations; ++i) {
198+ auto state = generator (i);
199+ this ->wrapped_integrator_ ->integrate (state, dt, end_time);
200+ results[i] = processor (state);
201+ }
202+ #endif
182203 } catch (const std::exception& e) {
183204 // Fall back to sequential processing if parallel fails
184205 for (size_t i = 0 ; i < num_simulations; ++i) {
@@ -222,11 +243,19 @@ class ParallelDecorator : public IntegratorDecorator<S> {
222243 static_cast <size_t >(std::distance (chunk_start, states_end))));
223244
224245 // Create range for this chunk and process in parallel
246+ #ifdef PARALLEL_EXECUTION_AVAILABLE
225247 std::for_each (std::execution::par_unseq, chunk_start, chunk_end,
226248 [this , dt, end_time](auto & state) {
227249 auto local_integrator = this ->create_copy ();
228250 local_integrator->integrate (state, dt, end_time);
229251 });
252+ #else
253+ // Sequential fallback for platforms without parallel execution support
254+ std::for_each (chunk_start, chunk_end,
255+ [this , dt, end_time](auto & state) {
256+ this ->wrapped_integrator_ ->integrate (state, dt, end_time);
257+ });
258+ #endif
230259
231260 chunk_start = chunk_end;
232261 }
0 commit comments