This repository has been archived by the owner on Aug 5, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lex_m.h
129 lines (107 loc) · 3.65 KB
/
lex_m.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
* Implementation of the LEX M algorithm described by Rose & Tarjan in
* "Algorithmic aspects of vertex elimination on graphs".
*
* See: https://doi.org/10.1137/0205021
*/
#ifndef ALGO_LEXM_H
#define ALGO_LEXM_H
#include <limits>
#include <vector>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <boost/graph/graph_concepts.hpp>
#include "utils.h"
#include "radix_sort.h"
/**
* Compute a minimal elimination order for the given graph.
*
* @param g graph to compute the order for
* @return a minimal elimination order for the graph as an ordered sequence of
* all its vertices
*
* @pre `g` is a simple, connected, undirected graph
*/
template <class Graph>
VertexOrder<Graph> lex_m(const Graph &g) {
typedef VertexDesc<Graph> Vertex;
typedef VertexSizeT<Graph> Label;
typedef std::unordered_set<Vertex> VertexSet;
static_assert(!std::numeric_limits<Label>::is_signed);
BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept<Graph>));
BOOST_CONCEPT_ASSERT((boost::AdjacencyGraphConcept<Graph>));
const auto n_vertices = boost::num_vertices(g);
VertexSet unnumbered = std::make_from_tuple<VertexSet>(boost::vertices(g));
Label n_unique_labels = 1;
VertexOrder<Graph> order(n_vertices);
std::unordered_map<Vertex, Label> label(n_vertices);
std::unordered_map<Label, std::deque<Vertex>> to_reach;
VertexSet reached;
// Start with any vertex
Vertex cur_vertex = *unnumbered.begin();
// Number each vertex of the graph in reverse order
for (size_t index = n_vertices - 1; index < n_vertices; index--) {
// Assign index to cur_vertex
unnumbered.erase(cur_vertex);
order[index] = cur_vertex;
to_reach.clear();
reached.clear();
// Mark each neighbor of cur_vertex as reached and increment its label,
// while also adding it to the queue for reaching other vertices
for (const auto v : iter_neighbors(g, cur_vertex)) {
if (unnumbered.find(v) != unnumbered.end()) {
reached.insert(v);
to_reach[label[v]].push_back(v);
label[v]++;
}
}
// Explore all unnumbered vertices of the graph in BFS order, following
// the chains of vertices from lowest to highest maximum label
for (Label l = 0; l < 2 * n_unique_labels; l += 2) {
// While we have vertices to reach with chains of maximum label up
// to l
while (!to_reach[l].empty()) {
const auto v = to_reach[l].front();
to_reach[l].pop_front();
// For all neighbors of the vertex
for (const auto w : iter_neighbors(g, v)) {
if (unnumbered.find(w) != unnumbered.end() && reached.find(w) == reached.end()) {
reached.insert(w);
if (label[w] > l) {
// We reached this vertex with a chain of lower
// labeled vertives, increase its label
to_reach[label[w]].push_back(w);
label[w]++;
} else {
// We reached this vertex, but with a chain of
// vertices with some higher-or-equal labels, add it
// to the queue to be explored later
to_reach[l].push_back(w);
}
}
}
}
}
if (unnumbered.empty())
break;
// Sort and recompute the labels of all unnumbered vertices to be
// [0, 2, ..., 2 * n_unique_labels) while also counting the number of
// unique labels
std::vector<Vertex> to_relabel(unnumbered.begin(), unnumbered.end());
radix_sort(to_relabel.begin(), to_relabel.end(), label);
Label prev_label = label[to_relabel.front()];
n_unique_labels = 1;
for (const auto v : to_relabel) {
if (label[v] != prev_label) {
n_unique_labels++;
prev_label = label[v];
}
label[v] = 2 * (n_unique_labels - 1);
}
// Pick the highest labeled vertex as the next one
cur_vertex = to_relabel.back();
}
return order;
}
#endif // ALGO_LEXM_H