lemon/steiner.h
author ladanyi
Sun, 02 Mar 2008 22:55:27 +0000
changeset 2592 f1fb0c31f952
parent 2510 bb523a4758f7
permissions -rw-r--r--
Revert to long long int since currently I don't know a better solution.
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2008
     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     Value _value;
   130 
   131   public:
   132 
   133     /// \brief Constructor
   134     
   135     /// Constructor
   136     ///
   137     SteinerTree(const UGraph &graph, const CostMap &cost)
   138       : _graph(graph), _cost(cost), _dijkstra(graph, _cost), 
   139         _pred(0), _comp(0), _forked(0), _filter(0), _tree(0) {}
   140 
   141     /// \brief Initializes the internal data structures.
   142     ///
   143     /// Initializes the internal data structures.
   144     void init() {
   145       if (!_pred) _pred = new PredMap(_graph);
   146       if (!_comp) _comp = new CompMap(_graph);
   147       if (!_forked) _forked = new ForkedMap(*_pred, *_comp);
   148       if (!_filter) _filter = new FilterMap(_graph);
   149       if (!_tree) _tree = new TreeMap(_graph);
   150       _dijkstra.predMap(*_forked);
   151       _dijkstra.init();
   152       _terminal_num = 0;
   153       for (NodeIt it(_graph); it != INVALID; ++it) {
   154         _filter->set(it, false);
   155       }
   156     }
   157 
   158     /// \brief Adds a new terminal node.
   159     ///
   160     /// Adds a new terminal node to the Steiner-tree problem.
   161     void addTerminal(const Node& node) {
   162       if (!_dijkstra.reached(node)) {
   163         _dijkstra.addSource(node);
   164         _comp->comp(node, _terminal_num);
   165         ++_terminal_num;
   166       }
   167     }
   168     
   169     /// \brief Executes the algorithm.
   170     ///
   171     /// Executes the algorithm.
   172     ///
   173     /// \pre init() must be called and at least some nodes should be
   174     /// added with addTerminal() before using this function.
   175     ///
   176     /// This method constructs an approximation of the Steiner-Tree.
   177     void start() {
   178       _dijkstra.start();
   179       
   180       std::vector<External> externals;
   181       for (UEdgeIt it(_graph); it != INVALID; ++it) {
   182         Node s = _graph.source(it);
   183         Node t = _graph.target(it);
   184         if (_comp->comp(s) == _comp->comp(t)) continue;
   185 
   186         Value cost = _dijkstra.dist(s) + _dijkstra.dist(t) + _cost[it];
   187 
   188         if (_comp->comp(s) < _comp->comp(t)) {
   189           externals.push_back(External(_comp->comp(s), _comp->comp(t), 
   190                                        it, cost));
   191         } else {
   192           externals.push_back(External(_comp->comp(t), _comp->comp(s), 
   193                                        it, cost));
   194         }
   195       }
   196       std::sort(externals.begin(), externals.end(), ExternalLess());
   197 
   198       SmartUGraph aux_graph;
   199       std::vector<SmartUGraph::Node> aux_nodes;
   200 
   201       for (int i = 0; i < _terminal_num; ++i) {
   202         aux_nodes.push_back(aux_graph.addNode());
   203       }
   204 
   205       SmartUGraph::UEdgeMap<Value> aux_cost(aux_graph);
   206       SmartUGraph::UEdgeMap<UEdge> cross(aux_graph);
   207       {
   208         int i = 0;
   209         while (i < int(externals.size())) {
   210           int sn = externals[i].source;
   211           int tn = externals[i].target;
   212           Value ev = externals[i].value;
   213           UEdge ee = externals[i].uedge;
   214           ++i;
   215           while (i < int(externals.size()) && 
   216                  sn == externals[i].source && tn == externals[i].target) {
   217             if (externals[i].value < ev) {
   218               ev = externals[i].value;
   219               ee = externals[i].uedge;
   220             }
   221             ++i;
   222           }
   223           SmartUGraph::UEdge ne = 
   224             aux_graph.addEdge(aux_nodes[sn], aux_nodes[tn]);
   225           aux_cost.set(ne, ev);
   226           cross.set(ne, ee);
   227         }
   228       }
   229 
   230       std::vector<SmartUGraph::UEdge> aux_tree_edges;
   231       BackInserterBoolMap<std::vector<SmartUGraph::UEdge> >
   232         aux_tree_map(aux_tree_edges);
   233       prim(aux_graph, aux_cost, aux_tree_map);
   234 
   235       for (std::vector<SmartUGraph::UEdge>::iterator 
   236              it = aux_tree_edges.begin(); it != aux_tree_edges.end(); ++it) {
   237         Node node;
   238         node = _graph.source(cross[*it]);
   239         while (node != INVALID && !(*_filter)[node]) {
   240           _filter->set(node, true);
   241           node = (*_pred)[node] != INVALID ? 
   242             _graph.source((*_pred)[node]) : INVALID;
   243         }
   244         node = _graph.target(cross[*it]);
   245         while (node != INVALID && !(*_filter)[node]) {
   246           _filter->set(node, true);
   247           node = (*_pred)[node] != INVALID ? 
   248             _graph.source((*_pred)[node]) : INVALID;
   249         }
   250       }
   251 
   252       _value = prim(nodeSubUGraphAdaptor(_graph, *_filter), _cost, *_tree);
   253             
   254     }
   255 
   256     /// \brief Checks if an edge is in the Steiner-tree or not.
   257     ///
   258     /// Checks if an edge is in the Steiner-tree or not.
   259     /// \param e is the edge that will be checked
   260     /// \return \c true if e is in the Steiner-tree, \c false otherwise
   261     bool tree(UEdge e){
   262       return (*_tree)[e];
   263     }
   264 
   265     /// \brief Checks if the node is in the Steiner-tree or not.
   266     ///
   267     /// Checks if a node is in the Steiner-tree or not.
   268     /// \param n is the node that will be checked
   269     /// \return \c true if n is in the Steiner-tree, \c false otherwise
   270     bool tree(Node n){
   271       return (*_filter)[n];
   272     }
   273 
   274     /// \brief Checks if the node is a Steiner-node.
   275     ///
   276     /// Checks if the node is a Steiner-node (i.e. a tree node but
   277     /// not terminal).
   278     /// \param n is the node that will be checked
   279     /// \return \c true if n is a Steiner-node, \c false otherwise
   280     bool steiner(Node n){
   281       return (*_filter)[n] && (*_pred)[n] != INVALID;
   282     }
   283 
   284     /// \brief Checks if the node is a terminal.
   285     ///
   286     /// Checks if the node is a terminal.
   287     /// \param n is the node that will be checked
   288     /// \return \c true if n is a terminal, \c false otherwise
   289     bool terminal(Node n){
   290       return _dijkstra.reached(n) && (*_pred)[n] == INVALID;
   291     }
   292     
   293     /// \brief The total cost of the tree
   294     ///
   295     /// The total cost of the constructed tree. The calculated value does
   296     /// not exceed the double of the optimal value.
   297     Value treeValue() const {
   298       return _value;
   299     }
   300     
   301   };
   302 
   303 } //END OF NAMESPACE LEMON
   304 
   305 #endif