All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Pages
steiner_tree_greedy.hpp
Go to the documentation of this file.
1 //=======================================================================
2 // Copyright (c) 2014 Piotr Smulewicz
3 // 2013 Piotr Wygocki
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //=======================================================================
16 #ifndef PAAL_STEINER_TREE_GREEDY_HPP
17 #define PAAL_STEINER_TREE_GREEDY_HPP
18 
20 #include "paal/utils/functors.hpp"
21 
22 #include <boost/graph/adjacency_list.hpp>
23 #include <boost/graph/dijkstra_shortest_paths.hpp>
24 #include <boost/graph/graph_concepts.hpp>
25 #include <boost/graph/graph_traits.hpp>
26 #include <boost/graph/kruskal_min_spanning_tree.hpp>
27 #include <boost/graph/named_function_params.hpp>
28 #include <boost/graph/properties.hpp>
29 #include <boost/graph/two_bit_color_map.hpp>
30 
31 #include <boost/property_map/property_map.hpp>
32 
33 #include <boost/range/algorithm/copy.hpp>
34 #include <boost/range/algorithm/fill.hpp>
35 #include <boost/range/algorithm/sort.hpp>
36 #include <boost/range/algorithm/unique.hpp>
37 #include <boost/range/as_array.hpp>
38 #include <boost/range/numeric.hpp>
39 
40 #include <algorithm>
41 #include <utility>
42 
44 enum edge_base_t { edge_base };
45 
46 namespace boost {
48 BOOST_INSTALL_PROPERTY(edge, base);
49 }
50 
51 namespace paal {
52 
56 enum Terminals { NONTERMINAL, TERMINAL };
57 
58 namespace detail {
59 template <typename NearestMap, typename LastEdgeMap, typename Tag>
61  : boost::base_visitor<nearest_recorder<NearestMap, LastEdgeMap, Tag>> {
62  public:
63  using event_filter = Tag;
64  nearest_recorder(NearestMap &nearest_map, LastEdgeMap &vpred)
65  : m_nearest_map(nearest_map), m_vpred(vpred) {};
66  template <typename Edge, typename Graph>
67  void operator()(Edge const e, Graph const &g) {
68  m_nearest_map[target(e, g)] = m_nearest_map[source(e, g)];
69  m_vpred[target(e, g)] = e;
70  }
71 
72  private:
73  NearestMap &m_nearest_map;
74  LastEdgeMap &m_vpred;
75 };
76 
77 template <typename NearestMap, typename LastEdgeMap, typename Tag>
79 make_nearest_recorder(NearestMap &nearest_map, LastEdgeMap &vpred, Tag) {
80  return nearest_recorder<NearestMap, LastEdgeMap, Tag>{ nearest_map, vpred };
81 }
82 }
95 template <typename Graph, typename OutputIterator, typename EdgeWeightMap,
96  typename ColorMap>
97 auto steiner_tree_greedy(const Graph &g, OutputIterator out,
98  EdgeWeightMap edge_weight, ColorMap color_map)
99  -> typename std::pair<
100  typename boost::property_traits<EdgeWeightMap>::value_type,
101  typename boost::property_traits<EdgeWeightMap>::value_type> {
102  using Vertex = typename boost::graph_traits<Graph>::vertex_descriptor;
103  using Edge = typename boost::graph_traits<Graph>::edge_descriptor;
104  using Base = typename boost::property<edge_base_t, Edge>;
105  using Weight = typename boost::property_traits<EdgeWeightMap>::value_type;
106  using WeightProperty =
107  typename boost::property<boost::edge_weight_t, Weight, Base>;
108  using TerminalGraph =
109  boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
110  boost::no_property, WeightProperty>;
111  using EdgeTerminal =
112  typename boost::graph_traits<TerminalGraph>::edge_descriptor;
113 
114  auto N = num_vertices(g);
115 
116  // distance array used in the dijkstra runs
117  std::vector<Weight> distance(N);
118 
119  // computing terminals
120  std::vector<int> terminals;
121  auto terminals_nr = accumulate_functor(
122  vertices(g), 0, [=](Vertex v) { return get(color_map, v); });
123  terminals.reserve(terminals_nr);
124  for (auto v : boost::as_array(vertices(g))) {
125  if (get(color_map, v) == Terminals::TERMINAL) {
126  terminals.push_back(v);
127  }
128  }
129  if (terminals.empty()) {
130  return std::make_pair(Weight{}, Weight{});
131  }
132  std::vector<Vertex> nearest_terminal(num_vertices(g));
133  auto index = get(boost::vertex_index, g);
134  auto nearest_terminal_map = boost::make_iterator_property_map(
135  nearest_terminal.begin(), get(boost::vertex_index, g));
136  for (auto terminal : terminals) {
137  nearest_terminal_map[terminal] = terminal;
138  }
139 
140  // compute voronoi diagram each vertex get nearest terminal and last edge on
141  // path to nearest terminal
142  auto distance_map = make_iterator_property_map(distance.begin(), index);
143  std::vector<Edge> vpred(N);
144  auto last_edge = boost::make_iterator_property_map(
145  vpred.begin(), get(boost::vertex_index, g));
146  boost::dijkstra_shortest_paths(
147  g, terminals.begin(), terminals.end(), boost::dummy_property_map(),
148  distance_map, edge_weight, index, utils::less(),
149  boost::closed_plus<Weight>(), std::numeric_limits<Weight>::max(), 0,
150  boost::make_dijkstra_visitor(detail::make_nearest_recorder(
151  nearest_terminal_map, last_edge, boost::on_edge_relaxed{})));
152 
153  // computing distances between terminals
154  // creating terminal_graph
155  TerminalGraph terminal_graph(N);
156  for (auto w : boost::as_array(edges(g))) {
157  auto const &nearest_to_source = nearest_terminal_map[source(w, g)];
158  auto const &nearest_to_target = nearest_terminal_map[target(w, g)];
159  if (nearest_to_source != nearest_to_target) {
160  add_edge(nearest_to_source, nearest_to_target,
161  WeightProperty(distance[source(w, g)] +
162  distance[target(w, g)] + edge_weight[w],
163  Base(w)),
164  terminal_graph);
165  }
166  }
167  // computing spanning tree on terminal_graph
168  std::vector<Edge> terminal_edge;
169  boost::kruskal_minimum_spanning_tree(terminal_graph,
170  std::back_inserter(terminal_edge));
171 
172  // computing result
173  std::vector<Edge> tree_edges;
174  tree_edges.reserve(terminals_nr);
175  for (auto edge : terminal_edge) {
176  auto base = get(edge_base, terminal_graph, edge);
177  tree_edges.push_back(base);
178  for (auto pom : { source(base, g), target(base, g) }) {
179  while (nearest_terminal_map[pom] != pom) {
180  tree_edges.push_back(vpred[pom]);
181  pom = source(vpred[pom], g);
182  }
183  }
184  }
185 
186  // because in each voronoi region we have unique patch to all vertex from
187  // terminal, result graph contain no cycle
188  // and all leaf are terminal
189 
190  boost::sort(tree_edges);
191  auto get_weight=[&](Edge edge){return edge_weight[edge];};
192  auto lower_bound=accumulate_functor(tree_edges, Weight{}, get_weight);
193  auto unique_edges = boost::unique(tree_edges);
194  auto cost_solution=accumulate_functor(unique_edges, Weight{}, get_weight);
195  boost::copy(unique_edges, out);
196  return std::make_pair(cost_solution, lower_bound / 2.);
197 }
198 
211 template <typename Graph, typename OutputIterator, typename P, typename T,
212  typename R>
213 auto steiner_tree_greedy(const Graph &g, OutputIterator out,
214  const boost::bgl_named_params<P, T, R> &params) {
215  return steiner_tree_greedy(
216  g, out, choose_const_pmap(get_param(params, boost::edge_weight), g,
217  boost::edge_weight),
218  choose_const_pmap(get_param(params, boost::vertex_color), g,
219  boost::vertex_color));
220 }
221 
230 template <typename Graph, typename OutputIterator>
231 auto steiner_tree_greedy(const Graph &g, OutputIterator out) {
232  return steiner_tree_greedy(g, out, boost::no_named_parameters());
233 }
234 
235 } // paal
236 
237 #endif // PAAL_STEINER_TREE_GREEDY_HPP
less functor
Definition: functors.hpp:497
auto steiner_tree_greedy(const Graph &g, OutputIterator out, EdgeWeightMap edge_weight, ColorMap color_map) -> typename std::pair< typename boost::property_traits< EdgeWeightMap >::value_type, typename boost::property_traits< EdgeWeightMap >::value_type >
non-named version of steiner_tree_greedy
This file contains set of simple useful functors or functor adapters.
T accumulate_functor(const Range &rng, T init, Functor f, BinaryOperation bin_op=BinaryOperation{})
combination of boost::accumulate and boost::adaptors::transformed
Terminals
enum indicates if given color represents terminal or NONTERMINAL.
edge_base_t
enum for edge base property