10
10
11
11
#include < adiar/internal/algorithms/reduce.h>
12
12
#include < adiar/internal/assert.h>
13
+ #include < adiar/internal/dd_func.h>
13
14
#include < adiar/internal/io/levelized_file_stream.h>
14
15
#include < adiar/internal/io/node_file.h>
15
16
#include < adiar/internal/io/node_stream.h>
@@ -60,19 +61,24 @@ namespace adiar::internal
60
61
replace_type
61
62
__replace__infer_type (LevelInfoStream& ls, const ReplaceFunction& m)
62
63
{
63
- using label_type = typename Policy::label_type;
64
- using result_type = typename ReplaceFunction::result_type;
64
+ using label_type = typename Policy::label_type;
65
+ using signed_label_type = typename Policy::signed_label_type;
66
+ using result_type = typename ReplaceFunction::result_type;
65
67
66
68
constexpr bool is_total_map = is_same<result_type, label_type>;
67
69
constexpr bool is_partial_map = is_same<result_type, optional<label_type>>;
68
70
69
71
static_assert (is_total_map || is_partial_map);
70
72
71
73
bool identity = true ;
74
+ bool shift = true ;
72
75
bool monotone = true ;
73
76
74
77
label_type prev_before = Policy::max_label + 1 ;
75
78
label_type prev_after = Policy::max_label + 1 ;
79
+
80
+ signed_label_type prev_diff = 0 ;
81
+
76
82
while (ls.can_pull ()) {
77
83
const label_type next_before = ls.pull ().level ();
78
84
const result_type next_after_opt = m (next_before);
@@ -89,6 +95,14 @@ namespace adiar::internal
89
95
next_after = next_after_opt;
90
96
}
91
97
98
+ if (shift) {
99
+ const signed_label_type next_diff =
100
+ static_cast <signed_label_type>(next_before) - static_cast <signed_label_type>(next_after);
101
+
102
+ shift &= Policy::max_label < prev_before || prev_diff == next_diff;
103
+ prev_diff = next_diff;
104
+ }
105
+
92
106
identity &= next_before == next_after;
93
107
monotone &= Policy::max_label < prev_before || prev_after < next_after;
94
108
@@ -97,13 +111,32 @@ namespace adiar::internal
97
111
}
98
112
99
113
if (!monotone) { return replace_type::Non_Monotone; }
100
- if (!identity) { return replace_type::Monotone; }
114
+ if (!shift) { return replace_type::Monotone; }
115
+ if (!identity) { return replace_type::Shift; }
101
116
return replace_type::Identity;
102
117
}
103
118
104
119
// ////////////////////////////////////////////////////////////////////////////////////////////////
105
120
// Algorithms
106
121
122
+ // ////////////////////////////////////////////////////////////////////////////////////////////////
123
+ // / \brief Replace the level in constant time
124
+ // /
125
+ // / \remark This requires that the mapping, `m`, is *monotonic*.
126
+ // ////////////////////////////////////////////////////////////////////////////////////////////////
127
+ template <typename Policy>
128
+ inline typename Policy::dd_type
129
+ __replace__shift_return (const typename Policy::dd_type& dd, const replace_func<Policy>& m)
130
+ {
131
+ adiar_assert (!dd->is_terminal ());
132
+
133
+ const typename Policy::signed_label_type topvar = dd_topvar (dd);
134
+ const typename Policy::signed_label_type shifted_topvar = m (topvar);
135
+
136
+ return typename Policy::dd_type (
137
+ dd.file_ptr (), dd.is_negated (), dd.shift () + (shifted_topvar - topvar));
138
+ }
139
+
107
140
// ////////////////////////////////////////////////////////////////////////////////////////////////
108
141
// / \brief Replace the level of all nodes in a single linear scan.
109
142
// /
@@ -211,6 +244,12 @@ namespace adiar::internal
211
244
#endif
212
245
return __replace__monotonic_scan<Policy>(dd, m);
213
246
247
+ case replace_type::Shift:
248
+ #ifdef ADIAR_STATS
249
+ stats_replace.shift_returns += 1u ;
250
+ #endif
251
+ return __replace__shift_return<Policy>(dd, m);
252
+
214
253
case replace_type::Identity:
215
254
#ifdef ADIAR_STATS
216
255
stats_replace.identity_returns += 1u ;
@@ -263,6 +302,7 @@ namespace adiar::internal
263
302
throw invalid_argument (" Non-monotonic variable replacement not (yet) supported." );
264
303
265
304
case replace_type::Monotone:
305
+ case replace_type::Shift:
266
306
#ifdef ADIAR_STATS
267
307
stats_replace.monotonic_reduces += 1u ;
268
308
#endif
0 commit comments