williamr@2
|
1 |
//-*-c++-*-
|
williamr@2
|
2 |
//=======================================================================
|
williamr@2
|
3 |
// Copyright 1997-2001 University of Notre Dame.
|
williamr@2
|
4 |
// Authors: Lie-Quan Lee, Jeremy Siek
|
williamr@2
|
5 |
//
|
williamr@2
|
6 |
// Distributed under the Boost Software License, Version 1.0. (See
|
williamr@2
|
7 |
// accompanying file LICENSE_1_0.txt or copy at
|
williamr@2
|
8 |
// http://www.boost.org/LICENSE_1_0.txt)
|
williamr@2
|
9 |
//=======================================================================
|
williamr@2
|
10 |
//
|
williamr@2
|
11 |
#ifndef MINIMUM_DEGREE_ORDERING_HPP
|
williamr@2
|
12 |
#define MINIMUM_DEGREE_ORDERING_HPP
|
williamr@2
|
13 |
|
williamr@2
|
14 |
#include <vector>
|
williamr@2
|
15 |
#include <cassert>
|
williamr@2
|
16 |
#include <boost/config.hpp>
|
williamr@2
|
17 |
#include <boost/pending/bucket_sorter.hpp>
|
williamr@2
|
18 |
#include <boost/detail/numeric_traits.hpp> // for integer_traits
|
williamr@2
|
19 |
#include <boost/graph/graph_traits.hpp>
|
williamr@2
|
20 |
#include <boost/property_map.hpp>
|
williamr@2
|
21 |
|
williamr@2
|
22 |
namespace boost {
|
williamr@2
|
23 |
|
williamr@2
|
24 |
namespace detail {
|
williamr@2
|
25 |
|
williamr@2
|
26 |
//
|
williamr@2
|
27 |
// Given a set of n integers (where the integer values range from
|
williamr@2
|
28 |
// zero to n-1), we want to keep track of a collection of stacks
|
williamr@2
|
29 |
// of integers. It so happens that an integer will appear in at
|
williamr@2
|
30 |
// most one stack at a time, so the stacks form disjoint sets.
|
williamr@2
|
31 |
// Because of these restrictions, we can use one big array to
|
williamr@2
|
32 |
// store all the stacks, intertwined with one another.
|
williamr@2
|
33 |
// No allocation/deallocation happens in the push()/pop() methods
|
williamr@2
|
34 |
// so this is faster than using std::stack's.
|
williamr@2
|
35 |
//
|
williamr@2
|
36 |
template <class SignedInteger>
|
williamr@2
|
37 |
class Stacks {
|
williamr@2
|
38 |
typedef SignedInteger value_type;
|
williamr@2
|
39 |
typedef typename std::vector<value_type>::size_type size_type;
|
williamr@2
|
40 |
public:
|
williamr@2
|
41 |
Stacks(size_type n) : data(n) {}
|
williamr@2
|
42 |
|
williamr@2
|
43 |
//: stack
|
williamr@2
|
44 |
class stack {
|
williamr@2
|
45 |
typedef typename std::vector<value_type>::iterator Iterator;
|
williamr@2
|
46 |
public:
|
williamr@2
|
47 |
stack(Iterator _data, const value_type& head)
|
williamr@2
|
48 |
: data(_data), current(head) {}
|
williamr@2
|
49 |
|
williamr@2
|
50 |
// did not use default argument here to avoid internal compiler error
|
williamr@2
|
51 |
// in g++.
|
williamr@2
|
52 |
stack(Iterator _data)
|
williamr@2
|
53 |
: data(_data), current(-(std::numeric_limits<value_type>::max)()) {}
|
williamr@2
|
54 |
|
williamr@2
|
55 |
void pop() {
|
williamr@2
|
56 |
assert(! empty());
|
williamr@2
|
57 |
current = data[current];
|
williamr@2
|
58 |
}
|
williamr@2
|
59 |
void push(value_type v) {
|
williamr@2
|
60 |
data[v] = current;
|
williamr@2
|
61 |
current = v;
|
williamr@2
|
62 |
}
|
williamr@2
|
63 |
bool empty() {
|
williamr@2
|
64 |
return current == -(std::numeric_limits<value_type>::max)();
|
williamr@2
|
65 |
}
|
williamr@2
|
66 |
value_type& top() { return current; }
|
williamr@2
|
67 |
private:
|
williamr@2
|
68 |
Iterator data;
|
williamr@2
|
69 |
value_type current;
|
williamr@2
|
70 |
};
|
williamr@2
|
71 |
|
williamr@2
|
72 |
// To return a stack object
|
williamr@2
|
73 |
stack make_stack()
|
williamr@2
|
74 |
{ return stack(data.begin()); }
|
williamr@2
|
75 |
protected:
|
williamr@2
|
76 |
std::vector<value_type> data;
|
williamr@2
|
77 |
};
|
williamr@2
|
78 |
|
williamr@2
|
79 |
|
williamr@2
|
80 |
// marker class, a generalization of coloring.
|
williamr@2
|
81 |
//
|
williamr@2
|
82 |
// This class is to provide a generalization of coloring which has
|
williamr@2
|
83 |
// complexity of amortized constant time to set all vertices' color
|
williamr@2
|
84 |
// back to be untagged. It implemented by increasing a tag.
|
williamr@2
|
85 |
//
|
williamr@2
|
86 |
// The colors are:
|
williamr@2
|
87 |
// not tagged
|
williamr@2
|
88 |
// tagged
|
williamr@2
|
89 |
// multiple_tagged
|
williamr@2
|
90 |
// done
|
williamr@2
|
91 |
//
|
williamr@2
|
92 |
template <class SignedInteger, class Vertex, class VertexIndexMap>
|
williamr@2
|
93 |
class Marker {
|
williamr@2
|
94 |
typedef SignedInteger value_type;
|
williamr@2
|
95 |
typedef typename std::vector<value_type>::size_type size_type;
|
williamr@2
|
96 |
|
williamr@2
|
97 |
static value_type done()
|
williamr@2
|
98 |
{ return (std::numeric_limits<value_type>::max)()/2; }
|
williamr@2
|
99 |
public:
|
williamr@2
|
100 |
Marker(size_type _num, VertexIndexMap index_map)
|
williamr@2
|
101 |
: tag(1 - (std::numeric_limits<value_type>::max)()),
|
williamr@2
|
102 |
data(_num, - (std::numeric_limits<value_type>::max)()),
|
williamr@2
|
103 |
id(index_map) {}
|
williamr@2
|
104 |
|
williamr@2
|
105 |
void mark_done(Vertex node) { data[get(id, node)] = done(); }
|
williamr@2
|
106 |
|
williamr@2
|
107 |
bool is_done(Vertex node) { return data[get(id, node)] == done(); }
|
williamr@2
|
108 |
|
williamr@2
|
109 |
void mark_tagged(Vertex node) { data[get(id, node)] = tag; }
|
williamr@2
|
110 |
|
williamr@2
|
111 |
void mark_multiple_tagged(Vertex node) { data[get(id, node)] = multiple_tag; }
|
williamr@2
|
112 |
|
williamr@2
|
113 |
bool is_tagged(Vertex node) const { return data[get(id, node)] >= tag; }
|
williamr@2
|
114 |
|
williamr@2
|
115 |
bool is_not_tagged(Vertex node) const { return data[get(id, node)] < tag; }
|
williamr@2
|
116 |
|
williamr@2
|
117 |
bool is_multiple_tagged(Vertex node) const
|
williamr@2
|
118 |
{ return data[get(id, node)] >= multiple_tag; }
|
williamr@2
|
119 |
|
williamr@2
|
120 |
void increment_tag() {
|
williamr@2
|
121 |
const size_type num = data.size();
|
williamr@2
|
122 |
++tag;
|
williamr@2
|
123 |
if ( tag >= done() ) {
|
williamr@2
|
124 |
tag = 1 - (std::numeric_limits<value_type>::max)();
|
williamr@2
|
125 |
for (size_type i = 0; i < num; ++i)
|
williamr@2
|
126 |
if ( data[i] < done() )
|
williamr@2
|
127 |
data[i] = - (std::numeric_limits<value_type>::max)();
|
williamr@2
|
128 |
}
|
williamr@2
|
129 |
}
|
williamr@2
|
130 |
|
williamr@2
|
131 |
void set_multiple_tag(value_type mdeg0)
|
williamr@2
|
132 |
{
|
williamr@2
|
133 |
const size_type num = data.size();
|
williamr@2
|
134 |
multiple_tag = tag + mdeg0;
|
williamr@2
|
135 |
|
williamr@2
|
136 |
if ( multiple_tag >= done() ) {
|
williamr@2
|
137 |
tag = 1-(std::numeric_limits<value_type>::max)();
|
williamr@2
|
138 |
|
williamr@2
|
139 |
for (size_type i=0; i<num; i++)
|
williamr@2
|
140 |
if ( data[i] < done() )
|
williamr@2
|
141 |
data[i] = -(std::numeric_limits<value_type>::max)();
|
williamr@2
|
142 |
|
williamr@2
|
143 |
multiple_tag = tag + mdeg0;
|
williamr@2
|
144 |
}
|
williamr@2
|
145 |
}
|
williamr@2
|
146 |
|
williamr@2
|
147 |
void set_tag_as_multiple_tag() { tag = multiple_tag; }
|
williamr@2
|
148 |
|
williamr@2
|
149 |
protected:
|
williamr@2
|
150 |
value_type tag;
|
williamr@2
|
151 |
value_type multiple_tag;
|
williamr@2
|
152 |
std::vector<value_type> data;
|
williamr@2
|
153 |
VertexIndexMap id;
|
williamr@2
|
154 |
};
|
williamr@2
|
155 |
|
williamr@2
|
156 |
template< class Iterator, class SignedInteger,
|
williamr@2
|
157 |
class Vertex, class VertexIndexMap, int offset = 1 >
|
williamr@2
|
158 |
class Numbering {
|
williamr@2
|
159 |
typedef SignedInteger number_type;
|
williamr@2
|
160 |
number_type num; //start from 1 instead of zero
|
williamr@2
|
161 |
Iterator data;
|
williamr@2
|
162 |
number_type max_num;
|
williamr@2
|
163 |
VertexIndexMap id;
|
williamr@2
|
164 |
public:
|
williamr@2
|
165 |
Numbering(Iterator _data, number_type _max_num, VertexIndexMap id)
|
williamr@2
|
166 |
: num(1), data(_data), max_num(_max_num), id(id) {}
|
williamr@2
|
167 |
void operator()(Vertex node) { data[get(id, node)] = -num; }
|
williamr@2
|
168 |
bool all_done(number_type i = 0) const { return num + i > max_num; }
|
williamr@2
|
169 |
void increment(number_type i = 1) { num += i; }
|
williamr@2
|
170 |
bool is_numbered(Vertex node) const {
|
williamr@2
|
171 |
return data[get(id, node)] < 0;
|
williamr@2
|
172 |
}
|
williamr@2
|
173 |
void indistinguishable(Vertex i, Vertex j) {
|
williamr@2
|
174 |
data[get(id, i)] = - (get(id, j) + offset);
|
williamr@2
|
175 |
}
|
williamr@2
|
176 |
};
|
williamr@2
|
177 |
|
williamr@2
|
178 |
template <class SignedInteger, class Vertex, class VertexIndexMap>
|
williamr@2
|
179 |
class degreelists_marker {
|
williamr@2
|
180 |
public:
|
williamr@2
|
181 |
typedef SignedInteger value_type;
|
williamr@2
|
182 |
typedef typename std::vector<value_type>::size_type size_type;
|
williamr@2
|
183 |
degreelists_marker(size_type n, VertexIndexMap id)
|
williamr@2
|
184 |
: marks(n, 0), id(id) {}
|
williamr@2
|
185 |
void mark_need_update(Vertex i) { marks[get(id, i)] = 1; }
|
williamr@2
|
186 |
bool need_update(Vertex i) { return marks[get(id, i)] == 1; }
|
williamr@2
|
187 |
bool outmatched_or_done (Vertex i) { return marks[get(id, i)] == -1; }
|
williamr@2
|
188 |
void mark(Vertex i) { marks[get(id, i)] = -1; }
|
williamr@2
|
189 |
void unmark(Vertex i) { marks[get(id, i)] = 0; }
|
williamr@2
|
190 |
private:
|
williamr@2
|
191 |
std::vector<value_type> marks;
|
williamr@2
|
192 |
VertexIndexMap id;
|
williamr@2
|
193 |
};
|
williamr@2
|
194 |
|
williamr@2
|
195 |
// Helper function object for edge removal
|
williamr@2
|
196 |
template <class Graph, class MarkerP, class NumberD, class Stack,
|
williamr@2
|
197 |
class VertexIndexMap>
|
williamr@2
|
198 |
class predicateRemoveEdge1 {
|
williamr@2
|
199 |
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
|
williamr@2
|
200 |
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
|
williamr@2
|
201 |
public:
|
williamr@2
|
202 |
predicateRemoveEdge1(Graph& _g, MarkerP& _marker,
|
williamr@2
|
203 |
NumberD _numbering, Stack& n_e, VertexIndexMap id)
|
williamr@2
|
204 |
: g(&_g), marker(&_marker), numbering(_numbering),
|
williamr@2
|
205 |
neighbor_elements(&n_e), id(id) {}
|
williamr@2
|
206 |
|
williamr@2
|
207 |
bool operator()(edge_t e) {
|
williamr@2
|
208 |
vertex_t dist = target(e, *g);
|
williamr@2
|
209 |
if ( marker->is_tagged(dist) )
|
williamr@2
|
210 |
return true;
|
williamr@2
|
211 |
marker->mark_tagged(dist);
|
williamr@2
|
212 |
if (numbering.is_numbered(dist)) {
|
williamr@2
|
213 |
neighbor_elements->push(get(id, dist));
|
williamr@2
|
214 |
return true;
|
williamr@2
|
215 |
}
|
williamr@2
|
216 |
return false;
|
williamr@2
|
217 |
}
|
williamr@2
|
218 |
private:
|
williamr@2
|
219 |
Graph* g;
|
williamr@2
|
220 |
MarkerP* marker;
|
williamr@2
|
221 |
NumberD numbering;
|
williamr@2
|
222 |
Stack* neighbor_elements;
|
williamr@2
|
223 |
VertexIndexMap id;
|
williamr@2
|
224 |
};
|
williamr@2
|
225 |
|
williamr@2
|
226 |
// Helper function object for edge removal
|
williamr@2
|
227 |
template <class Graph, class MarkerP>
|
williamr@2
|
228 |
class predicate_remove_tagged_edges
|
williamr@2
|
229 |
{
|
williamr@2
|
230 |
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
|
williamr@2
|
231 |
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
|
williamr@2
|
232 |
public:
|
williamr@2
|
233 |
predicate_remove_tagged_edges(Graph& _g, MarkerP& _marker)
|
williamr@2
|
234 |
: g(&_g), marker(&_marker) {}
|
williamr@2
|
235 |
|
williamr@2
|
236 |
bool operator()(edge_t e) {
|
williamr@2
|
237 |
vertex_t dist = target(e, *g);
|
williamr@2
|
238 |
if ( marker->is_tagged(dist) )
|
williamr@2
|
239 |
return true;
|
williamr@2
|
240 |
return false;
|
williamr@2
|
241 |
}
|
williamr@2
|
242 |
private:
|
williamr@2
|
243 |
Graph* g;
|
williamr@2
|
244 |
MarkerP* marker;
|
williamr@2
|
245 |
};
|
williamr@2
|
246 |
|
williamr@2
|
247 |
template<class Graph, class DegreeMap,
|
williamr@2
|
248 |
class InversePermutationMap,
|
williamr@2
|
249 |
class PermutationMap,
|
williamr@2
|
250 |
class SuperNodeMap,
|
williamr@2
|
251 |
class VertexIndexMap>
|
williamr@2
|
252 |
class mmd_impl
|
williamr@2
|
253 |
{
|
williamr@2
|
254 |
// Typedefs
|
williamr@2
|
255 |
typedef graph_traits<Graph> Traits;
|
williamr@2
|
256 |
typedef typename Traits::vertices_size_type size_type;
|
williamr@2
|
257 |
typedef typename detail::integer_traits<size_type>::difference_type
|
williamr@2
|
258 |
diff_t;
|
williamr@2
|
259 |
typedef typename Traits::vertex_descriptor vertex_t;
|
williamr@2
|
260 |
typedef typename Traits::adjacency_iterator adj_iter;
|
williamr@2
|
261 |
typedef iterator_property_map<vertex_t*,
|
williamr@2
|
262 |
identity_property_map, vertex_t, vertex_t&> IndexVertexMap;
|
williamr@2
|
263 |
typedef detail::Stacks<diff_t> Workspace;
|
williamr@2
|
264 |
typedef bucket_sorter<size_type, vertex_t, DegreeMap, VertexIndexMap>
|
williamr@2
|
265 |
DegreeLists;
|
williamr@2
|
266 |
typedef Numbering<InversePermutationMap, diff_t, vertex_t,VertexIndexMap>
|
williamr@2
|
267 |
NumberingD;
|
williamr@2
|
268 |
typedef degreelists_marker<diff_t, vertex_t, VertexIndexMap>
|
williamr@2
|
269 |
DegreeListsMarker;
|
williamr@2
|
270 |
typedef Marker<diff_t, vertex_t, VertexIndexMap> MarkerP;
|
williamr@2
|
271 |
|
williamr@2
|
272 |
// Data Members
|
williamr@2
|
273 |
|
williamr@2
|
274 |
// input parameters
|
williamr@2
|
275 |
Graph& G;
|
williamr@2
|
276 |
int delta;
|
williamr@2
|
277 |
DegreeMap degree;
|
williamr@2
|
278 |
InversePermutationMap inverse_perm;
|
williamr@2
|
279 |
PermutationMap perm;
|
williamr@2
|
280 |
SuperNodeMap supernode_size;
|
williamr@2
|
281 |
VertexIndexMap vertex_index_map;
|
williamr@2
|
282 |
|
williamr@2
|
283 |
// internal data-structures
|
williamr@2
|
284 |
std::vector<vertex_t> index_vertex_vec;
|
williamr@2
|
285 |
size_type n;
|
williamr@2
|
286 |
IndexVertexMap index_vertex_map;
|
williamr@2
|
287 |
DegreeLists degreelists;
|
williamr@2
|
288 |
NumberingD numbering;
|
williamr@2
|
289 |
DegreeListsMarker degree_lists_marker;
|
williamr@2
|
290 |
MarkerP marker;
|
williamr@2
|
291 |
Workspace work_space;
|
williamr@2
|
292 |
public:
|
williamr@2
|
293 |
mmd_impl(Graph& g, size_type n_, int delta, DegreeMap degree,
|
williamr@2
|
294 |
InversePermutationMap inverse_perm,
|
williamr@2
|
295 |
PermutationMap perm,
|
williamr@2
|
296 |
SuperNodeMap supernode_size,
|
williamr@2
|
297 |
VertexIndexMap id)
|
williamr@2
|
298 |
: G(g), delta(delta), degree(degree),
|
williamr@2
|
299 |
inverse_perm(inverse_perm),
|
williamr@2
|
300 |
perm(perm),
|
williamr@2
|
301 |
supernode_size(supernode_size),
|
williamr@2
|
302 |
vertex_index_map(id),
|
williamr@2
|
303 |
index_vertex_vec(n_),
|
williamr@2
|
304 |
n(n_),
|
williamr@2
|
305 |
degreelists(n_ + 1, n_, degree, id),
|
williamr@2
|
306 |
numbering(inverse_perm, n_, vertex_index_map),
|
williamr@2
|
307 |
degree_lists_marker(n_, vertex_index_map),
|
williamr@2
|
308 |
marker(n_, vertex_index_map),
|
williamr@2
|
309 |
work_space(n_)
|
williamr@2
|
310 |
{
|
williamr@2
|
311 |
typename graph_traits<Graph>::vertex_iterator v, vend;
|
williamr@2
|
312 |
size_type vid = 0;
|
williamr@2
|
313 |
for (tie(v, vend) = vertices(G); v != vend; ++v, ++vid)
|
williamr@2
|
314 |
index_vertex_vec[vid] = *v;
|
williamr@2
|
315 |
index_vertex_map = IndexVertexMap(&index_vertex_vec[0]);
|
williamr@2
|
316 |
|
williamr@2
|
317 |
// Initialize degreelists. Degreelists organizes the nodes
|
williamr@2
|
318 |
// according to their degree.
|
williamr@2
|
319 |
for (tie(v, vend) = vertices(G); v != vend; ++v) {
|
williamr@2
|
320 |
put(degree, *v, out_degree(*v, G));
|
williamr@2
|
321 |
degreelists.push(*v);
|
williamr@2
|
322 |
}
|
williamr@2
|
323 |
}
|
williamr@2
|
324 |
|
williamr@2
|
325 |
void do_mmd()
|
williamr@2
|
326 |
{
|
williamr@2
|
327 |
// Eliminate the isolated nodes -- these are simply the nodes
|
williamr@2
|
328 |
// with no neighbors, which are accessible as a list (really, a
|
williamr@2
|
329 |
// stack) at location 0. Since these don't affect any other
|
williamr@2
|
330 |
// nodes, we can eliminate them without doing degree updates.
|
williamr@2
|
331 |
typename DegreeLists::stack list_isolated = degreelists[0];
|
williamr@2
|
332 |
while (!list_isolated.empty()) {
|
williamr@2
|
333 |
vertex_t node = list_isolated.top();
|
williamr@2
|
334 |
marker.mark_done(node);
|
williamr@2
|
335 |
numbering(node);
|
williamr@2
|
336 |
numbering.increment();
|
williamr@2
|
337 |
list_isolated.pop();
|
williamr@2
|
338 |
}
|
williamr@2
|
339 |
size_type min_degree = 1;
|
williamr@2
|
340 |
typename DegreeLists::stack list_min_degree = degreelists[min_degree];
|
williamr@2
|
341 |
|
williamr@2
|
342 |
while (list_min_degree.empty()) {
|
williamr@2
|
343 |
++min_degree;
|
williamr@2
|
344 |
list_min_degree = degreelists[min_degree];
|
williamr@2
|
345 |
}
|
williamr@2
|
346 |
|
williamr@2
|
347 |
// check if the whole eliminating process is done
|
williamr@2
|
348 |
while (!numbering.all_done()) {
|
williamr@2
|
349 |
|
williamr@2
|
350 |
size_type min_degree_limit = min_degree + delta; // WARNING
|
williamr@2
|
351 |
typename Workspace::stack llist = work_space.make_stack();
|
williamr@2
|
352 |
|
williamr@2
|
353 |
// multiple elimination
|
williamr@2
|
354 |
while (delta >= 0) {
|
williamr@2
|
355 |
|
williamr@2
|
356 |
// Find the next non-empty degree
|
williamr@2
|
357 |
for (list_min_degree = degreelists[min_degree];
|
williamr@2
|
358 |
list_min_degree.empty() && min_degree <= min_degree_limit;
|
williamr@2
|
359 |
++min_degree, list_min_degree = degreelists[min_degree])
|
williamr@2
|
360 |
;
|
williamr@2
|
361 |
if (min_degree > min_degree_limit)
|
williamr@2
|
362 |
break;
|
williamr@2
|
363 |
|
williamr@2
|
364 |
const vertex_t node = list_min_degree.top();
|
williamr@2
|
365 |
const size_type node_id = get(vertex_index_map, node);
|
williamr@2
|
366 |
list_min_degree.pop();
|
williamr@2
|
367 |
numbering(node);
|
williamr@2
|
368 |
|
williamr@2
|
369 |
// check if node is the last one
|
williamr@2
|
370 |
if (numbering.all_done(supernode_size[node])) {
|
williamr@2
|
371 |
numbering.increment(supernode_size[node]);
|
williamr@2
|
372 |
break;
|
williamr@2
|
373 |
}
|
williamr@2
|
374 |
marker.increment_tag();
|
williamr@2
|
375 |
marker.mark_tagged(node);
|
williamr@2
|
376 |
|
williamr@2
|
377 |
this->eliminate(node);
|
williamr@2
|
378 |
|
williamr@2
|
379 |
numbering.increment(supernode_size[node]);
|
williamr@2
|
380 |
llist.push(node_id);
|
williamr@2
|
381 |
} // multiple elimination
|
williamr@2
|
382 |
|
williamr@2
|
383 |
if (numbering.all_done())
|
williamr@2
|
384 |
break;
|
williamr@2
|
385 |
|
williamr@2
|
386 |
this->update( llist, min_degree);
|
williamr@2
|
387 |
}
|
williamr@2
|
388 |
|
williamr@2
|
389 |
} // do_mmd()
|
williamr@2
|
390 |
|
williamr@2
|
391 |
void eliminate(vertex_t node)
|
williamr@2
|
392 |
{
|
williamr@2
|
393 |
typename Workspace::stack element_neighbor = work_space.make_stack();
|
williamr@2
|
394 |
|
williamr@2
|
395 |
// Create two function objects for edge removal
|
williamr@2
|
396 |
typedef typename Workspace::stack WorkStack;
|
williamr@2
|
397 |
predicateRemoveEdge1<Graph, MarkerP, NumberingD,
|
williamr@2
|
398 |
WorkStack, VertexIndexMap>
|
williamr@2
|
399 |
p(G, marker, numbering, element_neighbor, vertex_index_map);
|
williamr@2
|
400 |
|
williamr@2
|
401 |
predicate_remove_tagged_edges<Graph, MarkerP> p2(G, marker);
|
williamr@2
|
402 |
|
williamr@2
|
403 |
// Reconstruct the adjacent node list, push element neighbor in a List.
|
williamr@2
|
404 |
remove_out_edge_if(node, p, G);
|
williamr@2
|
405 |
//during removal element neighbors are collected.
|
williamr@2
|
406 |
|
williamr@2
|
407 |
while (!element_neighbor.empty()) {
|
williamr@2
|
408 |
// element absorb
|
williamr@2
|
409 |
size_type e_id = element_neighbor.top();
|
williamr@2
|
410 |
vertex_t element = get(index_vertex_map, e_id);
|
williamr@2
|
411 |
adj_iter i, i_end;
|
williamr@2
|
412 |
for (tie(i, i_end) = adjacent_vertices(element, G); i != i_end; ++i){
|
williamr@2
|
413 |
vertex_t i_node = *i;
|
williamr@2
|
414 |
if (!marker.is_tagged(i_node) && !numbering.is_numbered(i_node)) {
|
williamr@2
|
415 |
marker.mark_tagged(i_node);
|
williamr@2
|
416 |
add_edge(node, i_node, G);
|
williamr@2
|
417 |
}
|
williamr@2
|
418 |
}
|
williamr@2
|
419 |
element_neighbor.pop();
|
williamr@2
|
420 |
}
|
williamr@2
|
421 |
adj_iter v, ve;
|
williamr@2
|
422 |
for (tie(v, ve) = adjacent_vertices(node, G); v != ve; ++v) {
|
williamr@2
|
423 |
vertex_t v_node = *v;
|
williamr@2
|
424 |
if (!degree_lists_marker.need_update(v_node)
|
williamr@2
|
425 |
&& !degree_lists_marker.outmatched_or_done(v_node)) {
|
williamr@2
|
426 |
degreelists.remove(v_node);
|
williamr@2
|
427 |
}
|
williamr@2
|
428 |
//update out edges of v_node
|
williamr@2
|
429 |
remove_out_edge_if(v_node, p2, G);
|
williamr@2
|
430 |
|
williamr@2
|
431 |
if ( out_degree(v_node, G) == 0 ) { // indistinguishable nodes
|
williamr@2
|
432 |
supernode_size[node] += supernode_size[v_node];
|
williamr@2
|
433 |
supernode_size[v_node] = 0;
|
williamr@2
|
434 |
numbering.indistinguishable(v_node, node);
|
williamr@2
|
435 |
marker.mark_done(v_node);
|
williamr@2
|
436 |
degree_lists_marker.mark(v_node);
|
williamr@2
|
437 |
} else { // not indistinguishable nodes
|
williamr@2
|
438 |
add_edge(v_node, node, G);
|
williamr@2
|
439 |
degree_lists_marker.mark_need_update(v_node);
|
williamr@2
|
440 |
}
|
williamr@2
|
441 |
}
|
williamr@2
|
442 |
} // eliminate()
|
williamr@2
|
443 |
|
williamr@2
|
444 |
|
williamr@2
|
445 |
template <class Stack>
|
williamr@2
|
446 |
void update(Stack llist, size_type& min_degree)
|
williamr@2
|
447 |
{
|
williamr@2
|
448 |
size_type min_degree0 = min_degree + delta + 1;
|
williamr@2
|
449 |
|
williamr@2
|
450 |
while (! llist.empty()) {
|
williamr@2
|
451 |
size_type deg, deg0 = 0;
|
williamr@2
|
452 |
|
williamr@2
|
453 |
marker.set_multiple_tag(min_degree0);
|
williamr@2
|
454 |
typename Workspace::stack q2list = work_space.make_stack();
|
williamr@2
|
455 |
typename Workspace::stack qxlist = work_space.make_stack();
|
williamr@2
|
456 |
|
williamr@2
|
457 |
vertex_t current = get(index_vertex_map, llist.top());
|
williamr@2
|
458 |
adj_iter i, ie;
|
williamr@2
|
459 |
for (tie(i,ie) = adjacent_vertices(current, G); i != ie; ++i) {
|
williamr@2
|
460 |
vertex_t i_node = *i;
|
williamr@2
|
461 |
const size_type i_id = get(vertex_index_map, i_node);
|
williamr@2
|
462 |
if (supernode_size[i_node] != 0) {
|
williamr@2
|
463 |
deg0 += supernode_size[i_node];
|
williamr@2
|
464 |
marker.mark_multiple_tagged(i_node);
|
williamr@2
|
465 |
if (degree_lists_marker.need_update(i_node)) {
|
williamr@2
|
466 |
if (out_degree(i_node, G) == 2)
|
williamr@2
|
467 |
q2list.push(i_id);
|
williamr@2
|
468 |
else
|
williamr@2
|
469 |
qxlist.push(i_id);
|
williamr@2
|
470 |
}
|
williamr@2
|
471 |
}
|
williamr@2
|
472 |
}
|
williamr@2
|
473 |
|
williamr@2
|
474 |
while (!q2list.empty()) {
|
williamr@2
|
475 |
const size_type u_id = q2list.top();
|
williamr@2
|
476 |
vertex_t u_node = get(index_vertex_map, u_id);
|
williamr@2
|
477 |
// if u_id is outmatched by others, no need to update degree
|
williamr@2
|
478 |
if (degree_lists_marker.outmatched_or_done(u_node)) {
|
williamr@2
|
479 |
q2list.pop();
|
williamr@2
|
480 |
continue;
|
williamr@2
|
481 |
}
|
williamr@2
|
482 |
marker.increment_tag();
|
williamr@2
|
483 |
deg = deg0;
|
williamr@2
|
484 |
|
williamr@2
|
485 |
adj_iter nu = adjacent_vertices(u_node, G).first;
|
williamr@2
|
486 |
vertex_t neighbor = *nu;
|
williamr@2
|
487 |
if (neighbor == u_node) {
|
williamr@2
|
488 |
++nu;
|
williamr@2
|
489 |
neighbor = *nu;
|
williamr@2
|
490 |
}
|
williamr@2
|
491 |
if (numbering.is_numbered(neighbor)) {
|
williamr@2
|
492 |
adj_iter i, ie;
|
williamr@2
|
493 |
for (tie(i,ie) = adjacent_vertices(neighbor, G);
|
williamr@2
|
494 |
i != ie; ++i) {
|
williamr@2
|
495 |
const vertex_t i_node = *i;
|
williamr@2
|
496 |
if (i_node == u_node || supernode_size[i_node] == 0)
|
williamr@2
|
497 |
continue;
|
williamr@2
|
498 |
if (marker.is_tagged(i_node)) {
|
williamr@2
|
499 |
if (degree_lists_marker.need_update(i_node)) {
|
williamr@2
|
500 |
if ( out_degree(i_node, G) == 2 ) { // is indistinguishable
|
williamr@2
|
501 |
supernode_size[u_node] += supernode_size[i_node];
|
williamr@2
|
502 |
supernode_size[i_node] = 0;
|
williamr@2
|
503 |
numbering.indistinguishable(i_node, u_node);
|
williamr@2
|
504 |
marker.mark_done(i_node);
|
williamr@2
|
505 |
degree_lists_marker.mark(i_node);
|
williamr@2
|
506 |
} else // is outmatched
|
williamr@2
|
507 |
degree_lists_marker.mark(i_node);
|
williamr@2
|
508 |
}
|
williamr@2
|
509 |
} else {
|
williamr@2
|
510 |
marker.mark_tagged(i_node);
|
williamr@2
|
511 |
deg += supernode_size[i_node];
|
williamr@2
|
512 |
}
|
williamr@2
|
513 |
}
|
williamr@2
|
514 |
} else
|
williamr@2
|
515 |
deg += supernode_size[neighbor];
|
williamr@2
|
516 |
|
williamr@2
|
517 |
deg -= supernode_size[u_node];
|
williamr@2
|
518 |
degree[u_node] = deg; //update degree
|
williamr@2
|
519 |
degreelists[deg].push(u_node);
|
williamr@2
|
520 |
//u_id has been pushed back into degreelists
|
williamr@2
|
521 |
degree_lists_marker.unmark(u_node);
|
williamr@2
|
522 |
if (min_degree > deg)
|
williamr@2
|
523 |
min_degree = deg;
|
williamr@2
|
524 |
q2list.pop();
|
williamr@2
|
525 |
} // while (!q2list.empty())
|
williamr@2
|
526 |
|
williamr@2
|
527 |
while (!qxlist.empty()) {
|
williamr@2
|
528 |
const size_type u_id = qxlist.top();
|
williamr@2
|
529 |
const vertex_t u_node = get(index_vertex_map, u_id);
|
williamr@2
|
530 |
|
williamr@2
|
531 |
// if u_id is outmatched by others, no need to update degree
|
williamr@2
|
532 |
if (degree_lists_marker.outmatched_or_done(u_node)) {
|
williamr@2
|
533 |
qxlist.pop();
|
williamr@2
|
534 |
continue;
|
williamr@2
|
535 |
}
|
williamr@2
|
536 |
marker.increment_tag();
|
williamr@2
|
537 |
deg = deg0;
|
williamr@2
|
538 |
adj_iter i, ie;
|
williamr@2
|
539 |
for (tie(i, ie) = adjacent_vertices(u_node, G); i != ie; ++i) {
|
williamr@2
|
540 |
vertex_t i_node = *i;
|
williamr@2
|
541 |
if (marker.is_tagged(i_node))
|
williamr@2
|
542 |
continue;
|
williamr@2
|
543 |
marker.mark_tagged(i_node);
|
williamr@2
|
544 |
|
williamr@2
|
545 |
if (numbering.is_numbered(i_node)) {
|
williamr@2
|
546 |
adj_iter j, je;
|
williamr@2
|
547 |
for (tie(j, je) = adjacent_vertices(i_node, G); j != je; ++j) {
|
williamr@2
|
548 |
const vertex_t j_node = *j;
|
williamr@2
|
549 |
if (marker.is_not_tagged(j_node)) {
|
williamr@2
|
550 |
marker.mark_tagged(j_node);
|
williamr@2
|
551 |
deg += supernode_size[j_node];
|
williamr@2
|
552 |
}
|
williamr@2
|
553 |
}
|
williamr@2
|
554 |
} else
|
williamr@2
|
555 |
deg += supernode_size[i_node];
|
williamr@2
|
556 |
} // for adjacent vertices of u_node
|
williamr@2
|
557 |
deg -= supernode_size[u_node];
|
williamr@2
|
558 |
degree[u_node] = deg;
|
williamr@2
|
559 |
degreelists[deg].push(u_node);
|
williamr@2
|
560 |
// u_id has been pushed back into degreelists
|
williamr@2
|
561 |
degree_lists_marker.unmark(u_node);
|
williamr@2
|
562 |
if (min_degree > deg)
|
williamr@2
|
563 |
min_degree = deg;
|
williamr@2
|
564 |
qxlist.pop();
|
williamr@2
|
565 |
} // while (!qxlist.empty()) {
|
williamr@2
|
566 |
|
williamr@2
|
567 |
marker.set_tag_as_multiple_tag();
|
williamr@2
|
568 |
llist.pop();
|
williamr@2
|
569 |
} // while (! llist.empty())
|
williamr@2
|
570 |
|
williamr@2
|
571 |
} // update()
|
williamr@2
|
572 |
|
williamr@2
|
573 |
|
williamr@2
|
574 |
void build_permutation(InversePermutationMap next,
|
williamr@2
|
575 |
PermutationMap prev)
|
williamr@2
|
576 |
{
|
williamr@2
|
577 |
// collect the permutation info
|
williamr@2
|
578 |
size_type i;
|
williamr@2
|
579 |
for (i = 0; i < n; ++i) {
|
williamr@2
|
580 |
diff_t size = supernode_size[get(index_vertex_map, i)];
|
williamr@2
|
581 |
if ( size <= 0 ) {
|
williamr@2
|
582 |
prev[i] = next[i];
|
williamr@2
|
583 |
supernode_size[get(index_vertex_map, i)]
|
williamr@2
|
584 |
= next[i] + 1; // record the supernode info
|
williamr@2
|
585 |
} else
|
williamr@2
|
586 |
prev[i] = - next[i];
|
williamr@2
|
587 |
}
|
williamr@2
|
588 |
for (i = 1; i < n + 1; ++i) {
|
williamr@2
|
589 |
if ( prev[i-1] > 0 )
|
williamr@2
|
590 |
continue;
|
williamr@2
|
591 |
diff_t parent = i;
|
williamr@2
|
592 |
while ( prev[parent - 1] < 0 ) {
|
williamr@2
|
593 |
parent = - prev[parent - 1];
|
williamr@2
|
594 |
}
|
williamr@2
|
595 |
|
williamr@2
|
596 |
diff_t root = parent;
|
williamr@2
|
597 |
diff_t num = prev[root - 1] + 1;
|
williamr@2
|
598 |
next[i-1] = - num;
|
williamr@2
|
599 |
prev[root-1] = num;
|
williamr@2
|
600 |
|
williamr@2
|
601 |
parent = i;
|
williamr@2
|
602 |
diff_t next_node = - prev[parent - 1];
|
williamr@2
|
603 |
while (next_node > 0) {
|
williamr@2
|
604 |
prev[parent-1] = - root;
|
williamr@2
|
605 |
parent = next_node;
|
williamr@2
|
606 |
next_node = - prev[parent - 1];
|
williamr@2
|
607 |
}
|
williamr@2
|
608 |
}
|
williamr@2
|
609 |
for (i = 0; i < n; i++) {
|
williamr@2
|
610 |
diff_t num = - next[i] - 1;
|
williamr@2
|
611 |
next[i] = num;
|
williamr@2
|
612 |
prev[num] = i;
|
williamr@2
|
613 |
}
|
williamr@2
|
614 |
} // build_permutation()
|
williamr@2
|
615 |
};
|
williamr@2
|
616 |
|
williamr@2
|
617 |
} //namespace detail
|
williamr@2
|
618 |
|
williamr@2
|
619 |
|
williamr@2
|
620 |
// MMD algorithm
|
williamr@2
|
621 |
//
|
williamr@2
|
622 |
//The implementation presently includes the enhancements for mass
|
williamr@2
|
623 |
//elimination, incomplete degree update, multiple elimination, and
|
williamr@2
|
624 |
//external degree.
|
williamr@2
|
625 |
//
|
williamr@2
|
626 |
//Important Note: This implementation requires the BGL graph to be
|
williamr@2
|
627 |
//directed. Therefore, nonzero entry (i, j) in a symmetrical matrix
|
williamr@2
|
628 |
//A coresponds to two directed edges (i->j and j->i).
|
williamr@2
|
629 |
//
|
williamr@2
|
630 |
//see Alan George and Joseph W. H. Liu, The Evolution of the Minimum
|
williamr@2
|
631 |
//Degree Ordering Algorithm, SIAM Review, 31, 1989, Page 1-19
|
williamr@2
|
632 |
template<class Graph, class DegreeMap,
|
williamr@2
|
633 |
class InversePermutationMap,
|
williamr@2
|
634 |
class PermutationMap,
|
williamr@2
|
635 |
class SuperNodeMap, class VertexIndexMap>
|
williamr@2
|
636 |
void minimum_degree_ordering
|
williamr@2
|
637 |
(Graph& G,
|
williamr@2
|
638 |
DegreeMap degree,
|
williamr@2
|
639 |
InversePermutationMap inverse_perm,
|
williamr@2
|
640 |
PermutationMap perm,
|
williamr@2
|
641 |
SuperNodeMap supernode_size,
|
williamr@2
|
642 |
int delta,
|
williamr@2
|
643 |
VertexIndexMap vertex_index_map)
|
williamr@2
|
644 |
{
|
williamr@2
|
645 |
detail::mmd_impl<Graph,DegreeMap,InversePermutationMap,
|
williamr@2
|
646 |
PermutationMap, SuperNodeMap, VertexIndexMap>
|
williamr@2
|
647 |
impl(G, num_vertices(G), delta, degree, inverse_perm,
|
williamr@2
|
648 |
perm, supernode_size, vertex_index_map);
|
williamr@2
|
649 |
impl.do_mmd();
|
williamr@2
|
650 |
impl.build_permutation(inverse_perm, perm);
|
williamr@2
|
651 |
}
|
williamr@2
|
652 |
|
williamr@2
|
653 |
} // namespace boost
|
williamr@2
|
654 |
|
williamr@2
|
655 |
#endif // MINIMUM_DEGREE_ORDERING_HPP
|