16 #ifndef PAAL_STEINER_TREE_HPP
17 #define PAAL_STEINER_TREE_HPP
19 #define BOOST_RESULT_OF_USE_DECLTYPE
32 #include <boost/random/discrete_distribution.hpp>
33 #include <boost/range/join.hpp>
34 #include <boost/range/algorithm/unique.hpp>
35 #include <boost/range/algorithm/sort.hpp>
36 #include <boost/range/algorithm/copy.hpp>
37 #include <boost/range/algorithm/find.hpp>
46 struct steiner_tree_compare_traits {
47 static const double EPSILON;
50 const double steiner_tree_compare_traits::EPSILON = 1e-10;
64 template<
typename OrigMetric,
typename Terminals,
typename Result,
65 typename Strategy = steiner_tree_all_generator,
66 typename Oracle = lp::random_violated_separation_oracle>
70 using Vertex =
typename MT::VertexType;
71 using Vertices = std::vector<Vertex>;
73 using Edge =
typename std::pair<Vertex, Vertex>;
92 Result m_result_iterator;
93 Vertices m_selected_elements;
96 std::unordered_map<int, lp::col_id> m_elements_map;
107 const Terminals& steiner_vertices, Result result,
108 const Strategy& strategy = Strategy{}, Oracle oracle = Oracle{}) :
109 m_terminals(terminals), m_steiner_vertices(steiner_vertices),
110 m_terminals_index(m_terminals),
111 m_vertex_index(boost::range::join(m_terminals, m_steiner_vertices)),
112 m_cost_map_idx(metric, boost::range::join(m_terminals, m_steiner_vertices)),
113 m_cost_map(m_cost_map_idx, m_vertex_index),
114 m_strategy(strategy), m_result_iterator(result),
115 m_compare(steiner_tree_compare_traits::EPSILON), m_oracle(oracle) {
126 template <
typename LP>
128 using candidate = steiner_tree_violation_checker::Candidate;
130 [&](candidate c){
return m_violation_checker.
check_violation(c, *
this);},
138 m_strategy.gen_components(m_cost_map, m_terminals, m_steiner_vertices,
158 return m_terminals_index.
get_idx(v);
165 bool b = m_elements_map.insert(std::make_pair(
id, col)).second;
178 boost::copy(steiner_elements, std::back_inserter(m_selected_elements));
185 boost::sort(m_selected_elements);
186 boost::copy(boost::unique(m_selected_elements), m_result_iterator);
194 auto all_terminals_except_first = boost::make_iterator_range(++all_terminals.begin(), all_terminals.end());
195 assert(!boost::empty(all_terminals));
196 auto const & sink = all_terminals.front();
197 for (
auto t : all_terminals_except_first) {
198 merge_vertices(sink, t);
199 auto ii = boost::range::find(m_terminals, t);
200 assert(ii != m_terminals.end());
201 m_terminals.erase(ii);
204 m_components.clear();
205 m_elements_map.clear();
220 auto get_idx(Vertex v)
const -> decltype(m_vertex_index.get_idx(v)) {
221 return m_vertex_index.
get_idx(v);
227 void merge_vertices(Vertex u_vertex, Vertex w_vertex) {
228 auto all_elements = boost::range::join(m_terminals, m_steiner_vertices);
229 auto u = get_idx(u_vertex);
230 auto w = get_idx(w_vertex);
231 for (
auto i_vertex: all_elements) {
232 for (
auto j_vertex: all_elements) {
233 auto i = get_idx(i_vertex);
234 auto j = get_idx(j_vertex);
236 m_cost_map_idx(i, u) + m_cost_map_idx(w, j));
251 template <
typename Problem,
typename LP>
255 problem.gen_components();
256 lp.set_optimization_type(lp::MINIMIZE);
257 add_variables(problem, lp);
264 template <
typename Problem,
typename LP>
265 void add_variables(Problem &problem,
LP &lp) {
266 for (
int i = 0; i < problem.get_components().size(); ++i) {
268 problem.get_components().find(i).get_cost(), 0, 1);
269 problem.add_column_lp(i, col);
278 std::default_random_engine m_rng;
286 template <
typename Problem,
typename LP>
288 auto size = problem.get_components().size();
289 std::vector<double> weights;
290 weights.reserve(size);
296 auto selected = boost::random::discrete_distribution<>(weights)(m_rng);
297 auto const &comp = problem.get_components().find(selected);
298 problem.add_to_solution(comp.get_steiner_elements());
299 problem.update_graph(comp);
309 template<
typename Problem,
typename LP>
311 return problem.get_terminals().size() < 2;
322 template <
typename Problem,
typename GetSolution>
324 problem.set_solution();
332 typename OrigMetric,
typename Terminals,
typename Result,
typename Strategy>
334 const OrigMetric& metric,
const Terminals& terminals,
335 const Terminals& steiner_vertices, Result result,
const Strategy& strategy,
336 Oracle oracle = Oracle()) {
338 terminals, steiner_vertices, result, strategy, oracle);
341 template <
typename Init = steiner_tree_init,
342 typename RoundCondition = steiner_tree_round_condition,
344 typename SetSolution = steiner_tree_set_solution,
345 typename SolveLPToExtremePoint = row_generation_solve_lp<>,
346 typename ResolveLPToExtremePoint = row_generation_solve_lp<>,
347 typename StopCondition = steiner_tree_stop_condition>
348 using steiner_tree_ir_components =
349 IRcomponents<Init, RoundCondition, RelaxCondition, SetSolution,
350 SolveLPToExtremePoint, ResolveLPToExtremePoint, StopCondition>;
356 typename Strategy = steiner_tree_all_generator,
361 typename Visitor = trivial_visitor>
363 const Terminals& steiner_vertices, Result result, Strategy strategy = Strategy{},
365 Visitor visitor = Visitor{}) {
374 #endif // PAAL_STEINER_TREE_HPP
void operator()(Problem &problem, const GetSolution &)
Violation check_violation(Candidate candidate, const Problem &problem)
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 operator()(Problem &problem, LP &lp)
steiner_tree(const OrigMetric &metric, const Terminals &terminals, const Terminals &steiner_vertices, Result result, const Strategy &strategy=Strategy{}, Oracle oracle=Oracle{})
utils::compare< double > get_compare() const
auto get_violation_candidates(const Problem &problem, const LP &lp) -> decltype(irange(problem.get_terminals().size()))
Idx get_idx(const T &t) const
gets index of element t
void add_to_solution(const std::vector< Vertex > &steiner_elements)
problem_type
LP problem type.
const steiner_components< Vertex, Dist > & get_components() const
auto get_find_violation(LP &lp)
Class represents k-components of Steiner Tree. Component is a subtree whose terminals coincide with l...
void set_lp_name(const std::string problem_name)
bool operator()(Problem &problem, LP &)
Checks if the IR algorithm should terminate.
The class for solving the Steiner Tree problem using Iterative Rounding.
const Vertices & get_terminals() const
auto irange(T begin, T end)
irange
lp::problem_type steiner_tree_iterative_rounding(const OrigMetric &metric, const Terminals &terminals, const Terminals &steiner_vertices, Result result, Strategy strategy=Strategy{}, IRcomponents comps=IRcomponents{}, Oracle oracle=Oracle{}, Visitor visitor=Visitor{})
Solves the Steiner Tree problem using Iterative Rounding.
Violations checker for the separation oracle in the steiner tree problem.
lp::col_id find_column_lp(int id) const
void assign_min(T &t, const T &u)
steiner_tree< OrigMetric, Terminals, Result, Strategy, Oracle > make_steiner_tree(const OrigMetric &metric, const Terminals &terminals, const Terminals &steiner_vertices, Result result, const Strategy &strategy, Oracle oracle=Oracle())
Terminals
enum indicates if given color represents terminal or NONTERMINAL.
auto get_terminal_idx(Vertex v) const -> decltype(m_terminals_index.get_idx(v))
typename components::type< Args...> IRcomponents
Iterative rounding components.
const Terminals & get_terminals() const
double get_col_value(col_id col) const
void add_violated_constraint(Candidate violating_terminal, const Problem &problem, LP &lp)
puretype(std::declval< Metric >()(std::declval< VertexType >(), std::declval< VertexType >())) DistanceType
Distance type.
void operator()(Problem &problem, LP &lp)
IRResult solve_dependent_iterative_rounding(Problem &problem, IRcomponents components, Visitor visitor=Visitor())
Solves an Iterative Rounding problem with dependent rounding.
void add_column_lp(int id, lp::col_id col)
void update_graph(const steiner_component< Vertex, Dist > &selected)