15 #ifndef PAAL_BOUNDED_DEGREE_MST_HPP
16 #define PAAL_BOUNDED_DEGREE_MST_HPP
24 #include <boost/bimap.hpp>
25 #include <boost/range/as_array.hpp>
26 #include <boost/graph/connected_components.hpp>
32 struct bounded_degree_mst_compare_traits {
33 static const double EPSILON;
36 const double bounded_degree_mst_compare_traits::EPSILON = 1e-10;
51 template <
typename Graph,
typename DegreeBounds,
typename CostMap,
52 typename VertexIndex,
typename SpanningTreeOutputIterator,
60 CostMap cost_map, VertexIndex index,
61 SpanningTreeOutputIterator result_spanning_tree, Oracle oracle = Oracle{}) :
62 m_g(g), m_cost_map(cost_map), m_index(index), m_deg_bounds(deg_bounds),
63 m_result_spanning_tree(result_spanning_tree),
64 m_compare(bounded_degree_mst_compare_traits::EPSILON),
68 using Edge =
typename boost::graph_traits<Graph>::edge_descriptor;
69 using Vertex =
typename boost::graph_traits<Graph>::vertex_descriptor;
71 using EdgeMap = boost::bimap<Edge, lp::col_id>;
72 using VertexMap = std::unordered_map<lp::row_id, Vertex>;
74 using EdgeMapOriginal = std::vector<std::pair<lp::col_id, Edge>>;
76 using ErrorMessage = boost::optional<std::string>;
83 std::vector<int>
components(num_vertices(m_g));
84 int num = boost::connected_components(m_g, &components[0]);
87 return ErrorMessage{
"The graph is not connected." };
90 return ErrorMessage{};
101 template <
typename LP>
103 using candidate = bdmst_violation_checker::Candidate;
105 [&](candidate c){
return m_violation_checker.
check_violation(c, *
this);},
117 const VertexIndex &
get_index()
const {
return m_index; }
123 auto ret = m_edge_map.right.erase(col_id);
131 m_edge_map_original.push_back(
132 typename EdgeMapOriginal::value_type(col, e));
133 m_edge_map.insert(
typename EdgeMap::value_type(e, col));
139 decltype(
get(std::declval<CostMap>(), std::declval<Edge>()))
141 return get(m_cost_map, e);
147 decltype(std::declval<DegreeBounds>()(
get(std::declval<VertexIndex>(),
148 std::declval<Vertex>())))
150 return m_deg_bounds(
get(m_index, v));
158 auto i = m_edge_map.left.find(e);
159 if (i != m_edge_map.left.end()) {
175 return m_edge_map_original;
182 *m_result_spanning_tree = e;
183 ++m_result_spanning_tree;
197 m_vertex_map.insert(
typename VertexMap::value_type(row, v));
204 auto ret = m_vertex_map.erase(row_id);
213 auto i = m_vertex_map.find(row);
214 if (i != m_vertex_map.end()) {
223 auto i = m_edge_map.right.find(col);
224 assert(i != m_edge_map.right.end());
231 const DegreeBounds &m_deg_bounds;
232 SpanningTreeOutputIterator m_result_spanning_tree;
233 bdmst_violation_checker m_violation_checker;
235 EdgeMapOriginal m_edge_map_original;
237 VertexMap m_vertex_map;
263 template <
typename Oracle = lp::random_violated_separation_oracle,
265 typename DegreeBounds,
typename CostMap,
typename VertexIndex,
266 typename SpanningTreeOutputIterator>
267 bounded_degree_mst<Graph, DegreeBounds, CostMap, VertexIndex, SpanningTreeOutputIterator, Oracle>
269 CostMap cost_map, VertexIndex vertex_index,
270 SpanningTreeOutputIterator result_spanning_tree,
271 Oracle oracle = Oracle()) {
273 SpanningTreeOutputIterator, Oracle>(g, deg_bounds, cost_map, vertex_index,
274 result_spanning_tree, oracle);
301 typename DegreeBounds,
typename SpanningTreeOutputIterator,
302 typename P,
typename T,
typename R>
305 const DegreeBounds & deg_bounds,
306 const boost::bgl_named_params<P, T, R> &
params,
307 SpanningTreeOutputIterator result_spanning_tree,
308 Oracle oracle = Oracle())
310 decltype(choose_const_pmap(get_param(params, boost::edge_weight), g, boost::edge_weight)),
311 decltype(choose_const_pmap(get_param(params, boost::vertex_index), g, boost::vertex_index)),
312 SpanningTreeOutputIterator, Oracle> {
315 choose_const_pmap(get_param(params, boost::edge_weight), g, boost::edge_weight),
316 choose_const_pmap(get_param(params, boost::vertex_index), g, boost::vertex_index),
317 result_spanning_tree, oracle);
338 typename Graph,
typename DegreeBounds,
typename SpanningTreeOutputIterator>
341 SpanningTreeOutputIterator result_spanning_tree,
342 Oracle oracle = Oracle()) ->
355 bounded_degree_mst_compare_traits::EPSILON)
356 : m_round_zero(epsilon) {}
363 template <
typename Problem,
typename LP>
366 auto ret = m_round_zero(problem, lp, col);
368 problem.remove_column(col);
388 template <
typename Problem,
typename LP>
390 auto vertex = problem.row_to_vertex(row);
393 problem.get_degree_bound(*vertex) + 1);
395 problem.remove_row(row);
411 template <
typename Problem,
typename LP>
413 lp.
set_lp_name(
"bounded degree minimum spanning tree");
414 lp.set_optimization_type(lp::MINIMIZE);
416 add_variables(problem, lp);
417 add_degree_bound_constraints(problem, lp);
418 add_all_set_equality(problem, lp);
426 template <
typename Problem,
typename LP>
427 void add_variables(Problem & problem,
LP & lp) {
428 for (
auto e : boost::as_array(edges(problem.get_graph()))) {
429 auto col = lp.
add_column(problem.get_cost(e), 0, 1);
430 problem.bind_edge_to_col(e, col);
439 template <
typename Problem,
typename LP>
440 void add_degree_bound_constraints(Problem &problem,
LP &lp) {
441 auto const &g = problem.get_graph();
443 for (
auto v : boost::as_array(vertices(g))) {
444 lp::linear_expression expr;
446 for (
auto e : boost::as_array(out_edges(v, g))) {
447 expr += *(problem.edge_to_col(e));
451 lp.
add_row(std::move(expr) <= problem.get_degree_bound(v));
452 problem.bind_vertex_to_row(v, row);
460 template <
typename Problem,
typename LP>
461 void add_all_set_equality(Problem &problem,
LP &lp) {
462 lp::linear_expression expr;
466 lp.
add_row(std::move(expr) == num_vertices(problem.get_graph()) - 1);
478 bounded_degree_mst_compare_traits::EPSILON)
479 : m_compare(epsilon) {}
485 template <
typename Problem,
typename GetSolution>
486 void operator()(Problem & problem,
const GetSolution & solution) {
487 for (
auto col_and_edge : problem.get_original_edges_map()) {
488 if (m_compare.
e(solution(col_and_edge.first), 1)) {
489 problem.add_to_result_spanning_tree(col_and_edge.second);
498 template <
typename Init = bdmst_init,
499 typename RoundCondition = bdmst_round_condition,
500 typename RelaxContition = bdmst_relax_condition,
501 typename SetSolution = bdmst_set_solution,
504 using bdmst_ir_components =
505 IRcomponents<Init, RoundCondition, RelaxContition, SetSolution,
506 SolveLPToExtremePoint, ResolveLpToExtremePoint>;
534 typename DegreeBounds,
typename CostMap,
typename VertexIndex,
535 typename SpanningTreeOutputIterator,
537 typename Visitor = trivial_visitor>
540 const DegreeBounds & deg_bounds,
542 VertexIndex vertex_index,
543 SpanningTreeOutputIterator result_spanning_tree,
545 Oracle oracle = Oracle(),
546 Visitor visitor = Visitor()) {
578 typename DegreeBounds,
typename SpanningTreeOutputIterator,
580 typename Visitor = trivial_visitor,
typename P,
typename T,
584 const DegreeBounds & deg_bounds,
585 const boost::bgl_named_params<P, T, R> & params,
586 SpanningTreeOutputIterator result_spanning_tree,
588 Oracle oracle = Oracle(),
589 Visitor visitor = Visitor()) {
592 choose_const_pmap(get_param(params, boost::edge_weight), g, boost::edge_weight),
593 choose_const_pmap(get_param(params, boost::vertex_index), g, boost::vertex_index),
594 std::move(result_spanning_tree), std::move(
components),
595 std::move(oracle), std::move(visitor));
618 typename DegreeBounds,
typename SpanningTreeOutputIterator,
620 typename Visitor = trivial_visitor>
623 const DegreeBounds & deg_bounds,
624 SpanningTreeOutputIterator result_spanning_tree,
626 Oracle oracle = Oracle(),
627 Visitor visitor = Visitor()) {
630 boost::no_named_parameters(), std::move(result_spanning_tree),
631 std::move(
components), std::move(oracle), std::move(visitor));
636 #endif // PAAL_BOUNDED_DEGREE_MST_HPP
const EdgeMapOriginal & get_original_edges_map() const
The class for solving the Bounded Degree MST problem using Iterative Rounding.
decltype(std::declval< DegreeBounds >()(get(std::declval< VertexIndex >(), std::declval< Vertex >()))) get_degree_bound(Vertex v)
decltype(get(std::declval< CostMap >(), std::declval< Edge >())) get_cost(Edge e)
const CandidateList & get_violation_candidates(const Problem &problem, const LP &lp)
ErrorMessage check_input_validity()
The common LP solvers base class. Responsible for:
const EdgeMap & get_edge_map() const
col_id add_column(double cost_coef=0, double lb=0., double ub=lp_traits::PLUS_INF, const std::string &name="")
bool operator()(Problem &problem, const LP &lp, lp::row_id row)
void bind_vertex_to_row(Vertex v, lp::row_id row)
const VertexIndex & get_index() const
bounded_degree_mst(const Graph &g, const DegreeBounds °_bounds, CostMap cost_map, VertexIndex index, SpanningTreeOutputIterator result_spanning_tree, Oracle oracle=Oracle{})
auto get_find_violation(LP &lp)
void bind_edge_to_col(Edge e, lp::col_id col)
void operator()(Problem &problem, LP &lp)
void add_to_result_spanning_tree(Edge e)
void set_lp_name(const std::string problem_name)
bounded_degree_mst< Graph, DegreeBounds, CostMap, VertexIndex, SpanningTreeOutputIterator, Oracle > make_bounded_degree_mst(const Graph &g, const DegreeBounds °_bounds, CostMap cost_map, VertexIndex vertex_index, SpanningTreeOutputIterator result_spanning_tree, Oracle oracle=Oracle())
Creates a bounded_degree_mst object. Non-named version.
auto make_bounded_degree_mst(const Graph &g, const DegreeBounds °_bounds, const boost::bgl_named_params< P, T, R > ¶ms, SpanningTreeOutputIterator result_spanning_tree, Oracle oracle=Oracle()) -> bounded_degree_mst< Graph, DegreeBounds, decltype(choose_const_pmap(get_param(params, boost::edge_weight), g, boost::edge_weight)), decltype(choose_const_pmap(get_param(params, boost::vertex_index), g, boost::vertex_index)), SpanningTreeOutputIterator, Oracle >
utils::compare< double > get_compare() const
IRResult bounded_degree_mst_iterative_rounding(const Graph &g, const DegreeBounds °_bounds, CostMap cost_map, VertexIndex vertex_index, SpanningTreeOutputIterator result_spanning_tree, IRcomponents components=IRcomponents(), Oracle oracle=Oracle(), Visitor visitor=Visitor())
Solves the Bounded Degree MST problem using Iterative Rounding. Non-named version.
boost::optional< lp::col_id > edge_to_col(Edge e) const
int get_row_degree(row_id row) const
typename components::type< Args...> IRcomponents
Iterative rounding components.
const ColSet & get_columns() const
boost::optional< Vertex > row_to_vertex(lp::row_id row)
row_id add_row(const double_bounded_expression &constraint=double_bounded_expression{}, const std::string &name="")
void add_violated_constraint(Candidate violating_pair, const Problem &problem, LP &lp)
bdmst_set_solution(double epsilon=bounded_degree_mst_compare_traits::EPSILON)
std::pair< lp::problem_type, IRSolutionCost > IRResult
IRResult solve_iterative_rounding(Problem &problem, IRcomponents components, Visitor visitor=Visitor())
Solves an Iterative Rounding problem.
bool e(T a, T b) const
equals
void remove_row(lp::row_id row_id)
IRResult bounded_degree_mst_iterative_rounding(const Graph &g, const DegreeBounds °_bounds, const boost::bgl_named_params< P, T, R > ¶ms, SpanningTreeOutputIterator result_spanning_tree, IRcomponents components=IRcomponents(), Oracle oracle=Oracle(), Visitor visitor=Visitor())
Solves the Bounded Degree MST problem using Iterative Rounding. Named version.
void operator()(Problem &problem, const GetSolution &solution)
const Graph & get_graph() const
void remove_column(lp::col_id col_id)
bdmst_round_condition(double epsilon=bounded_degree_mst_compare_traits::EPSILON)
Violation check_violation(Candidate candidate, const Problem &problem)
boost::optional< double > operator()(Problem &problem, const LP &lp, lp::col_id col)