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