16 #ifndef PAAL_MULTIWAY_CUT_HPP
17 #define PAAL_MULTIWAY_CUT_HPP
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>
45 inline int vertices_column_index(
int vertex,
int dimentions,
int column) {
46 return vertex * dimentions + column;
49 template <
class Graph>
50 using CostType =
typename boost::property_traits<
51 puretype(
get(boost::edge_weight, std::declval<Graph>()))>::value_type;
56 template <
typename Graph,
typename IndexMap,
typename WeightMap,
58 void init(
const Graph &graph,
int k,
const IndexMap &index_map,
59 const WeightMap &weight_map,
const ColorMap &color_map) {
62 m_lp.set_optimization_type(lp::MINIMIZE);
64 add_variables(graph, k, weight_map);
65 add_constraints(graph, k, index_map, color_map);
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);
79 for (
unsigned vertex = 0; vertex <= num_vertices(graph); ++vertex) {
80 for (
int i = 0; i < k; ++i) {
82 vertices_column.push_back(col_idx);
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) {
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));
97 edges_column[vertices_column_index(db_index, k, i)];
99 vertices_column[vertices_column_index(sour, k, i)];
101 vertices_column[vertices_column_index(targ, k, i)];
103 x_e + (j * 2 - 1) * x_src + (1 - 2 * j) * x_trg >= 0);
109 for (
auto vertex : boost::as_array(vertices(graph))) {
110 auto col =
get(color_map, vertex);
112 auto x_col = vertices_column[
113 vertices_column_index(db_index, k, col - 1)];
116 lp::linear_expression expr;
117 for (
auto i :
irange(k)) {
118 expr += vertices_column[vertices_column_index(db_index, k, i)];
120 m_lp.
add_row(std::move(expr) == 1);
127 std::vector<lp::col_id> edges_column;
128 std::vector<lp::col_id> vertices_column;
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> {
139 std::vector<double> random_radiuses;
141 for (
int i = 0; i < k; ++i) {
142 random_radiuses.push_back(dist(random_engine));
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)]);
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) {
158 vertex_to_part[
get(index_map, vertex)] = dimension;
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);
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);
184 for (
auto vertex : boost::as_array(vertices(graph))) {
185 assign_max(terminals,
get(color_map, vertex));
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) {
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);
202 for (
auto v : boost::as_array(vertices(graph))) {
203 *result = std::make_pair(v, best_solution[
get(index_map, v)]);
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;
224 return multiway_cut_dispatch(graph, result, random_engine,
225 number_of_repeats, index_map, weight_map,
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>
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,
266 boost::choose_const_pmap(get_param(params, boost::vertex_color), g,
267 boost::vertex_color));
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>
291 Rand random_engine = std::default_random_engine(5426u))
292 ->detail::CostType<Graph> {
293 return multiway_cut(graph, result, boost::no_named_parameters(),
298 #endif // PAAL_MULTIWAY_CUT_HPP
The common LP solvers base class. Responsible for:
col_id add_column(double cost_coef=0, double lb=0., double ub=lp_traits::PLUS_INF, const std::string &name="")
void set_lp_name(const std::string problem_name)
#define puretype(t)
for given expression returns its type with removed const and reference
auto irange(T begin, T end)
irange
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 > ¶ms, 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="")