All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Pages
multiway_cut.hpp
Go to the documentation of this file.
1 //=======================================================================
2 // Copyright (c) 2013 Piotr Smulewicz
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //=======================================================================
16 #ifndef PAAL_MULTIWAY_CUT_HPP
17 #define PAAL_MULTIWAY_CUT_HPP
18 
19 #include "paal/lp/glp.hpp"
21 #include "paal/utils/irange.hpp"
23 
24 #include <boost/bimap.hpp>
25 #include <boost/graph/breadth_first_search.hpp>
26 #include <boost/graph/connected_components.hpp>
27 #include <boost/graph/filtered_graph.hpp>
28 #include <boost/graph/graph_traits.hpp>
29 #include <boost/graph/graph_utility.hpp>
30 #include <boost/graph/named_function_params.hpp>
31 #include <boost/graph/stoer_wagner_min_cut.hpp>
32 #include <boost/property_map/property_map.hpp>
33 #include <boost/range/as_array.hpp>
34 
35 #include <fstream>
36 #include <tuple>
37 #include <utility>
38 #include <vector>
39 #include <random>
40 
41 
42 namespace paal {
43 namespace detail {
44 
45 inline int vertices_column_index(int vertex, int dimentions, int column) {
46  return vertex * dimentions + column;
47 }
48 
49 template <class Graph>
50 using CostType = typename boost::property_traits<
51  puretype(get(boost::edge_weight, std::declval<Graph>()))>::value_type;
52 
53 template <typename LP> class multiway_cut_lp {
54  public:
56  template <typename Graph, typename IndexMap, typename WeightMap,
57  typename ColorMap>
58  void init(const Graph &graph, int k, const IndexMap &index_map,
59  const WeightMap &weight_map, const ColorMap &color_map) {
60 
61  m_lp.set_lp_name("Multiway Cut");
62  m_lp.set_optimization_type(lp::MINIMIZE);
63 
64  add_variables(graph, k, weight_map);
65  add_constraints(graph, k, index_map, color_map);
66  }
67 
68  private:
69  // adding variables
70  // returns the number of variables
71  template <typename Graph, typename WeightMap>
72  void add_variables(const Graph &graph, int k, const WeightMap &weight_map) {
73  for (auto e : boost::as_array(edges(graph))) {
74  for (int i = 0; i < k; ++i) {
75  auto col_idx = m_lp.add_column(get(weight_map, e));
76  edges_column.push_back(col_idx);
77  }
78  }
79  for (unsigned vertex = 0; vertex <= num_vertices(graph); ++vertex) {
80  for (int i = 0; i < k; ++i) {
81  auto col_idx = m_lp.add_column(0);
82  vertices_column.push_back(col_idx);
83  }
84  }
85  }
86 
87  template <typename Graph, typename IndexMap, typename ColorMap>
88  void add_constraints(const Graph &graph, int k, const IndexMap &index_map,
89  const ColorMap &color_map) {
90  int db_index = 0;
91  for (auto edge : boost::as_array(edges(graph))) {
92  auto sour = get(index_map, source(edge, graph));
93  auto targ = get(index_map, target(edge, graph));
94  for (auto i : irange(k)) {
95  for (auto j : irange(2)) {
96  auto x_e =
97  edges_column[vertices_column_index(db_index, k, i)];
98  auto x_src =
99  vertices_column[vertices_column_index(sour, k, i)];
100  auto x_trg =
101  vertices_column[vertices_column_index(targ, k, i)];
102  m_lp.add_row(
103  x_e + (j * 2 - 1) * x_src + (1 - 2 * j) * x_trg >= 0);
104  }
105  }
106  ++db_index;
107  }
108  db_index = 0;
109  for (auto vertex : boost::as_array(vertices(graph))) {
110  auto col = get(color_map, vertex);
111  if (col != 0) {
112  auto x_col = vertices_column[
113  vertices_column_index(db_index, k, col - 1)];
114  m_lp.add_row(x_col == 1);
115  }
116  lp::linear_expression expr;
117  for (auto i : irange(k)) {
118  expr += vertices_column[vertices_column_index(db_index, k, i)];
119  }
120  m_lp.add_row(std::move(expr) == 1);
121  ++db_index;
122  }
123  }
124 
125  public:
126  LP m_lp;
127  std::vector<lp::col_id> edges_column;
128  std::vector<lp::col_id> vertices_column;
129 };
130 
131 
132 template <typename Graph, typename VertexIndexMap, typename EdgeWeightMap,
133  typename Dist, typename Rand, typename LP>
134 auto make_cut(const Graph &graph, int k, const VertexIndexMap &index_map,
135  const EdgeWeightMap &weight_map, Dist &dist, Rand &&random_engine,
136  multiway_cut_lp<LP> &mc_lp, std::vector<int> &vertex_to_part)
137  ->detail::CostType<Graph> {
138  double cut_cost = 0;
139  std::vector<double> random_radiuses;
140  dist.reset();
141  for (int i = 0; i < k; ++i) {
142  random_radiuses.push_back(dist(random_engine));
143  }
144  vertex_to_part.resize(num_vertices(graph));
145  auto get_column = [&](int vertex, int dimension) {
146  return mc_lp.m_lp.get_col_value(
147  mc_lp.vertices_column[vertices_column_index(vertex, k, dimension)]);
148  };
149 
150  for (auto vertex : boost::as_array(vertices(graph))) {
151  for (int dimension = 0; dimension < k; ++dimension)
152  if (1.0 - get_column(get(index_map, vertex), dimension) <
153  random_radiuses[dimension] ||
154  dimension == k - 1) {
155  // because each vertex have sum of coordinates equal 1,
156  // 1.0-get_column(vertex,dimension) is proportional to distance
157  // to vertex correspond to dimension
158  vertex_to_part[get(index_map, vertex)] = dimension;
159  break;
160  }
161  }
162  for (auto edge : boost::as_array(edges(graph))) {
163  if (vertex_to_part[get(index_map, source(edge, graph))] !=
164  vertex_to_part[get(index_map, target(edge, graph))])
165  cut_cost += get(weight_map, edge);
166  }
167  return cut_cost;
168 }
169 
170 
171 template <typename Rand = std::default_random_engine,
172  typename Distribution = std::uniform_real_distribution<double>,
173  typename LP = lp::glp, typename Graph, typename OutputIterator,
174  typename VertexIndexMap, typename EdgeWeightMap,
175  typename VertexColorMap>
176 auto multiway_cut_dispatch(const Graph &graph, OutputIterator result,
177  Rand &&random_engine, int iterations,
178  VertexIndexMap index_map, EdgeWeightMap weight_map,
179  VertexColorMap color_map)
180  ->typename boost::property_traits<EdgeWeightMap>::value_type {
181  using CostType = detail::CostType<Graph>;
182  Distribution dis(0, 1);
183  int terminals = 0;
184  for (auto vertex : boost::as_array(vertices(graph))) {
185  assign_max(terminals, get(color_map, vertex));
186  }
187  detail::multiway_cut_lp<LP> multiway_cut_lp;
188  multiway_cut_lp.init(graph, terminals, index_map, weight_map, color_map);
189  multiway_cut_lp.m_lp.solve_simplex(lp::DUAL);
190  CostType cut_cost = std::numeric_limits<CostType>::max();
191  std::vector<int> best_solution;
192  std::vector<int> solution;
193  for (int i = 0; i < iterations; ++i) {
194  solution.clear();
195  int res = detail::make_cut(graph, terminals, index_map, weight_map, dis,
196  random_engine, multiway_cut_lp, solution);
197  if (res < cut_cost) {
198  swap(solution, best_solution);
199  cut_cost = res;
200  }
201  }
202  for (auto v : boost::as_array(vertices(graph))) {
203  *result = std::make_pair(v, best_solution[get(index_map, v)]);
204  ++result;
205  }
206  return cut_cost;
207 }
208 
209 template <typename Rand = std::default_random_engine,
210  typename Distribution = std::uniform_real_distribution<double>,
211  typename LP = lp::glp, typename Graph, typename OutputIterator,
212  typename VertexIndexMap, typename EdgeWeightMap,
213  typename VertexColorMap>
214 auto multiway_cut_dispatch(const Graph &graph, OutputIterator result,
215  Rand &&random_engine, boost::param_not_found,
216  VertexIndexMap index_map, EdgeWeightMap weight_map,
217  VertexColorMap color_map)
218  ->typename boost::property_traits<EdgeWeightMap>::value_type {
219  int vertices = num_vertices(graph);
220  const static int MIN_NUMBER_OF_REPEATS = 100;
221  auto number_of_repeats =
222  vertices * vertices +
223  MIN_NUMBER_OF_REPEATS; // This variable is not supported by any proof
224  return multiway_cut_dispatch(graph, result, random_engine,
225  number_of_repeats, index_map, weight_map,
226  color_map);
227 }
228 
229 }
230 
250 template <typename Rand = std::default_random_engine,
251  typename Distribution = std::uniform_real_distribution<double>,
252  typename LP = lp::glp, typename Graph, typename OutputIterator,
253  typename P, typename T, typename R>
254 auto multiway_cut(const Graph &g, OutputIterator out,
255  const boost::bgl_named_params<P, T, R> &params,
256  Rand &&random_engine = std::default_random_engine(5426u))
257  ->typename boost::property_traits<puretype(
258  boost::choose_const_pmap(get_param(params, boost::edge_weight), g,
259  boost::edge_weight))>::value_type {
260  return detail::multiway_cut_dispatch(
261  g, out, random_engine, get_param(params, boost::iterations_t()),
262  boost::choose_const_pmap(get_param(params, boost::vertex_index), g,
263  boost::vertex_index),
264  boost::choose_const_pmap(get_param(params, boost::edge_weight), g,
265  boost::edge_weight),
266  boost::choose_const_pmap(get_param(params, boost::vertex_color), g,
267  boost::vertex_color));
268 }
269 
287 template <typename Rand = std::default_random_engine,
288  typename Distribution = std::uniform_real_distribution<double>,
289  typename LP = lp::glp, typename Graph, class OutputIterator>
290 auto multiway_cut(const Graph &graph, OutputIterator result,
291  Rand random_engine = std::default_random_engine(5426u))
292  ->detail::CostType<Graph> {
293  return multiway_cut(graph, result, boost::no_named_parameters(),
294  random_engine);
295 }
296 
297 }
298 #endif // PAAL_MULTIWAY_CUT_HPP
The common LP solvers base class. Responsible for:
Definition: lp_base.hpp:55
col_id add_column(double cost_coef=0, double lb=0., double ub=lp_traits::PLUS_INF, const std::string &name="")
Definition: lp_base.hpp:92
void set_lp_name(const std::string problem_name)
Definition: lp_base.hpp:78
#define puretype(t)
for given expression returns its type with removed const and reference
auto irange(T begin, T end)
irange
Definition: irange.hpp:22
void assign_max(T &t, const T &u)
void init(const Graph &graph, int k, const IndexMap &index_map, const WeightMap &weight_map, const ColorMap &color_map)
Initialize the cut LP.
auto multiway_cut(const Graph &g, OutputIterator out, const boost::bgl_named_params< P, T, R > &params, Rand &&random_engine=std::default_random_engine(5426u)) -> typename boost::property_traits< puretype(boost::choose_const_pmap(get_param(params, boost::edge_weight), g, boost::edge_weight))>::value_type
detail
row_id add_row(const double_bounded_expression &constraint=double_bounded_expression{}, const std::string &name="")
Definition: lp_base.hpp:109