From d0b40bd4bc64719bae98e1400ba475fe1ab4652b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 4 Jul 2023 11:10:24 +0200 Subject: [PATCH] Add Run-Time Heuristics for Non-canonical Reduce in Nested Sweep If a level in the Outer Sweep is not decreased by more than 5%, then we will switch over to use the fast reduce on all levels above this one until the next Inner Sweep. --- .../internal/algorithms/nested_sweeping.h | 26 ++++++++++++++++--- src/adiar/internal/algorithms/quantify.h | 3 +-- src/adiar/internal/algorithms/reduce.h | 11 +++++--- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/adiar/internal/algorithms/nested_sweeping.h b/src/adiar/internal/algorithms/nested_sweeping.h index f47dd64af..e9d74834c 100644 --- a/src/adiar/internal/algorithms/nested_sweeping.h +++ b/src/adiar/internal/algorithms/nested_sweeping.h @@ -1438,6 +1438,8 @@ namespace adiar::internal using outer_pq_decorator_t = nested_sweeping::outer::up__pq_decorator; + bool auto_fast_reduce = false; + while (outer_levels.can_pull()) { adiar_debug(outer_arcs.can_pull_terminal() || !outer_pq.empty(), "If there is a level, then there should also be something for it."); @@ -1488,8 +1490,8 @@ namespace adiar::internal outer_pq_decorator_t outer_pq_decorator(outer_pq, outer_roots, next_inner); if (/*constexpr*/ nesting_policy::reduce_strategy == nested_sweeping::NEVER_CANONICAL || - /*constexpr*/ nesting_policy::reduce_strategy == nested_sweeping::FINAL_CANONICAL - /*TODO: AUTO (probably with a different threshold than for the inner up-sweep)*/) { + /*constexpr*/ nesting_policy::reduce_strategy == nested_sweeping::FINAL_CANONICAL || + (nesting_policy::reduce_strategy == nested_sweeping::AUTO && auto_fast_reduce)) { #ifdef ADIAR_STATS // TODO #endif @@ -1500,15 +1502,28 @@ namespace adiar::internal // TODO #endif const size_t unreduced_width = outer_level.width(); + size_t reduced_width; + if(unreduced_width <= outer_internal_sorter_can_fit) { - __reduce_level + reduced_width = __reduce_level (outer_arcs, outer_level.level(), outer_pq_decorator, outer_writer, outer_sorters_memory, unreduced_width); } else { - __reduce_level + reduced_width = __reduce_level (outer_arcs, outer_level.level(), outer_pq_decorator, outer_writer, outer_sorters_memory, unreduced_width); } + + // AUTO Strategy: Use the fast reduce from the next level (until next + // inner sweep) if this level did not change considerably in size. + if constexpr (nesting_policy::reduce_strategy == nested_sweeping::AUTO) { + const double threshold = 0.05; + + const double prior = static_cast(unreduced_width); + const double delta = static_cast(unreduced_width - reduced_width); + + auto_fast_reduce |= (delta / prior) < threshold; + } } continue; @@ -1520,6 +1535,9 @@ namespace adiar::internal adiar_debug(outer_level.level() == next_inner, "'next_inner' level is not skipped"); + // Reset fast reduce for AUTO strategy. + auto_fast_reduce = false; + // ----------------------------------------------------------------------- // Collect all recursions for this level diff --git a/src/adiar/internal/algorithms/quantify.h b/src/adiar/internal/algorithms/quantify.h index f5b7a2aa8..5a1bd8811 100644 --- a/src/adiar/internal/algorithms/quantify.h +++ b/src/adiar/internal/algorithms/quantify.h @@ -511,9 +511,8 @@ namespace adiar::internal } //////////////////////////////////////////////////////////////////////////// - // TODO: set to AUTO and add heuristic hooks static constexpr internal::nested_sweeping::reduce_strategy reduce_strategy = - internal::nested_sweeping::ALWAYS_CANONICAL; + internal::nested_sweeping::AUTO; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/src/adiar/internal/algorithms/reduce.h b/src/adiar/internal/algorithms/reduce.h index 66232a868..c6b06432c 100644 --- a/src/adiar/internal/algorithms/reduce.h +++ b/src/adiar/internal/algorithms/reduce.h @@ -340,9 +340,9 @@ namespace adiar::internal } // Add number of nodes to level information, if any nodes were pushed to the output. - if (out_id != dd_policy::MAX_ID) { - const size_t width = dd_policy::MAX_ID - out_id; - out_writer.unsafe_push(level_info(label, width)); + const size_t reduced_width = dd_policy::MAX_ID - out_id; + if (reduced_width > 0) { + out_writer.unsafe_push(level_info(label, reduced_width)); } // Sort mappings for Reduction rule 2 back in order of arcs.internal @@ -413,6 +413,11 @@ namespace adiar::internal const bool terminal_value = next_red1.new_uid.is_terminal() && next_red1.new_uid.value(); __reduce_level__epilogue<>(arcs, label, reduce_pq, out_writer, terminal_value); + + adiar_debug(reduced_width <= unreduced_width, + "Reduction should only ever remove nodes"); + + return reduced_width; } //////////////////////////////////////////////////////////////////////////////