fixup! Implementation of Lengauer-Tarjan algorithm to find dominators

This commit is contained in:
Kamil Śliwak 2023-08-11 17:13:28 +02:00 committed by r0qs
parent 66b95967e6
commit 7888ff424e
No known key found for this signature in database
GPG Key ID: 61503DBA6667276C

View File

@ -27,439 +27,439 @@ namespace solidity::yul::test
struct ImmediateDominatorTest struct ImmediateDominatorTest
{ {
struct Vertex { struct Vertex {
std::string data; std::string data;
std::vector<Vertex*> successors; std::vector<Vertex*> successors;
bool operator<(Vertex const& _other) const bool operator<(Vertex const& _other) const
{ {
return data < _other.data; return data < _other.data;
} }
}; };
typedef std::pair<std::string, std::string> edge; typedef std::pair<std::string, std::string> edge;
struct ForEachVertexSuccessorTest { struct ForEachVertexSuccessorTest {
template<typename Callable> template<typename Callable>
void operator()(Vertex _v, Callable&& _callable) const void operator()(Vertex _v, Callable&& _callable) const
{ {
for (auto w: _v.successors) for (auto w: _v.successors)
_callable(*w); _callable(*w);
} }
}; };
size_t numVertices; size_t numVertices;
Vertex* entry; Vertex* entry;
std::map<std::string, Vertex*> vertices; std::map<std::string, Vertex*> vertices;
std::vector<size_t> expectedIdom; std::vector<size_t> expectedIdom;
std::map<std::string, size_t> expectedDFSIndices; std::map<std::string, size_t> expectedDFSIndices;
}; };
class DominatorFixture class DominatorFixture
{ {
typedef ImmediateDominatorTest::Vertex Vertex; typedef ImmediateDominatorTest::Vertex Vertex;
protected: protected:
static ImmediateDominatorTest const* generateGraph( static ImmediateDominatorTest const* generateGraph(
std::vector<std::string> _vertices, std::vector<std::string> _vertices,
std::vector<ImmediateDominatorTest::edge> _edges, std::vector<ImmediateDominatorTest::edge> _edges,
std::vector<size_t> _expectedIdom, std::vector<size_t> _expectedIdom,
std::map<std::string, size_t> _expectedDFSIndices std::map<std::string, size_t> _expectedDFSIndices
) )
{ {
soltestAssert(_edges.size() > 0); soltestAssert(_edges.size() > 0);
ImmediateDominatorTest* graph = new ImmediateDominatorTest(); ImmediateDominatorTest* graph = new ImmediateDominatorTest();
for (std::string v: _vertices) for (std::string v: _vertices)
graph->vertices.insert(make_pair(v, new Vertex{v, std::vector<Vertex*>{}})); graph->vertices.insert(make_pair(v, new Vertex{v, std::vector<Vertex*>{}}));
graph->entry = graph->vertices[_vertices[0]]; graph->entry = graph->vertices[_vertices[0]];
soltestAssert(_vertices.size() > 0 && _vertices.size() == graph->vertices.size()); soltestAssert(_vertices.size() > 0 && _vertices.size() == graph->vertices.size());
graph->numVertices = _vertices.size(); graph->numVertices = _vertices.size();
for (auto [from, to]: _edges) for (auto [from, to]: _edges)
graph->vertices[from]->successors.push_back(graph->vertices[to]); graph->vertices[from]->successors.push_back(graph->vertices[to]);
graph->expectedIdom = _expectedIdom; graph->expectedIdom = _expectedIdom;
graph->expectedDFSIndices = _expectedDFSIndices; graph->expectedDFSIndices = _expectedDFSIndices;
return graph; return graph;
} }
}; };
BOOST_AUTO_TEST_SUITE(Dominators) BOOST_AUTO_TEST_SUITE(Dominators)
BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture) BOOST_FIXTURE_TEST_CASE(immediate_dominator, DominatorFixture)
{ {
typedef ImmediateDominatorTest::edge edge; typedef ImmediateDominatorTest::edge edge;
std::vector<ImmediateDominatorTest const*> inputGraph(9); std::vector<ImmediateDominatorTest const*> inputGraph(9);
// A // A
// │ // │
// ▼ // ▼
// ┌───B // ┌───B
// │ │ // │ │
// ▼ │ // ▼ │
// C ──┼───┐ // C ──┼───┐
// │ │ │ // │ │ │
// ▼ │ ▼ // ▼ │ ▼
// D◄──┘ G // D◄──┘ G
// │ │ // │ │
// ▼ ▼ // ▼ ▼
// E H // E H
// │ │ // │ │
// └──►F◄──┘ // └──►F◄──┘
inputGraph[0] = generateGraph( inputGraph[0] = generateGraph(
{ "A", "B", "C", "D", "E", "F", "G", "H" }, { "A", "B", "C", "D", "E", "F", "G", "H" },
{ {
edge("A", "B"), edge("A", "B"),
edge("B", "C"), edge("B", "C"),
edge("B", "D"), edge("B", "D"),
edge("C", "D"), edge("C", "D"),
edge("C", "G"), edge("C", "G"),
edge("D", "E"), edge("D", "E"),
edge("E", "F"), edge("E", "F"),
edge("G", "H"), edge("G", "H"),
edge("H", "F") edge("H", "F")
}, },
{0, 0, 1, 1, 3, 1, 2, 6}, {0, 0, 1, 1, 3, 1, 2, 6},
{ {
{"A", 0}, {"A", 0},
{"B", 1}, {"B", 1},
{"C", 2}, {"C", 2},
{"D", 3}, {"D", 3},
{"E", 4}, {"E", 4},
{"F", 5}, {"F", 5},
{"G", 6}, {"G", 6},
{"H", 7} {"H", 7}
} }
); );
// ┌────►A──────┐ // ┌────►A──────┐
// │ │ ▼ // │ │ ▼
// │ B◄──┘ ┌──D──┐ // │ B◄──┘ ┌──D──┐
// │ │ │ │ // │ │ │ │
// │ ▼ ▼ ▼ // │ ▼ ▼ ▼
// └─C◄───┐ E F // └─C◄───┐ E F
// │ │ │ │ // │ │ │ │
// └───►G◄─┴─────┘ // └───►G◄─┴─────┘
inputGraph[1] = generateGraph( inputGraph[1] = generateGraph(
{ "A", "B", "C", "D", "E", "F", "G" }, { "A", "B", "C", "D", "E", "F", "G" },
{ {
edge("A", "B"), edge("A", "B"),
edge("B", "C"), edge("B", "C"),
edge("C", "G"), edge("C", "G"),
edge("C", "A"), edge("C", "A"),
edge("A", "D"), edge("A", "D"),
edge("D", "E"), edge("D", "E"),
edge("D", "F"), edge("D", "F"),
edge("E", "G"), edge("E", "G"),
edge("F", "G"), edge("F", "G"),
edge("G", "C") edge("G", "C")
}, },
{0, 0, 0, 0, 0, 4, 4}, {0, 0, 0, 0, 0, 4, 4},
{ {
{"A", 0}, {"A", 0},
{"B", 1}, {"B", 1},
{"C", 2}, {"C", 2},
{"G", 3}, {"G", 3},
{"D", 4}, {"D", 4},
{"E", 5}, {"E", 5},
{"F", 6} {"F", 6}
} }
); );
// ┌─────────┐ // ┌─────────┐
// │ ▼ // │ ▼
// │ ┌───A───┐ // │ ┌───A───┐
// │ │ │ // │ │ │
// │ ▼ ▼ // │ ▼ ▼
// │ ┌──►C◄───── B──┬──────┐ // │ ┌──►C◄───── B──┬──────┐
// │ │ │ ▲ │ │ // │ │ │ ▲ │ │
// │ │ │ ┌────┘ │ │ // │ │ │ ┌────┘ │ │
// │ │ ▼ │ ▼ ▼ // │ │ ▼ │ ▼ ▼
// │ │ D──┘ ┌───►E◄─────I // │ │ D──┘ ┌───►E◄─────I
// │ │ ▲ │ │ │ // │ │ ▲ │ │ │
// │ │ │ │ ├───┐ │ // │ │ │ │ ├───┐ │
// │ │ │ │ │ │ │ // │ │ │ │ │ │ │
// │ │ │ │ ▼ │ ▼ // │ │ │ │ ▼ │ ▼
// │ └───┼─────┼────F └─►H // │ └───┼─────┼────F └─►H
// │ │ │ │ │ // │ │ │ │ │
// │ │ │ │ │ // │ │ │ │ │
// │ │ │ │ │ // │ │ │ │ │
// │ └─────┴─G◄─┴──────┘ // │ └─────┴─G◄─┴──────┘
// │ │ // │ │
// └─────────────┘ // └─────────────┘
inputGraph[2] = generateGraph( inputGraph[2] = generateGraph(
{ "A", "B", "C", "D", "E", "F", "G", "H", "I" }, { "A", "B", "C", "D", "E", "F", "G", "H", "I" },
{ {
edge("A", "B"), edge("A", "B"),
edge("A", "C"), edge("A", "C"),
edge("B", "C"), edge("B", "C"),
edge("B", "I"), edge("B", "I"),
edge("B", "E"), edge("B", "E"),
edge("C", "D"), edge("C", "D"),
edge("D", "B"), edge("D", "B"),
edge("E", "H"), edge("E", "H"),
edge("E", "F"), edge("E", "F"),
edge("F", "G"), edge("F", "G"),
edge("F", "C"), edge("F", "C"),
edge("G", "E"), edge("G", "E"),
edge("G", "A"), edge("G", "A"),
edge("G", "D"), edge("G", "D"),
edge("H", "G"), edge("H", "G"),
edge("I", "E"), edge("I", "E"),
edge("I", "H") edge("I", "H")
}, },
{0, 0, 0, 0, 1, 1, 1, 1, 5}, {0, 0, 0, 0, 1, 1, 1, 1, 5},
{ {
{"A", 0}, {"A", 0},
{"B", 1}, {"B", 1},
{"C", 2}, {"C", 2},
{"D", 3}, {"D", 3},
{"I", 4}, {"I", 4},
{"E", 5}, {"E", 5},
{"H", 6}, {"H", 6},
{"G", 7}, {"G", 7},
{"F", 8} {"F", 8}
} }
); );
// T. Lengauer and R. E. Tarjan pg. 122 fig. 1 // T. Lengauer and R. E. Tarjan pg. 122 fig. 1
// ref: https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf // ref: https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf
inputGraph[3] = generateGraph( inputGraph[3] = generateGraph(
{ "R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K" }, { "R", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "K" },
{ {
edge("R", "B"), edge("R", "B"),
edge("R", "A"), edge("R", "A"),
edge("R", "C"), edge("R", "C"),
edge("B", "A"), edge("B", "A"),
edge("B", "D"), edge("B", "D"),
edge("B", "E"), edge("B", "E"),
edge("A", "D"), edge("A", "D"),
edge("D", "L"), edge("D", "L"),
edge("L", "H"), edge("L", "H"),
edge("E", "H"), edge("E", "H"),
edge("H", "E"), edge("H", "E"),
edge("H", "K"), edge("H", "K"),
edge("K", "I"), edge("K", "I"),
edge("K", "R"), edge("K", "R"),
edge("C", "F"), edge("C", "F"),
edge("C", "G"), edge("C", "G"),
edge("F", "I"), edge("F", "I"),
edge("G", "I"), edge("G", "I"),
edge("G", "J"), edge("G", "J"),
edge("J", "I"), edge("J", "I"),
edge("I", "K"), edge("I", "K"),
}, },
{0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 9, 9, 11}, {0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 9, 9, 11},
{ {
{"R", 0}, {"R", 0},
{"B", 1}, {"B", 1},
{"A", 2}, {"A", 2},
{"D", 3}, {"D", 3},
{"L", 4}, {"L", 4},
{"H", 5}, {"H", 5},
{"E", 6}, {"E", 6},
{"K", 7}, {"K", 7},
{"I", 8}, {"I", 8},
{"C", 9}, {"C", 9},
{"F", 10}, {"F", 10},
{"G", 11}, {"G", 11},
{"J", 12} {"J", 12}
} }
); );
// Extracted from Loukas Georgiadis Dissertation - Linear-Time Algorithms for Dominators and Related Problems // Extracted from Loukas Georgiadis Dissertation - Linear-Time Algorithms for Dominators and Related Problems
// pg. 12 Fig. 2.2 // pg. 12 Fig. 2.2
// ref: https://www.cs.princeton.edu/techreports/2005/737.pdf // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf
inputGraph[4] = generateGraph( inputGraph[4] = generateGraph(
{ "R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y" }, { "R", "W", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "Y" },
{ {
edge("R", "W"), edge("R", "W"),
edge("R", "Y"), edge("R", "Y"),
edge("W", "X1"), edge("W", "X1"),
edge("Y", "X7"), edge("Y", "X7"),
edge("X1", "X2"), edge("X1", "X2"),
edge("X2", "X1"), edge("X2", "X1"),
edge("X2", "X3"), edge("X2", "X3"),
edge("X3", "X2"), edge("X3", "X2"),
edge("X3", "X4"), edge("X3", "X4"),
edge("X4", "X3"), edge("X4", "X3"),
edge("X4", "X5"), edge("X4", "X5"),
edge("X5", "X4"), edge("X5", "X4"),
edge("X5", "X6"), edge("X5", "X6"),
edge("X6", "X5"), edge("X6", "X5"),
edge("X6", "X7"), edge("X6", "X7"),
edge("X7", "X6") edge("X7", "X6")
}, },
{0, 0, 0, 0, 0, 0, 0, 0, 0 , 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0 , 0},
{ {
{"R", 0}, {"R", 0},
{"W", 1}, {"W", 1},
{"X1", 2}, {"X1", 2},
{"X2", 3}, {"X2", 3},
{"X3", 4}, {"X3", 4},
{"X4", 5}, {"X4", 5},
{"X5", 6}, {"X5", 6},
{"X6", 7}, {"X6", 7},
{"X7", 8}, {"X7", 8},
{"Y", 9} {"Y", 9}
} }
); );
// Worst-case families for k = 3 // Worst-case families for k = 3
// Example itworst(3) pg. 26 fig. 2.9 // Example itworst(3) pg. 26 fig. 2.9
// ref: https://www.cs.princeton.edu/techreports/2005/737.pdf // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf
inputGraph[5] = generateGraph( inputGraph[5] = generateGraph(
{ "R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" }, { "R", "W1", "W2", "W3", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" },
{ {
edge("R", "W1"), edge("R", "W1"),
edge("R", "X1"), edge("R", "X1"),
edge("R", "Z3"), edge("R", "Z3"),
edge("W1", "W2"), edge("W1", "W2"),
edge("W2", "W3"), edge("W2", "W3"),
edge("X1", "X2"), edge("X1", "X2"),
edge("X2", "X3"), edge("X2", "X3"),
edge("X3", "Y1"), edge("X3", "Y1"),
edge("Y1", "W1"), edge("Y1", "W1"),
edge("Y1", "W2"), edge("Y1", "W2"),
edge("Y1", "W3"), edge("Y1", "W3"),
edge("Y1", "Y2"), edge("Y1", "Y2"),
edge("Y2", "W1"), edge("Y2", "W1"),
edge("Y2", "W2"), edge("Y2", "W2"),
edge("Y2", "W3"), edge("Y2", "W3"),
edge("Y2", "Y3"), edge("Y2", "Y3"),
edge("Y3", "W1"), edge("Y3", "W1"),
edge("Y3", "W2"), edge("Y3", "W2"),
edge("Y3", "W3"), edge("Y3", "W3"),
edge("Y3", "Z1"), edge("Y3", "Z1"),
edge("Z1", "Z2"), edge("Z1", "Z2"),
edge("Z2", "Z1"), edge("Z2", "Z1"),
edge("Z2", "Z3"), edge("Z2", "Z3"),
edge("Z3", "Z2") edge("Z3", "Z2")
}, },
{0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 0, 0, 0}, {0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 0, 0, 0},
{ {
{"R", 0}, {"R", 0},
{"W1", 1}, {"W1", 1},
{"W2", 2}, {"W2", 2},
{"W3", 3}, {"W3", 3},
{"X1", 4}, {"X1", 4},
{"X2", 5}, {"X2", 5},
{"X3", 6}, {"X3", 6},
{"Y1", 7}, {"Y1", 7},
{"Y2", 8}, {"Y2", 8},
{"Y3", 9}, {"Y3", 9},
{"Z1", 10}, {"Z1", 10},
{"Z2", 11}, {"Z2", 11},
{"Z3", 12} {"Z3", 12}
} }
); );
// Worst-case families for k = 3 // Worst-case families for k = 3
// Example idfsquad(3) pg. 26 fig. 2.9 // Example idfsquad(3) pg. 26 fig. 2.9
// ref: https://www.cs.princeton.edu/techreports/2005/737.pdf // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf
inputGraph[6] = generateGraph( inputGraph[6] = generateGraph(
{ "R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" }, { "R", "X1", "X2", "X3", "Y1", "Y2", "Y3", "Z1", "Z2", "Z3" },
{ {
edge("R", "X1"), edge("R", "X1"),
edge("R", "Z1"), edge("R", "Z1"),
edge("X1", "Y1"), edge("X1", "Y1"),
edge("X1", "X2"), edge("X1", "X2"),
edge("X2", "X3"), edge("X2", "X3"),
edge("X2", "Y2"), edge("X2", "Y2"),
edge("X3", "Y3"), edge("X3", "Y3"),
edge("Y1", "Z1"), edge("Y1", "Z1"),
edge("Y1", "Z2"), edge("Y1", "Z2"),
edge("Z1", "Y1"), edge("Z1", "Y1"),
edge("Y2", "Z2"), edge("Y2", "Z2"),
edge("Y2", "Z3"), edge("Y2", "Z3"),
edge("Z2", "Y2"), edge("Z2", "Y2"),
edge("Y3", "Z3"), edge("Y3", "Z3"),
edge("Z3", "Y3") edge("Z3", "Y3")
}, },
{0, 0, 0, 0, 0, 0, 0, 0, 1, 8}, {0, 0, 0, 0, 0, 0, 0, 0, 1, 8},
{ {
{"R", 0}, {"R", 0},
{"X1", 1}, {"X1", 1},
{"Y1", 2}, {"Y1", 2},
{"Z1", 3}, {"Z1", 3},
{"Z2", 4}, {"Z2", 4},
{"Y2", 5}, {"Y2", 5},
{"Z3", 6}, {"Z3", 6},
{"Y3", 7}, {"Y3", 7},
{"X2", 8}, {"X2", 8},
{"X3", 9} {"X3", 9}
} }
); );
// Worst-case families for k = 3 // Worst-case families for k = 3
// Example ibfsquad(3) pg. 26 fig. 2.9 // Example ibfsquad(3) pg. 26 fig. 2.9
// ref: https://www.cs.princeton.edu/techreports/2005/737.pdf // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf
inputGraph[7] = generateGraph( inputGraph[7] = generateGraph(
{ "R", "W", "X1", "X2", "X3", "Y", "Z" }, { "R", "W", "X1", "X2", "X3", "Y", "Z" },
{ {
edge("R", "W"), edge("R", "W"),
edge("R", "Y"), edge("R", "Y"),
edge("W", "X1"), edge("W", "X1"),
edge("W", "X2"), edge("W", "X2"),
edge("W", "X3"), edge("W", "X3"),
edge("Y", "Z"), edge("Y", "Z"),
edge("Z", "X3"), edge("Z", "X3"),
edge("X3", "X2"), edge("X3", "X2"),
edge("X2", "X1") edge("X2", "X1")
}, },
{0, 0, 0, 0, 0, 0, 5}, {0, 0, 0, 0, 0, 0, 5},
{ {
{"R", 0}, {"R", 0},
{"W", 1}, {"W", 1},
{"X1", 2}, {"X1", 2},
{"X2", 3}, {"X2", 3},
{"X3", 4}, {"X3", 4},
{"Y", 5}, {"Y", 5},
{"Z", 6} {"Z", 6}
} }
); );
// Worst-case families for k = 3 // Worst-case families for k = 3
// Example sncaworst(3) pg. 26 fig. 2.9 // Example sncaworst(3) pg. 26 fig. 2.9
// ref: https://www.cs.princeton.edu/techreports/2005/737.pdf // ref: https://www.cs.princeton.edu/techreports/2005/737.pdf
inputGraph[8] = generateGraph( inputGraph[8] = generateGraph(
{ "R", "X1", "X2", "X3", "Y1", "Y2", "Y3" }, { "R", "X1", "X2", "X3", "Y1", "Y2", "Y3" },
{ {
edge("R", "X1"), edge("R", "X1"),
edge("R", "Y1"), edge("R", "Y1"),
edge("R", "Y2"), edge("R", "Y2"),
edge("R", "Y3"), edge("R", "Y3"),
edge("X1", "X2"), edge("X1", "X2"),
edge("X2", "X3"), edge("X2", "X3"),
edge("X3", "Y1"), edge("X3", "Y1"),
edge("X3", "Y2"), edge("X3", "Y2"),
edge("X3", "Y3") edge("X3", "Y3")
}, },
{0, 0, 1, 2, 0, 0, 0}, {0, 0, 1, 2, 0, 0, 0},
{ {
{"R", 0}, {"R", 0},
{"X1", 1}, {"X1", 1},
{"X2", 2}, {"X2", 2},
{"X3", 3}, {"X3", 3},
{"Y1", 4}, {"Y1", 4},
{"Y2", 5}, {"Y2", 5},
{"Y3", 6}, {"Y3", 6},
} }
); );
for (ImmediateDominatorTest const* g: inputGraph) for (ImmediateDominatorTest const* g: inputGraph)
{ {
Dominator< Dominator<
ImmediateDominatorTest::Vertex, ImmediateDominatorTest::Vertex,
ImmediateDominatorTest::ForEachVertexSuccessorTest ImmediateDominatorTest::ForEachVertexSuccessorTest
> dom(*g->entry, g->numVertices); > dom(*g->entry, g->numVertices);
for (auto [v, idx]: dom.vertexIndices()) for (auto [v, idx]: dom.vertexIndices())
BOOST_CHECK(g->expectedDFSIndices.at(v.data) == idx); BOOST_CHECK(g->expectedDFSIndices.at(v.data) == idx);
BOOST_TEST(dom.immediateDominators() == g->expectedIdom); BOOST_TEST(dom.immediateDominators() == g->expectedIdom);
} }
} }