lemon/steiner.h
author alpar
Sat, 03 Mar 2007 16:30:37 +0000
changeset 2391 14a343be7a5a
parent 2386 81b47fc5c444
child 2399 ccf2a1fa1821
permissions -rw-r--r--
Happy New Year to all source files!
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2007
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #ifndef LEMON_STEINER_H
    20 #define LEMON_STEINER_H
    21 
    22 ///\ingroup approx
    23 ///\file
    24 ///\brief Algorithm for the 2-approximation of Steiner Tree problem.
    25 ///
    26 
    27 #include <lemon/smart_graph.h>
    28 #include <lemon/graph_utils.h>
    29 #include <lemon/error.h>
    30 
    31 #include <lemon/ugraph_adaptor.h>
    32 #include <lemon/maps.h>
    33 
    34 #include <lemon/dijkstra.h>
    35 #include <lemon/prim.h>
    36 
    37 
    38 namespace lemon {
    39 
    40   /// \ingroup approx
    41   
    42   /// \brief Algorithm for the 2-approximation of Steiner Tree problem
    43   ///
    44   /// The Steiner-tree problem is the next: Given a connected
    45   /// undirected graph, a cost function on the edges and a subset of
    46   /// the nodes. Construct a tree with minimum cost which covers the
    47   /// given subset of the nodes. The problem is NP-hard moreover
    48   /// it is APX-complete too.
    49   ///
    50   /// Mehlhorn's approximation algorithm is implemented in this class,
    51   /// which gives a 2-approximation for the Steiner-tree problem. The
    52   /// algorithm's time complexity is O(nlog(n)+e).
    53   template <typename UGraph,
    54             typename CostMap = typename UGraph:: template UEdgeMap<double> >
    55   class SteinerTree {
    56   public:
    57     
    58     UGRAPH_TYPEDEFS(typename UGraph)
    59 
    60     typedef typename CostMap::Value Value;
    61     
    62   private:
    63 
    64     class CompMap {
    65     public:
    66       typedef Node Key;
    67       typedef Edge Value;
    68 
    69     private:
    70       const UGraph& _graph;
    71       typename UGraph::template NodeMap<int> _comp;
    72 
    73     public:
    74       CompMap(const UGraph& graph) : _graph(graph), _comp(graph) {}
    75 
    76       void set(const Node& node, const Edge& edge) {
    77         if (edge != INVALID) {
    78           _comp.set(node, _comp[_graph.source(edge)]);
    79         } else {
    80           _comp.set(node, -1);
    81         }
    82       }
    83 
    84       int comp(const Node& node) const { return _comp[node]; }
    85       void comp(const Node& node, int value) { _comp.set(node, value); }
    86     };
    87 
    88     typedef typename UGraph::template NodeMap<Edge> PredMap;
    89 
    90     typedef ForkWriteMap<PredMap, CompMap> ForkedMap;
    91 
    92 
    93     struct External {
    94       int source, target;
    95       UEdge uedge;
    96       Value value;
    97 
    98       External(int s, int t, const UEdge& e, const Value& v)
    99         : source(s), target(t), uedge(e), value(v) {}
   100     };
   101 
   102     struct ExternalLess {
   103       bool operator()(const External& left, const External& right) const {
   104         return (left.source < right.source) || 
   105           (left.source == right.source && left.target < right.target);
   106       }
   107     };
   108 
   109 
   110     typedef typename UGraph::template NodeMap<bool> FilterMap;
   111 
   112     typedef typename UGraph::template UEdgeMap<bool> TreeMap;
   113 
   114     const UGraph& _graph;
   115     const CostMap& _cost;
   116 
   117     typename Dijkstra<UGraph, CostMap>::
   118     template DefPredMap<ForkedMap>::Create _dijkstra;
   119 
   120     PredMap* _pred;
   121     CompMap* _comp;
   122     ForkedMap* _forked;
   123 
   124     int _terminal_num;
   125 
   126     FilterMap *_filter;
   127     TreeMap *_tree;
   128 
   129   public:
   130 
   131     /// \brief Constructor
   132     
   133     /// Constructor
   134     ///
   135     SteinerTree(const UGraph &graph, const CostMap &cost)
   136       : _graph(graph), _cost(cost), _dijkstra(graph, _cost), 
   137         _pred(0), _comp(0), _forked(0), _filter(0), _tree(0) {}
   138 
   139     /// \brief Initializes the internal data structures.
   140     ///
   141     /// Initializes the internal data structures.
   142     void init() {
   143       if (!_pred) _pred = new PredMap(_graph);
   144       if (!_comp) _comp = new CompMap(_graph);
   145       if (!_forked) _forked = new ForkedMap(*_pred, *_comp);
   146       if (!_filter) _filter = new FilterMap(_graph);
   147       if (!_tree) _tree = new TreeMap(_graph);
   148       _dijkstra.predMap(*_forked);
   149       _dijkstra.init();
   150       _terminal_num = 0;
   151       for (NodeIt it(_graph); it != INVALID; ++it) {
   152         _filter->set(it, false);
   153       }
   154     }
   155 
   156     /// \brief Adds a new terminal node.
   157     ///
   158     /// Adds a new terminal node to the Steiner-tree problem.
   159     void addTerminal(const Node& node) {
   160       if (!_dijkstra.reached(node)) {
   161         _dijkstra.addSource(node);
   162         _comp->comp(node, _terminal_num);
   163         ++_terminal_num;
   164       }
   165     }
   166     
   167     /// \brief Executes the algorithm.
   168     ///
   169     /// Executes the algorithm.
   170     ///
   171     /// \pre init() must be called and at least some nodes should be
   172     /// added with addTerminal() before using this function.
   173     ///
   174     /// This method constructs an approximation of the Steiner-Tree.
   175     void start() {
   176       _dijkstra.start();
   177       
   178       std::vector<External> externals;
   179       for (UEdgeIt it(_graph); it != INVALID; ++it) {
   180         Node s = _graph.source(it);
   181         Node t = _graph.target(it);
   182         if (_comp->comp(s) == _comp->comp(t)) continue;
   183 
   184         Value cost = _dijkstra.dist(s) + _dijkstra.dist(t) + _cost[it];
   185 
   186         if (_comp->comp(s) < _comp->comp(t)) {
   187           externals.push_back(External(_comp->comp(s), _comp->comp(t), 
   188                                        it, cost));
   189         } else {
   190           externals.push_back(External(_comp->comp(t), _comp->comp(s), 
   191                                        it, cost));
   192         }
   193       }
   194       std::sort(externals.begin(), externals.end(), ExternalLess());
   195 
   196       SmartUGraph aux_graph;
   197       std::vector<SmartUGraph::Node> aux_nodes;
   198 
   199       for (int i = 0; i < _terminal_num; ++i) {
   200         aux_nodes.push_back(aux_graph.addNode());
   201       }
   202 
   203       SmartUGraph::UEdgeMap<Value> aux_cost(aux_graph);
   204       SmartUGraph::UEdgeMap<UEdge> cross(aux_graph);
   205       {
   206         int i = 0;
   207         while (i < int(externals.size())) {
   208           int sn = externals[i].source;
   209           int tn = externals[i].target;
   210           Value ev = externals[i].value;
   211           UEdge ee = externals[i].uedge;
   212           ++i;
   213           while (i < int(externals.size()) && 
   214                  sn == externals[i].source && tn == externals[i].target) {
   215             if (externals[i].value < ev) {
   216               ev = externals[i].value;
   217               ee = externals[i].uedge;
   218             }
   219             ++i;
   220           }
   221           SmartUGraph::UEdge ne = 
   222             aux_graph.addEdge(aux_nodes[sn], aux_nodes[tn]);
   223           aux_cost.set(ne, ev);
   224           cross.set(ne, ee);
   225         }
   226       }
   227 
   228       std::vector<SmartUGraph::UEdge> aux_tree_edges;
   229       BackInserterBoolMap<std::vector<SmartUGraph::UEdge> >
   230         aux_tree_map(aux_tree_edges);
   231       prim(aux_graph, aux_cost, aux_tree_map);
   232 
   233       for (std::vector<SmartUGraph::UEdge>::iterator 
   234              it = aux_tree_edges.begin(); it != aux_tree_edges.end(); ++it) {
   235         Node node;
   236         node = _graph.source(cross[*it]);
   237         while (node != INVALID && !(*_filter)[node]) {
   238           _filter->set(node, true);
   239           node = (*_pred)[node] != INVALID ? 
   240             _graph.source((*_pred)[node]) : INVALID;
   241         }
   242         node = _graph.target(cross[*it]);
   243         while (node != INVALID && !(*_filter)[node]) {
   244           _filter->set(node, true);
   245           node = (*_pred)[node] != INVALID ? 
   246             _graph.source((*_pred)[node]) : INVALID;
   247         }
   248       }
   249 
   250       prim(nodeSubUGraphAdaptor(_graph, *_filter), _cost, *_tree);
   251             
   252     }
   253 
   254     /// \brief Checks if an edge is in the Steiner-tree or not.
   255     ///
   256     /// Checks if an edge is in the Steiner-tree or not.
   257     /// \param e is the edge that will be checked
   258     /// \return \c true if e is in the Steiner-tree, \c false otherwise
   259     bool tree(UEdge e){
   260       return (*_tree)[e];
   261     }
   262 
   263     /// \brief Checks if the node is in the Steiner-tree or not.
   264     ///
   265     /// Checks if a node is in the Steiner-tree or not.
   266     /// \param n is the node that will be checked
   267     /// \return \c true if n is in the Steiner-tree, \c false otherwise
   268     bool tree(Node n){
   269       return (*_filter)[n];
   270     }
   271     
   272 
   273   };
   274 
   275 } //END OF NAMESPACE LEMON
   276 
   277 #endif