Skip to content

Commit 4792e04

Browse files
Merge pull request #408 from samolisov/dominator-tree-vector-of-structs
Aggregate predecessor state for Lengauer-Tarjan Improves performance on several benchmarks although regresses on one.
2 parents 9237081 + 7b04334 commit 4792e04

File tree

3 files changed

+115
-42
lines changed

3 files changed

+115
-42
lines changed

.clang-format

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ AlignEscapedNewlinesLeft: true
55
AlwaysBreakAfterDefinitionReturnType: None
66
BreakBeforeBraces: Allman
77
BreakConstructorInitializersBeforeComma: false
8+
BreakTemplateDeclarations: Yes
89
ColumnLimit: 80
910
ConstructorInitializerAllOnOneLineOrOnePerLine: true
1011
ConstructorInitializerIndentWidth: 0

include/boost/graph/dominator_tree.hpp

+40-21
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,21 @@ namespace detail
6262
Tag >(timeMap, v, t);
6363
}
6464

65+
// Auxiliary structure of different kinds of predecessors are used to
66+
// calculate the semidominators: ancestor, semidominator, and the ancestor
67+
// with the lowest semidominator (`best`). Placing these predecessors in a
68+
// structure let us organize a "vector of structs" what improves cache
69+
// efficiency.
70+
template < class Graph >
71+
struct vertex_triple
72+
{
73+
using Vertex = typename graph_traits< Graph >::vertex_descriptor;
74+
75+
Vertex semi { graph_traits< Graph >::null_vertex() };
76+
Vertex ancestor { graph_traits< Graph >::null_vertex() };
77+
Vertex best { graph_traits< Graph >::null_vertex() };
78+
};
79+
6580
template < class Graph, class IndexMap, class TimeMap, class PredMap,
6681
class DomTreePredMap >
6782
class dominator_visitor
@@ -80,13 +95,9 @@ namespace detail
8095
*/
8196
dominator_visitor(const Graph& g, const Vertex& entry,
8297
const IndexMap& indexMap, DomTreePredMap domTreePredMap)
83-
: semi_(num_vertices(g))
84-
, ancestor_(num_vertices(g), graph_traits< Graph >::null_vertex())
85-
, samedom_(ancestor_)
86-
, best_(semi_)
87-
, semiMap_(make_iterator_property_map(semi_.begin(), indexMap))
88-
, ancestorMap_(make_iterator_property_map(ancestor_.begin(), indexMap))
89-
, bestMap_(make_iterator_property_map(best_.begin(), indexMap))
98+
: pred_(num_vertices(g))
99+
, predMap_(make_iterator_property_map(pred_.begin(), indexMap))
100+
, samedom_(num_vertices(g), graph_traits< Graph >::null_vertex())
90101
, buckets_(num_vertices(g))
91102
, bucketMap_(make_iterator_property_map(buckets_.begin(), indexMap))
92103
, entry_(entry)
@@ -132,18 +143,18 @@ namespace detail
132143
if (get(dfnumMap, v) <= get(dfnumMap, n))
133144
s2 = v;
134145
else
135-
s2 = get(semiMap_, ancestor_with_lowest_semi_(v, dfnumMap));
146+
s2 = get(predMap_, ancestor_with_lowest_semi_(v, dfnumMap))
147+
.semi;
136148

137149
if (get(dfnumMap, s2) < get(dfnumMap, s))
138150
s = s2;
139151
}
140-
put(semiMap_, n, s);
152+
auto& pred_of_n = get(predMap_, n);
153+
pred_of_n = {s, p, n};
141154

142155
// 2. Calculation of n's dominator is deferred until
143156
// the path from s to n has been linked into the forest
144157
get(bucketMap_, s).push_back(n);
145-
get(ancestorMap_, n) = p;
146-
get(bestMap_, n) = n;
147158

