Skip to content

Commit

Permalink
Readd shallow variables heuristic (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
SSoelvsten committed Feb 27, 2024
1 parent fc67136 commit e45b9bb
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 19 deletions.
10 changes: 5 additions & 5 deletions src/adiar/exec_policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,20 +174,20 @@ namespace adiar

//////////////////////////////////////////////////////////////////////////
/// \brief Maximum number of repeated transpositions before switching to
/// nested sweeping
/// nested sweeping.
//////////////////////////////////////////////////////////////////////////
class transposition_max
{
public:
/// \brief Minimal value (equivalent to disabling repeated transpositions)
/// \brief Minimal value (equivalent to disabling repeated transpositions).
static constexpr transposition_max
min()
{
return std::numeric_limits<unsigned char>::min();
}

/// \brief Maximal value (in many cases, this is equivalent to only
/// doing repeated transpositions and not nested sweeping)
/// \brief Maximal value (equivalent to using the built-in heuristics
/// based on the graph's meta information).
static constexpr transposition_max
max()
{
Expand All @@ -200,7 +200,7 @@ namespace adiar
public:
/// \brief Default value construction.
constexpr transposition_max()
: _value(1u)
: _value(std::numeric_limits<unsigned char>::max())
{}

/// \brief Wrap an `unsigned char`
Expand Down
74 changes: 60 additions & 14 deletions src/adiar/internal/algorithms/quantify.h
Original file line number Diff line number Diff line change
Expand Up @@ -1276,16 +1276,16 @@ namespace adiar::internal
};

//////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief Obtain the deepest lvel that satisfies (or not) the requested level.
/// \brief Obtain the deepest level that satisfies (or not) the requested level.
//////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: optimisations
// - initial cheap check on is_terminal.
// - initial 'quantify__get_deepest' should not terminate early but
// - initial '__quantify__get_deepest' should not terminate early but
// determine whether any variable may "survive".
template <typename Policy>
inline typename Policy::label_type
quantify__get_deepest(const typename Policy::dd_type& dd,
const predicate<typename Policy::label_type>& pred)
__quantify__get_deepest(const typename Policy::dd_type& dd,
const predicate<typename Policy::label_type>& pred)
{
level_info_stream<true /* bottom-up */> lis(dd);

Expand All @@ -1296,6 +1296,50 @@ namespace adiar::internal
return Policy::max_label + 1;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief Heuristically derive a bound for the number of partial sweeps based on the graph meta
/// data.
//////////////////////////////////////////////////////////////////////////////////////////////////
template <typename Policy>
inline typename Policy::label_type
__quantify__max_partial_sweeps(const typename Policy::dd_type& dd,
const predicate<typename Policy::label_type>& pred)
{
// Extract meta data constants about the DAG
const size_t size = dd.size();

// Keep track of the number of nodes on the top-most levels in relation to the total size
size_t seen_nodes = 0u;

// Threshold to stop after the first n/4 nodes. If the input is very "small", look at the first
// 32 nodes, i.e. the first 5(ish) levels.
const size_t max_nodes = std::max<size_t>(std::min<size_t>(size, 32), size / 4);

// Final result
//
// TODO: Turn `result` into a double and decrease the weight of to-be quantified variables
// depending on `seen_nodes`, the number of levels of width `width`, and/or in general a
// (quadratic?) decay in the weight.
typename Policy::label_type result = 0u;

level_info_stream<false /*top-down*/> lis(dd);

while (lis.can_pull()) {
const level_info li = lis.pull();

if (pred(li.label()) == Policy::quantify_onset) {
result++;
}

// Stop when having seen too many nodes
seen_nodes += li.width();
if (max_nodes < seen_nodes) { break; }
}

adiar_assert(result < Policy::max_label);
return result;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief Entry Point for Multi-variable Quantification with a Predicate.
//////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -1308,7 +1352,7 @@ namespace adiar::internal
using unreduced_t = typename Policy::__dd_type;
// TODO: check for missing std::move(...)

typename Policy::label_type label = quantify__get_deepest<Policy>(dd, pred);
typename Policy::label_type label = __quantify__get_deepest<Policy>(dd, pred);

if (Policy::max_label < label) {
#ifdef ADIAR_STATS
Expand All @@ -1328,7 +1372,7 @@ namespace adiar::internal
dd = quantify<Policy>(ep, dd, label);
if (dd_isterminal(dd)) { return dd; }

label = quantify__get_deepest<Policy>(dd, pred);
label = __quantify__get_deepest<Policy>(dd, pred);
}
return dd;
}
Expand All @@ -1346,8 +1390,10 @@ namespace adiar::internal
* static_cast<double>(dd_size)));

// 2. ... it has not run more than the maximum number of iterations.
const size_t transposition__max_iterations =
ep.template get<exec_policy::quantify::transposition_max>();
const size_t transposition__max_iterations = std::min<size_t>({
ep.template get<exec_policy::quantify::transposition_max>(),
__quantify__max_partial_sweeps<Policy>(dd, pred)
});

unreduced_t transposed;

Expand Down Expand Up @@ -1482,15 +1528,15 @@ namespace adiar::internal
//////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: optimisations
// - initial cheap check on is_terminal.
// - initial 'quantify__get_deepest' should not terminate early but
// - initial '__quantify__get_deepest' should not terminate early but
// determine whether any variable may "survive".
// clean up
// - Make return type 'optional' rather than larger than 'max_label'
template <typename Policy>
inline typename Policy::label_type
quantify__get_deepest(const typename Policy::dd_type& dd,
const typename Policy::label_type bot_level,
const optional<typename Policy::label_type> top_level)
__quantify__get_deepest(const typename Policy::dd_type& dd,
const typename Policy::label_type bot_level,
const optional<typename Policy::label_type> top_level)
{
level_info_stream<true /* bottom-up */> lis(dd);

Expand Down Expand Up @@ -1543,7 +1589,7 @@ namespace adiar::internal
// Quantify everything below 'label'
for (;;) {
const typename Policy::label_type off_level =
quantify__get_deepest<Policy>(dd, Policy::max_label, on_level.value());
__quantify__get_deepest<Policy>(dd, Policy::max_label, on_level.value());

if (Policy::max_label < off_level) { break; }

Expand All @@ -1561,7 +1607,7 @@ namespace adiar::internal
while (bot_level) {
for (;;) {
const typename Policy::label_type off_level =
quantify__get_deepest<Policy>(dd, bot_level.value(), top_level);
__quantify__get_deepest<Policy>(dd, bot_level.value(), top_level);

if (Policy::max_label < off_level) { break; }

Expand Down

0 comments on commit e45b9bb

Please sign in to comment.