@@ -225,6 +225,83 @@ inline void valid_axis_range(
225225 }
226226}
227227
228+ // Sweep every (node, target) pair on a 2D grid for which `node + offset` stays
229+ // in bounds, restricted to the half-open y-slab [y_begin, y_end). The body
230+ // receives flat C-order indices for both endpoints and is expected to inline
231+ // at -O2 since this is a header-only template with a fully-known callable
232+ // type at instantiation.
233+ template <class Body >
234+ void sweep_offset_box_2d (
235+ const std::ptrdiff_t dy,
236+ const std::ptrdiff_t dx,
237+ const std::size_t height,
238+ const std::size_t width,
239+ const std::size_t y_begin,
240+ const std::size_t y_end,
241+ const Body &body
242+ ) {
243+ std::size_t y_lo_full, y_hi_full, x_lo, x_hi;
244+ valid_axis_range (dy, height, y_lo_full, y_hi_full);
245+ valid_axis_range (dx, width, x_lo, x_hi);
246+ const auto y_lo = std::max (y_lo_full, y_begin);
247+ const auto y_hi = std::min (y_hi_full, y_end);
248+ if (y_lo >= y_hi || x_lo >= x_hi) {
249+ return ;
250+ }
251+ const auto offset_stride = dy * static_cast <std::ptrdiff_t >(width) + dx;
252+ for (std::size_t y = y_lo; y < y_hi; ++y) {
253+ const auto row_offset = y * width;
254+ for (std::size_t x = x_lo; x < x_hi; ++x) {
255+ const auto node = row_offset + x;
256+ const auto target = static_cast <std::uint64_t >(
257+ static_cast <std::ptrdiff_t >(node) + offset_stride
258+ );
259+ body (static_cast <std::uint64_t >(node), target);
260+ }
261+ }
262+ }
263+
264+ // 3D variant of `sweep_offset_box_2d`. Restricts the sweep to a z-slab.
265+ template <class Body >
266+ void sweep_offset_box_3d (
267+ const std::ptrdiff_t dz,
268+ const std::ptrdiff_t dy,
269+ const std::ptrdiff_t dx,
270+ const std::size_t depth,
271+ const std::size_t height,
272+ const std::size_t width,
273+ const std::size_t z_begin,
274+ const std::size_t z_end,
275+ const Body &body
276+ ) {
277+ std::size_t z_lo_full, z_hi_full, y_lo, y_hi, x_lo, x_hi;
278+ valid_axis_range (dz, depth, z_lo_full, z_hi_full);
279+ valid_axis_range (dy, height, y_lo, y_hi);
280+ valid_axis_range (dx, width, x_lo, x_hi);
281+ const auto z_lo = std::max (z_lo_full, z_begin);
282+ const auto z_hi = std::min (z_hi_full, z_end);
283+ if (z_lo >= z_hi || y_lo >= y_hi || x_lo >= x_hi) {
284+ return ;
285+ }
286+ const auto slice_size = height * width;
287+ const auto offset_stride =
288+ dz * static_cast <std::ptrdiff_t >(slice_size) +
289+ dy * static_cast <std::ptrdiff_t >(width) + dx;
290+ for (std::size_t z = z_lo; z < z_hi; ++z) {
291+ const auto slice_offset = z * slice_size;
292+ for (std::size_t y = y_lo; y < y_hi; ++y) {
293+ const auto row_offset = slice_offset + y * width;
294+ for (std::size_t x = x_lo; x < x_hi; ++x) {
295+ const auto node = row_offset + x;
296+ const auto target = static_cast <std::uint64_t >(
297+ static_cast <std::ptrdiff_t >(node) + offset_stride
298+ );
299+ body (static_cast <std::uint64_t >(node), target);
300+ }
301+ }
302+ }
303+ }
304+
228305template <class LabelT , class ValueT , class Stats >
229306void scan_affinity_2d_chunk (
230307 const RegionAdjacencyGraph &rag,
@@ -240,25 +317,11 @@ void scan_affinity_2d_chunk(
240317 const auto number_of_nodes = static_cast <std::uint64_t >(height * width);
241318 for (std::size_t channel = 0 ; channel < offsets.size (); ++channel) {
242319 const auto &off = offsets[channel];
243- std::size_t y_lo_full, y_hi_full, x_lo, x_hi;
244- valid_axis_range (off[0 ], height, y_lo_full, y_hi_full);
245- valid_axis_range (off[1 ], width, x_lo, x_hi);
246- const auto y_lo = std::max (y_lo_full, y_begin);
247- const auto y_hi = std::min (y_hi_full, y_end);
248- if (y_lo >= y_hi || x_lo >= x_hi) {
249- continue ;
250- }
251- const auto offset_stride =
252- off[0 ] * static_cast <std::ptrdiff_t >(width) + off[1 ];
253320 const auto channel_offset =
254321 static_cast <std::uint64_t >(channel) * number_of_nodes;
255- for (std::size_t y = y_lo; y < y_hi; ++y) {
256- const auto row_offset = y * width;
257- for (std::size_t x = x_lo; x < x_hi; ++x) {
258- const auto node = row_offset + x;
259- const auto target = static_cast <std::uint64_t >(
260- static_cast <std::ptrdiff_t >(node) + offset_stride
261- );
322+ sweep_offset_box_2d (
323+ off[0 ], off[1 ], height, width, y_begin, y_end,
324+ [&](const std::uint64_t node, const std::uint64_t target) {
262325 const auto u = label_at (labels, node);
263326 const auto v = label_at (labels, target);
264327 const auto edge = edge_for_labels (rag, u, v);
@@ -268,7 +331,7 @@ void scan_affinity_2d_chunk(
268331 );
269332 }
270333 }
271- }
334+ );
272335 }
273336}
274337
@@ -289,41 +352,21 @@ void scan_affinity_3d_chunk(
289352 const auto number_of_nodes = static_cast <std::uint64_t >(depth * slice_size);
290353 for (std::size_t channel = 0 ; channel < offsets.size (); ++channel) {
291354 const auto &off = offsets[channel];
292- std::size_t z_lo_full, z_hi_full, y_lo, y_hi, x_lo, x_hi;
293- valid_axis_range (off[0 ], depth, z_lo_full, z_hi_full);
294- valid_axis_range (off[1 ], height, y_lo, y_hi);
295- valid_axis_range (off[2 ], width, x_lo, x_hi);
296- const auto z_lo = std::max (z_lo_full, z_begin);
297- const auto z_hi = std::min (z_hi_full, z_end);
298- if (z_lo >= z_hi || y_lo >= y_hi || x_lo >= x_hi) {
299- continue ;
300- }
301- const auto offset_stride =
302- off[0 ] * static_cast <std::ptrdiff_t >(slice_size) +
303- off[1 ] * static_cast <std::ptrdiff_t >(width) +
304- off[2 ];
305355 const auto channel_offset =
306356 static_cast <std::uint64_t >(channel) * number_of_nodes;
307- for (std::size_t z = z_lo; z < z_hi; ++z) {
308- const auto slice_offset = z * slice_size;
309- for (std::size_t y = y_lo; y < y_hi; ++y) {
310- const auto row_offset = slice_offset + y * width;
311- for (std::size_t x = x_lo; x < x_hi; ++x) {
312- const auto node = row_offset + x;
313- const auto target = static_cast <std::uint64_t >(
314- static_cast <std::ptrdiff_t >(node) + offset_stride
357+ sweep_offset_box_3d (
358+ off[0 ], off[1 ], off[2 ], depth, height, width, z_begin, z_end,
359+ [&](const std::uint64_t node, const std::uint64_t target) {
360+ const auto u = label_at (labels, node);
361+ const auto v = label_at (labels, target);
362+ const auto edge = edge_for_labels (rag, u, v);
363+ if (edge >= 0 ) {
364+ stats[static_cast <std::size_t >(edge)].add (
365+ affinities[channel_offset + node]
315366 );
316- const auto u = label_at (labels, node);
317- const auto v = label_at (labels, target);
318- const auto edge = edge_for_labels (rag, u, v);
319- if (edge >= 0 ) {
320- stats[static_cast <std::size_t >(edge)].add (
321- affinities[channel_offset + node]
322- );
323- }
324367 }
325368 }
326- }
369+ );
327370 }
328371}
329372
0 commit comments