All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Pages
steiner_network.hpp
Go to the documentation of this file.
1 //=======================================================================
2 // Copyright (c) 2013 Piotr Wygocki
3 // 2014 Piotr Godlewski
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_NETWORK_HPP
17 #define PAAL_STEINER_NETWORK_HPP
18 
19 
25 
26 #include <boost/graph/kruskal_min_spanning_tree.hpp>
27 #include <boost/graph/named_function_params.hpp>
28 #include <boost/range/as_array.hpp>
29 
30 namespace paal {
31 namespace ir {
32 
33 namespace {
34 struct steiner_network_compare_traits {
35  static const double EPSILON;
36 };
37 
38 const double steiner_network_compare_traits::EPSILON = 1e-10;
39 }
40 
41 
52 template <typename Graph, typename Restrictions, typename CostMap,
53  typename VertexIndex, typename ResultNetworkOutputIterator,
56  using edge = typename boost::graph_traits<Graph>::edge_descriptor;
57  using vertex = typename boost::graph_traits<Graph>::vertex_descriptor;
58  using vertex_idx = decltype(get(std::declval<VertexIndex>(),
59  std::declval<VertexIndex>()));
60 
61  using edge_map = std::unordered_map<lp::col_id, edge>;
62  using edge_list = std::vector<edge>;
64  using error_message = boost::optional<std::string>;
65 
66  steiner_network_violation_checker m_violation_checker;
67  const Graph &m_g;
68  const Restrictions &m_restrictions;
69  CostMap m_cost_map;
70  VertexIndex m_index;
71  ResultNetworkOutputIterator m_result_network;
72  RestrictionsVector m_restrictions_vec;
73  Oracle m_oracle;
74 
75  edge_map m_edge_map;
76  edge_list m_result_list;
77  compare m_compare;
78 
79 public:
80 
84  steiner_network(const Graph & g, const Restrictions & restrictions,
85  CostMap cost_map, VertexIndex vertex_index,
86  ResultNetworkOutputIterator result_network,
87  Oracle oracle = Oracle{}) :
88  m_g(g), m_restrictions(restrictions),
89  m_cost_map(cost_map), m_index(vertex_index), m_result_network(result_network),
90  m_restrictions_vec(prune_restrictions_to_tree(m_restrictions, num_vertices(m_g))),
91  m_oracle(oracle), m_compare(steiner_network_compare_traits::EPSILON) {}
92 
96  error_message check_input_validity() {
98  if (!checker.check_if_solution_exists(*this)) {
99  return error_message{ "A Steiner network satisfying the "
100  "restrictions does not exist." };
101  } else {
102  return error_message{};
103  }
104  }
105 
114  template <typename LP>
115  auto get_find_violation(LP & lp) {
116  using candidate = steiner_network_violation_checker::Candidate;
117  return m_oracle([&](){return m_violation_checker.get_violation_candidates(*this, lp);},
118  [&](candidate c){return m_violation_checker.check_violation(c, *this);},
119  [&](candidate c){return m_violation_checker.add_violated_constraint(c, *this, lp);});
120  }
121 
125  const edge_map &get_edge_map() const { return m_edge_map; }
126 
130  const Graph &get_graph() const { return m_g; }
131 
135  const VertexIndex &get_index() const { return m_index; }
136 
140  // TODO when automatic return is used g++-4.8.2 crashes
141  auto get_max_restriction(vertex_idx u, vertex_idx v) const
142  -> decltype(std::declval<Restrictions>()(0, 0))
143  {
144  return std::max(m_restrictions(u, v), m_restrictions(v, u));
145  }
146 
150  const RestrictionsVector &get_restrictions_vec() const
151  {
152  return m_restrictions_vec;
153  }
154 
158  // TODO when automatic return is used g++-4.8.2 crashes
159  auto get_cost(edge e) -> decltype(get(std::declval<CostMap>(), e))
160  {
161  return get(m_cost_map, e);
162  }
163 
167  void bind_edge_to_col(edge e, lp::col_id col) {
168  m_edge_map.insert(typename edge_map::value_type(col, e));
169  }
170 
174  void remove_column(lp::col_id col_id) {
175  auto ret = m_edge_map.erase(col_id);
176  assert(ret == 1);
177  }
178 
183  auto e = col_to_edge(col_id);
184  *m_result_network = e;
185  ++m_result_network;
186  m_result_list.push_back(e);
187  }
188 
192  const edge_list &get_edges_in_solution() const { return m_result_list; }
193 
197  compare get_compare() const { return m_compare; }
198 
199  private:
200 
201  edge col_to_edge(lp::col_id col) {
202  auto i = m_edge_map.find(col);
203  assert(i != m_edge_map.end());
204  return i->second;
205  }
206 
207 };
208 
209 namespace detail {
227 template <typename Oracle = lp::random_violated_separation_oracle,
228  typename Graph, typename Restrictions, typename CostMap,
229  typename VertexIndex, typename ResultNetworkOutputIterator>
230 steiner_network<Graph, Restrictions, CostMap, VertexIndex, ResultNetworkOutputIterator, Oracle>
231 make_steiner_network(const Graph & g, const Restrictions & restrictions,
232  CostMap cost_map, VertexIndex vertex_index,
233  ResultNetworkOutputIterator result_network,
234  Oracle oracle = Oracle{}) {
235  return steiner_network<Graph, Restrictions, CostMap, VertexIndex,
236  ResultNetworkOutputIterator, Oracle>(
237  g, restrictions, cost_map, vertex_index, result_network, oracle);
238 }
239 } // detail
240 
262 template <typename Oracle = lp::random_violated_separation_oracle,
263  typename Graph, typename Restrictions, typename ResultNetworkOutputIterator,
264  typename P, typename T, typename R>
265 auto
266 make_steiner_network(const Graph & g, const Restrictions & restrictions,
267  const boost::bgl_named_params<P, T, R>& params,
268  ResultNetworkOutputIterator result_network,
269  Oracle oracle = Oracle()) ->
270  steiner_network<Graph, Restrictions,
271  decltype(choose_const_pmap(get_param(params, boost::edge_weight), g, boost::edge_weight)),
272  decltype(choose_const_pmap(get_param(params, boost::vertex_index), g, boost::vertex_index)),
273  ResultNetworkOutputIterator, Oracle> {
274  return detail::make_steiner_network(g, restrictions,
275  choose_const_pmap(get_param(params, boost::edge_weight), g, boost::edge_weight),
276  choose_const_pmap(get_param(params, boost::vertex_index), g, boost::vertex_index),
277  result_network, oracle);
278 }
279 
297 template <typename Oracle = lp::random_violated_separation_oracle,
298  typename Graph, typename Restrictions, typename ResultNetworkOutputIterator>
299 auto
300 make_steiner_network(const Graph & g, const Restrictions & restrictions,
301  ResultNetworkOutputIterator result_network, Oracle oracle = Oracle()) ->
302  decltype(make_steiner_network(g, restrictions, boost::no_named_parameters(), result_network, oracle)) {
303  return make_steiner_network(g, restrictions, boost::no_named_parameters(), result_network, oracle);
304 }
305 
313  template <typename Problem, typename LP>
314  void operator()(Problem &problem, LP &lp) {
315  lp.set_lp_name("steiner network");
316  lp.set_optimization_type(lp::MINIMIZE);
317  add_variables(problem, lp);
318  }
319 
320  private:
321  // adding variables
322  template <typename Problem, typename LP>
323  void add_variables(Problem &problem, LP &lp) {
324  for (auto e : boost::as_array(edges(problem.get_graph()))) {
325  lp::col_id col = lp.add_column(problem.get_cost(e), 0, 1);
326  problem.bind_edge_to_col(e, col);
327  }
328  }
329 };
330 
339  steiner_network_compare_traits::EPSILON)
340  : m_round_half(epsilon), m_round_zero(epsilon) {}
341 
352  template <typename Problem, typename LP>
353  boost::optional<double> operator()(Problem & problem, const LP & lp, lp::col_id col_id) {
354  auto ret = m_round_zero(problem, lp, col_id);
355  if (ret) {
356  //removing edge
357  problem.remove_column(col_id);
358  return ret;
359  } else {
360  ret = m_round_half(problem, lp, col_id);
361  if (ret) {
362  problem.add_column_to_solution(col_id);
363  problem.remove_column(col_id);
364  }
365  return ret;
366  }
367  }
368 
369  private:
371  round_condition_equals<0> m_round_zero;
372 };
373 
382  steiner_network_compare_traits::EPSILON)
383  : m_compare(epsilon) {}
384 
389  template <typename Problem, typename GetSolution>
390  void operator()(Problem &problem, const GetSolution &solution) {
391  for (auto edge_and_col : problem.get_edge_map()) {
392  if (m_compare.e(solution(edge_and_col.first), 1)) {
393  problem.add_column_to_solution(edge_and_col.first);
394  }
395  }
396  }
397 
398 private:
399  const utils::compare<double> m_compare;
400 };
401 
402 template <typename Init = steiner_network_init,
403  typename RoundCondition = steiner_network_round_condition,
404  typename RelaxContition = utils::always_false,
405  typename SetSolution = steiner_network_set_solution,
406  typename SolveLPToExtremePoint = row_generation_solve_lp<>,
407  typename ResolveLPToExtremePoint = row_generation_solve_lp<>>
408 using steiner_network_ir_components =
409  IRcomponents<Init, RoundCondition, RelaxContition, SetSolution,
410  SolveLPToExtremePoint, ResolveLPToExtremePoint>;
411 
412 namespace detail {
436 template <typename Oracle = lp::random_violated_separation_oracle, typename Graph,
437  typename Restrictions, typename CostMap, typename VertexIndex,
438  typename ResultNetworkOutputIterator,
439  typename IRcomponents = steiner_network_ir_components<>,
440  typename Visitor = trivial_visitor>
442  const Graph & g,
443  const Restrictions & restrictions,
444  CostMap cost,
445  VertexIndex vertex_index,
446  ResultNetworkOutputIterator result,
448  Oracle oracle = Oracle(),
449  Visitor visitor = Visitor()) {
450  auto steiner = make_steiner_network(g, restrictions, cost, vertex_index, result, oracle);
451  return solve_iterative_rounding(steiner, std::move(components), std::move(visitor));
452 }
453 } // detail
454 
478 template <typename Oracle = lp::random_violated_separation_oracle, typename Graph,
479  typename Restrictions, typename ResultNetworkOutputIterator,
480  typename IRcomponents = steiner_network_ir_components<>,
481  typename Visitor = trivial_visitor, typename P, typename T,
482  typename R>
484  const Graph &g, const Restrictions &restrictions,
485  const boost::bgl_named_params<P, T, R> &params,
486  ResultNetworkOutputIterator result,
487  IRcomponents components = IRcomponents(), Oracle oracle = Oracle(),
488  Visitor visitor = Visitor()) {
490  g, restrictions,
491  choose_const_pmap(get_param(params, boost::edge_weight), g,
492  boost::edge_weight),
493  choose_const_pmap(get_param(params, boost::vertex_index), g,
494  boost::vertex_index),
495  std::move(result), std::move(components), std::move(oracle),
496  std::move(visitor));
497 }
498 
518 template <typename Oracle = lp::random_violated_separation_oracle, typename Graph,
519  typename Restrictions, typename ResultNetworkOutputIterator,
520  typename IRcomponents = steiner_network_ir_components<>,
521  typename Visitor = trivial_visitor>
523  const Restrictions &restrictions,
524  ResultNetworkOutputIterator result,
526  IRcomponents(),
527  Oracle oracle = Oracle(),
528  Visitor visitor = Visitor()) {
530  g, restrictions, boost::no_named_parameters(), std::move(result),
531  std::move(components), std::move(oracle), std::move(visitor));
532 }
533 
534 }
535 }
536 #endif // PAAL_STEINER_NETWORK_HPP
void operator()(Problem &problem, const GetSolution &solution)
const edge_list & get_edges_in_solution() const
void add_column_to_solution(lp::col_id col_id)
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 add_violated_constraint(Candidate violation, const Problem &problem, LP &lp)
functor return false
Definition: functors.hpp:222
Violations checker for the separation oracle in the steiner network problem.
void remove_column(lp::col_id col_id)
void bind_edge_to_col(edge e, lp::col_id col)
IRResult steiner_network_iterative_rounding(const Graph &g, const Restrictions &restrictions, const boost::bgl_named_params< P, T, R > &params, ResultNetworkOutputIterator result, IRcomponents components=IRcomponents(), Oracle oracle=Oracle(), Visitor visitor=Visitor())
Solves the Steiner Network problem using Iterative Rounding. Named version.
error_message check_input_validity()
const VertexIndex & get_index() const
steiner_network_set_solution(double epsilon=steiner_network_compare_traits::EPSILON)
void set_lp_name(const std::string problem_name)
Definition: lp_base.hpp:78
The class for solving the Steiner Network problem using Iterative Rounding.
auto get_max_restriction(vertex_idx u, vertex_idx v) const -> decltype(std::declval< Restrictions >()(0, 0))
steiner_network(const Graph &g, const Restrictions &restrictions, CostMap cost_map, VertexIndex vertex_index, ResultNetworkOutputIterator result_network, Oracle oracle=Oracle{})
void operator()(Problem &problem, LP &lp)
Violation check_violation(Candidate candidate, const Problem &problem)
steiner_network< Graph, Restrictions, CostMap, VertexIndex, ResultNetworkOutputIterator, Oracle > make_steiner_network(const Graph &g, const Restrictions &restrictions, CostMap cost_map, VertexIndex vertex_index, ResultNetworkOutputIterator result_network, Oracle oracle=Oracle{})
Creates a steiner_network object. Non-named version.
RestrictionsVector prune_restrictions_to_tree(Restrictions res, int N)
Returns a list of restrictions, made of the edges of a maximum spanning tree in a clique with edge we...
Column rounding component. A variable is rounded up to 1, if it has value at least half in the soluti...
const RestrictionsVector & get_restrictions_vec() const
typename components::type< Args...> IRcomponents
Iterative rounding components.
steiner_network_round_condition(double epsilon=steiner_network_compare_traits::EPSILON)
auto get_cost(edge e) -> decltype(get(std::declval< CostMap >(), e))
const Graph & get_graph() const
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
Definition: floating.hpp:33
boost::optional< double > operator()(Problem &problem, const LP &lp, lp::col_id col_id)
IRResult steiner_network_iterative_rounding(const Graph &g, const Restrictions &restrictions, CostMap cost, VertexIndex vertex_index, ResultNetworkOutputIterator result, IRcomponents components=IRcomponents(), Oracle oracle=Oracle(), Visitor visitor=Visitor())
Solves the Steiner Network problem using Iterative Rounding. Non-named version.
const edge_map & get_edge_map() const
auto get_violation_candidates(const Problem &problem, const LP &lp) -> decltype(problem.get_restrictions_vec())
auto make_steiner_network(const Graph &g, const Restrictions &restrictions, const boost::bgl_named_params< P, T, R > &params, ResultNetworkOutputIterator result_network, Oracle oracle=Oracle()) -> steiner_network< Graph, Restrictions, 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)), ResultNetworkOutputIterator, Oracle >