epoc32/include/stdapis/boost/graph/minimum_degree_ordering.hpp
author William Roberts <williamr@symbian.org>
Wed, 31 Mar 2010 12:33:34 +0100
branchSymbian3
changeset 4 837f303aceeb
permissions -rw-r--r--
Current Symbian^3 public API header files (from PDK 3.0.h)
This is the epoc32/include tree with the "platform" subtrees removed, and
all but a selected few mbg and rsg files removed.
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