148159
// 3. Now that the path from p to v has been linked into
149160
// the spanning forest, these lines calculate the dominator of v,
@@ -161,7 +172,7 @@ namespace detail
161172
{
162173
const Vertex v(*buckItr);
163174
const Vertex y(ancestor_with_lowest_semi_(v, dfnumMap));
164-
if (get(semiMap_, y) == get(semiMap_, v))
175+
if (get(predMap_, y).semi == get(predMap_, v).semi)
165176
put(domTreePredMap_, v, p);
166177
else
167178
put(samedomMap, v, y);
@@ -177,24 +188,32 @@ namespace detail
177188
const Vertex ancestor_with_lowest_semi_(
178189
const Vertex& v, const TimeMap& dfnumMap)
179190
{
180-
const Vertex a(get(ancestorMap_, v));
191+
const Vertex a(get(predMap_, v).ancestor);
192+
const auto& pred_of_a = get(predMap_, a);
193+
194+
auto& pred_of_v = get(predMap_, v);
181195

182-
if (get(ancestorMap_, a) != graph_traits< Graph >::null_vertex())
196+
if (pred_of_a.ancestor != graph_traits< Graph >::null_vertex())
183197
{
184198
const Vertex b(ancestor_with_lowest_semi_(a, dfnumMap));
199+
const auto& pred_of_b = get(predMap_, b);
185200

186-
put(ancestorMap_, v, get(ancestorMap_, a));
201+
pred_of_v.ancestor = pred_of_a.ancestor;
187202

188-
if (get(dfnumMap, get(semiMap_, b))
189-
< get(dfnumMap, get(semiMap_, get(bestMap_, v))))
190-
put(bestMap_, v, b);
203+
if (get(dfnumMap, pred_of_b.semi)
204+
< get(dfnumMap, get(predMap_, pred_of_v.best).semi))
205+
pred_of_v.best = b;
191206
}
192207

193-
return get(bestMap_, v);
208+
return pred_of_v.best;
194209
}
195210

196-
std::vector< Vertex > semi_, ancestor_, samedom_, best_;
197-
PredMap semiMap_, ancestorMap_, bestMap_;
211+
std::vector< vertex_triple< Graph > > pred_;
212+
iterator_property_map< typename std::vector< vertex_triple< Graph > >::iterator,
213+
IndexMap >
214+
predMap_;
215+
216+
std::vector< Vertex > samedom_;
198217
std::vector< std::vector< Vertex > > buckets_;
199218

200219
iterator_property_map<

test/dominator_tree_test.cpp

+74-21
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <iostream>
1010
#include <algorithm>
1111
#include <boost/graph/adjacency_list.hpp>
12+
#include <boost/graph/adjacency_matrix.hpp>
1213
#include <boost/graph/dominator_tree.hpp>
1314

1415
using namespace std;
@@ -24,13 +25,51 @@ struct DominatorCorrectnessTestSet
2425

2526
using namespace boost;
2627

27-
typedef adjacency_list< listS, listS, bidirectionalS,
28-
property< vertex_index_t, std::size_t >, no_property >
29-
G;
28+
// a workaround for the C++ standard before C++17, after switching to C++17,
29+
// the method may be just inlined into the run_test() with constexpr if.
30+
namespace detail
31+
{
3032

31-
int main(int, char*[])
33+
template < typename Graph >
34+
void index_graph(Graph&, std::true_type /*IsRandomAccessAdjacentList*/)
35+
{
36+
// nothing to do for already indexed adjacent list
37+
}
38+
39+
template < typename Graph >
40+
void index_graph(Graph& g, std::false_type /*IsRandomAccessAdjacentList*/)
3241
{
33-
typedef DominatorCorrectnessTestSet::edge edge;
42+
using IndexMap = typename property_map< Graph, vertex_index_t >::type;
43+
IndexMap indexMap(get(vertex_index, g));
44+
typename graph_traits< Graph >::vertex_iterator uItr, uEnd;
45+
int j = 0;
46+
for (boost::tie(uItr, uEnd) = vertices(g); uItr != uEnd; ++uItr, ++j)
47+
{
48+
put(indexMap, *uItr, j);
49+
}
50+
}
51+
52+
} // namespace detail
53+
54+
template < typename OEL, typename VL, typename D, typename VP, typename EP,
55+
typename GP, typename EL >
56+
void index_graph(adjacency_list< OEL, VL, D, VP, EP, GP, EL >& g)
57+
{
58+
using Traits = adjacency_list_traits< OEL, VL, D, EL >;
59+
::detail::index_graph(
60+
g, std::integral_constant< bool, Traits::is_rand_access::value > {});
61+
}
62+
63+
template < typename D, typename VP, typename EP, typename GP, typename A >
64+
void index_graph(adjacency_matrix<D, VP, EP, GP, A>&)
65+
{
66+
// nothing to do for already indexed adjacent matrix
67+
}
68+
69+
template < typename Graph >
70+
void run_test()
71+
{
72+
using edge = DominatorCorrectnessTestSet::edge;
3473

3574
DominatorCorrectnessTestSet testSet[7];
3675

@@ -217,34 +256,32 @@ int main(int, char*[])
217256
{
218257
const int numOfVertices = testSet[i].numOfVertices;
219258

220-
G g(testSet[i].edges.begin(), testSet[i].edges.end(), numOfVertices);
259+
Graph g(testSet[i].edges.begin(), testSet[i].edges.end(), numOfVertices);
260+
261+
using Vertex = typename graph_traits< Graph >::vertex_descriptor;
262+
using IndexMap = typename property_map< Graph, vertex_index_t >::type;
263+
IndexMap indexMap(get(vertex_index, g));
264+
using PredMap
265+
= iterator_property_map< typename vector< Vertex >::iterator, IndexMap >;
221266

222-
typedef graph_traits< G >::vertex_descriptor Vertex;
223-
typedef property_map< G, vertex_index_t >::type IndexMap;
224-
typedef iterator_property_map< vector< Vertex >::iterator, IndexMap >
225-
PredMap;
267+
index_graph(g);
226268

227269
vector< Vertex > domTreePredVector, domTreePredVector2;
228-
IndexMap indexMap(get(vertex_index, g));
229-
graph_traits< G >::vertex_iterator uItr, uEnd;
230-
int j = 0;
231-
for (boost::tie(uItr, uEnd) = vertices(g); uItr != uEnd; ++uItr, ++j)
232-
{
233-
put(indexMap, *uItr, j);
234-
}
235270

236271
// Lengauer-Tarjan dominator tree algorithm
237272
domTreePredVector = vector< Vertex >(
238-
num_vertices(g), graph_traits< G >::null_vertex());
273+
num_vertices(g), graph_traits< Graph >::null_vertex());
239274
PredMap domTreePredMap
240275
= make_iterator_property_map(domTreePredVector.begin(), indexMap);
241276

242277
lengauer_tarjan_dominator_tree(g, vertex(0, g), domTreePredMap);
243278

244279
vector< int > idom(num_vertices(g));
280+
typename graph_traits< Graph >::vertex_iterator uItr, uEnd;
245281
for (boost::tie(uItr, uEnd) = vertices(g); uItr != uEnd; ++uItr)
246282
{
247-
if (get(domTreePredMap, *uItr) != graph_traits< G >::null_vertex())
283+
if (get(domTreePredMap, *uItr)
284+
!= graph_traits< Graph >::null_vertex())
248285
idom[get(indexMap, *uItr)]
249286
= get(indexMap, get(domTreePredMap, *uItr));
250287
else
@@ -260,7 +297,7 @@ int main(int, char*[])
260297

261298
// compare results of fast version and slow version of dominator tree
262299
domTreePredVector2 = vector< Vertex >(
263-
num_vertices(g), graph_traits< G >::null_vertex());
300+
num_vertices(g), graph_traits< Graph >::null_vertex());
264301
domTreePredMap
265302
= make_iterator_property_map(domTreePredVector2.begin(), indexMap);
266303

@@ -269,7 +306,8 @@ int main(int, char*[])
269306
vector< int > idom2(num_vertices(g));
270307
for (boost::tie(uItr, uEnd) = vertices(g); uItr != uEnd; ++uItr)
271308
{
272-
if (get(domTreePredMap, *uItr) != graph_traits< G >::null_vertex())
309+
if (get(domTreePredMap, *uItr)
310+
!= graph_traits< Graph >::null_vertex())
273311
idom2[get(indexMap, *uItr)]
274312
= get(indexMap, get(domTreePredMap, *uItr));
275313
else
@@ -283,6 +321,21 @@ int main(int, char*[])
283321
for (k = 0; k < num_vertices(g); ++k)
284322
BOOST_TEST(domTreePredVector[k] == domTreePredVector2[k]);
285323
}
324+
cout << endl;
325+
}
326+
327+
int main(int, char*[])
328+
{
329+
using AdjacencyListList = adjacency_list< listS, listS, bidirectionalS,
330+
property< vertex_index_t, std::size_t >, no_property >;
331+
332+
using AdjacencyListVec = adjacency_list< listS, vecS, bidirectionalS >;
333+
334+
using AdjacencyMatrix = adjacency_matrix< directedS >;
335+
336+
run_test< AdjacencyListList >();
337+
run_test< AdjacencyListVec >();
338+
run_test< AdjacencyMatrix >();
286339

287340
return boost::report_errors();
288341
}

0 commit comments

Comments
 (0)