Developer documentation
Version 3.0.3-105-gd3941f44
stochastic_threaded_loop.h
Go to the documentation of this file.
1/* Copyright (c) 2008-2022 the MRtrix3 contributors.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 *
7 * Covered Software is provided under this License on an "as is"
8 * basis, without warranty of any kind, either expressed, implied, or
9 * statutory, including, without limitation, warranties that the
10 * Covered Software is free of defects, merchantable, fit for a
11 * particular purpose or non-infringing.
12 * See the Mozilla Public License v. 2.0 for more details.
13 *
14 * For more details, see http://www.mrtrix.org/.
15 */
16
17#ifndef __algo_stochastic_threaded_loop_h__
18#define __algo_stochastic_threaded_loop_h__
19
20#include "debug.h"
21#include "algo/loop.h"
22#include "algo/iterator.h"
23#include "thread.h"
24#include "math/rng.h"
25
26namespace MR
27{
28
29 /* slower than ThreadedLoop for any voxel_density */
30
31
32
33 namespace {
34
35
36 template <int N, class Functor, class... ImageType>
37 struct StochasticThreadedLoopRunInner
38 { MEMALIGN(StochasticThreadedLoopRunInner<N,Functor,ImageType...>)
39 const vector<size_t>& outer_axes;
40 decltype (Loop (outer_axes)) loop;
41 typename std::remove_reference<Functor>::type func;
42 double density;
43 Math::RNG::Uniform<double> rng;
44 std::tuple<ImageType...> vox;
45
46 StochasticThreadedLoopRunInner (const vector<size_t>& outer_axes, const vector<size_t>& inner_axes,
47 const Functor& functor, const double voxel_density, ImageType&... voxels) :
48 outer_axes (outer_axes),
49 loop (Loop (inner_axes)),
50 func (functor),
51 density (voxel_density),
52 rng (Math::RNG::Uniform<double>()),
53 vox (voxels...) { }
54
55 void operator() (const Iterator& pos) {
56 assign_pos_of (pos, outer_axes).to (vox);
57 for (auto i = unpack (loop, vox); i; ++i) {
58 if (rng() >= density){
59 //DEBUG (str(pos) + " ...skipped inner");
60 continue;
61 }
62 // DEBUG (str(pos) + " ...used inner");
63 unpack (func, vox);
64 }
65 }
66 };
67
68
69 template <class Functor, class... ImageType>
70 struct StochasticThreadedLoopRunInner<0,Functor,ImageType...>
71 { MEMALIGN(StochasticThreadedLoopRunInner<0, Functor,ImageType...>)
72 const vector<size_t>& outer_axes;
73 decltype (Loop (outer_axes)) loop;
74 typename std::remove_reference<Functor>::type func;
75 double density;
76 Math::RNG::Uniform<double> rng;
77
78
79 StochasticThreadedLoopRunInner (const vector<size_t>& outer_axes, const vector<size_t>& inner_axes,
80 const Functor& functor, const double voxel_density, ImageType&... voxels) :
81 outer_axes (outer_axes),
82 loop (Loop (inner_axes)),
83 func (functor),
84 density (voxel_density),
85 rng (Math::RNG::Uniform<double>()) { }
86
87 void operator() (Iterator& pos) {
88 for (auto i = loop (pos); i; ++i){
89 if (rng() >= density){
90 // DEBUG (str(pos) + " ...skipped inner");
91 continue;
92 }
93 // DEBUG (str(pos) + " ...used inner");
94 func (pos);
95 }
96 }
97 };
98
99
100 template <class OuterLoopType>
101 struct StochasticThreadedLoopRunOuter { MEMALIGN(StochasticThreadedLoopRunOuter<OuterLoopType>)
102 Iterator iterator;
103 OuterLoopType outer_loop;
104 vector<size_t> inner_axes;
105
107 template <class Functor>
108 void run_outer (Functor&& functor, const double voxel_density)
109 {
110 if (Thread::threads_to_execute() == 0) {
111 for (auto i = outer_loop (iterator); i; ++i){
112 // std::cerr << "outer: " << str(iterator) << " " << voxel_density << std::endl;
113 functor (iterator);
114 }
115 return;
116 }
117
118 struct Shared { MEMALIGN(Shared)
119 Iterator& iterator;
120 decltype (outer_loop (iterator)) loop;
121 std::mutex mutex;
122 FORCE_INLINE bool next (Iterator& pos) {
123 std::lock_guard<std::mutex> lock (mutex);
124 if (loop) {
125 assign_pos_of (iterator, loop.axes).to (pos);
126 ++loop;
127 return true;
128 }
129 else return false;
130 }
131 } shared = { iterator, outer_loop (iterator) };
132
133 struct PerThread { MEMALIGN(PerThread)
134 Shared& shared;
135 typename std::remove_reference<Functor>::type func;
136 void execute () {
137 Iterator pos = shared.iterator;
138 while (shared.next (pos))
139 func (pos);
140 }
141 } loop_thread = { shared, functor };
142
143 Thread::run (Thread::multi (loop_thread), "loop threads").wait();
144 }
145
146
147
149 template <class Functor, class... ImageType>
150 void run (Functor&& functor, const double voxel_density, ImageType&&... vox)
151 {
152 StochasticThreadedLoopRunInner<
153 sizeof...(ImageType),
154 typename std::remove_reference<Functor>::type,
155 typename std::remove_reference<ImageType>::type...
156 > loop_thread (outer_loop.axes, inner_axes, functor, voxel_density, vox...);
157 run_outer (loop_thread, voxel_density);
159 }
160
161 };
162 }
163
164
165
166
167
168
169
170 template <class HeaderType>
171 inline StochasticThreadedLoopRunOuter<decltype(Loop(vector<size_t>()))> StochasticThreadedLoop (
172 const HeaderType& source,
173 const vector<size_t>& outer_axes,
174 const vector<size_t>& inner_axes) {
175 return { source, Loop (outer_axes), inner_axes };
176 }
177
178
179 template <class HeaderType>
180 inline StochasticThreadedLoopRunOuter<decltype(Loop(vector<size_t>()))> StochasticThreadedLoop (
181 const HeaderType& source,
182 const vector<size_t>& axes,
183 size_t num_inner_axes = 1) {
184 return { source, Loop (get_outer_axes (axes, num_inner_axes)), get_inner_axes (axes, num_inner_axes) };
185 }
186
187 template <class HeaderType>
188 inline StochasticThreadedLoopRunOuter<decltype(Loop(vector<size_t>()))> StochasticThreadedLoop (
189 const HeaderType& source,
190 size_t from_axis = 0,
191 size_t to_axis = std::numeric_limits<size_t>::max(),
192 size_t num_inner_axes = 1) {
193 return { source,
194 Loop (get_outer_axes (source, num_inner_axes, from_axis, to_axis)),
195 get_inner_axes (source, num_inner_axes, from_axis, to_axis) };
196 }
197
198 template <class HeaderType>
199 inline StochasticThreadedLoopRunOuter<decltype(Loop("", vector<size_t>()))> StochasticThreadedLoop (
200 const std::string& progress_message,
201 const HeaderType& source,
202 const vector<size_t>& outer_axes,
203 const vector<size_t>& inner_axes) {
204 return { source, Loop (progress_message, outer_axes), inner_axes };
205 }
206
207 template <class HeaderType>
208 inline StochasticThreadedLoopRunOuter<decltype(Loop("", vector<size_t>()))> StochasticThreadedLoop (
209 const std::string& progress_message,
210 const HeaderType& source,
211 const vector<size_t>& axes,
212 size_t num_inner_axes = 1) {
213 return { source,
214 Loop (progress_message, get_outer_axes (axes, num_inner_axes)),
215 get_inner_axes (axes, num_inner_axes) };
216 }
217
218 template <class HeaderType>
219 inline StochasticThreadedLoopRunOuter<decltype(Loop("", vector<size_t>()))> StochasticThreadedLoop (
220 const std::string& progress_message,
221 const HeaderType& source,
222 size_t from_axis = 0,
223 size_t to_axis = std::numeric_limits<size_t>::max(),
224 size_t num_inner_axes = 1) {
225 return { source,
226 Loop (progress_message, get_outer_axes (source, num_inner_axes, from_axis, to_axis)),
227 get_inner_axes (source, num_inner_axes, from_axis, to_axis) };
228 }
229
230
233}
234
235#endif
236
237
238
void run()
FORCE_INLINE LoopAlongAxes Loop()
Definition: loop.h:419
__run< Functor >::type run(Functor &&functor, const std::string &name="unnamed")
Execute the functor's execute method in a separate thread.
Definition: thread.h:373
size_t threads_to_execute()
__Multi< typename std::remove_reference< Functor >::type > multi(Functor &&functor, size_t nthreads=threads_to_execute())
used to request multiple threads of the corresponding functor
Definition: thread.h:285
thread_local Math::RNG rng
thread-local, but globally accessible RNG to vastly simplify multi-threading
Definition: base.h:24
auto unpack(F &&f, T &&t) -> decltype(Unpack< ::std::tuple_size< typename ::std::decay< T >::type >::value >::unpack(::std::forward< F >(f), ::std::forward< T >(t)))
if t is a tuple of elements a..., invoke f(a...)
Definition: apply.h:91
void check_app_exit_code()
StochasticThreadedLoopRunOuter< decltype(Loop(vector< size_t >()))> StochasticThreadedLoop(const HeaderType &source, const vector< size_t > &outer_axes, const vector< size_t > &inner_axes)
#define MEMALIGN(...)
Definition: types.h:185
#define FORCE_INLINE
Definition: types.h:156
std::remove_reference< Functor >::type & functor
Definition: thread.h:215