Camargue
solver.hpp
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6 
7 #ifndef CMR_SOLVER_H
8 #define CMR_SOLVER_H
9 
10 #include "core_lp.hpp"
11 #include "karp.hpp"
12 #include "datagroups.hpp"
13 #include "separator.hpp"
14 #include "meta_sep.hpp"
15 #include "abc_nodesel.hpp"
16 
17 #include "pricer.hpp"
18 #include "err_util.hpp"
19 #include "util.hpp"
20 #include "timer.hpp"
21 
22 #include <array>
23 #include <functional>
24 #include <iostream>
25 #include <map>
26 #include <memory>
27 #include <string>
28 #include <stdexcept>
29 
30 namespace CMR {
31 
32 namespace Sep {
33 class SafeGomory;
34 }
35 
37 class Solver {
38 public:
40  Solver(const std::string &tsp_fname, int seed, Graph::EdgePlan eplan,
42  OutPrefs outprefs);
43  Solver(const std::string &tsp_fname, int seed, OutPrefs outprefs);
44 
46  Solver(const std::string &tsp_fname, const std::string &tour_fname,
47  int seed, Graph::EdgePlan eplan, OutPrefs outprefs);
48  Solver(const std::string &tsp_fname, const std::string &tour_fname,
49  int seed, OutPrefs outprefs);
51 
53  Solver(int seed, int node_count, int gridsize, Graph::EdgePlan eplan,
55  OutPrefs outprefs);
56  Solver(int seed, int node_count, int gridsize, OutPrefs outprefs);
58 
59  ~Solver();
60 
61  void set_lowerbound(double lb);
62 
64  LP::PivType cutting_loop(bool do_price, bool try_recover,
65  bool pure_cut);
66 
67  template <typename SelectionRule>
68  LP::PivType abc(bool do_price);
69 
70  const Data::Instance &inst_info() const { return tsp_instance; }
71  const Graph::CoreGraph &graph_info() const { return core_graph; }
72  const Data::BestGroup &best_info() const{ return best_data; }
73  const LP::ActiveTour &active_tour() const { return core_lp.active_tour; }
74  const LP::CoreLP &get_core_lp() const { return core_lp; }
75 
77  struct CutSel {
79  enum Presets {
83  };
84 
85  bool cutpool = true;
86 
88  bool segment = true;
90  bool ex2m = true;
91  bool simpleDP = true;
92 
95  bool fast2m = true;
97  bool blkcomb = true;
98  bool connect = true;
99 
102  bool localcuts = false;
104  bool decker = false;
105  bool handling = false;
106  bool teething = false;
107 
108  bool consec1 = false;
109 
110  bool tighten = false;
111  bool tighten_pool = false;
113 
114  bool safeGMI = false;
115  } cut_sel;
116 
117  void choose_cuts(CutSel::Presets preset);
118 
120  enum Aug : char {
121  Init = 'I',
122  Piv = 'P',
123  Xtour = 'X',
124  Branch = 'B',
125  };
126 
127  using AugObj = std::pair<Aug, double>;
128  const std::vector<AugObj> &get_aug_chart() const { return aug_chart; }
129 
130 private:
131  void report_lp(LP::PivType piv);
132  void report_cuts();
133  void report_aug(Aug aug_type);
134  void initial_prints();
135 
136  std::string file_infix();
137 
139  static double PH_delta(double new_val, double prev_val, double tourlen);
140 
142  bool restart_loop(LP::PivType piv, double delta_metric);
143 
145  bool return_pivot(LP::PivType piv);
146 
147  bool lb_fathom();
148 
150  LP::PivType cut_and_piv(bool do_price);
151 
153  void opt_check_prunable(bool do_price, ABC::BranchNode &prob);
154 
155  LP::PivType abc_bcp(bool do_price);
156 
157  LP::PivType frac_recover();
158 
162  void reset_separator(std::unique_ptr<Sep::Separator> &S);
164  void reset_separator(std::unique_ptr<Sep::MetaCuts> &MS);
165 
166  void reset_separator(std::unique_ptr<Sep::SafeGomory> &GS);
168 
170  struct PivStats {
172  PivStats(double first_piv) :
173  initial_piv(first_piv), prev_val(first_piv), lowest_piv(first_piv)
174  {}
175 
176  void update(double new_val, double tourlen);
177 
178  void report_extrema();
179 
180  const double initial_piv;
181  double prev_val = 0.0;
182  double delta_ratio = 0.0;
183  double lowest_piv = 0.0;
184  double max_ratio = 0.0;
185  double first_last_ratio = 0.0;
186 
187  bool found_cuts = false;
188  };
189 
191  template <typename Qtype>
192  bool call_separator(const std::function<bool()> &sepcall,
193  Qtype &sep_q, const std::string sep_name,
194  LP::PivType &piv, PivStats &piv_stats);
195 
196  double target_lb{-std::numeric_limits<double>::max() + 1.0};
197 
198  Data::Instance tsp_instance;
199  Data::KarpPartition karp_part;
200  Graph::CoreGraph core_graph;
201  Data::BestGroup best_data;
202 
203  LP::CoreLP core_lp;
204 
205  std::unique_ptr<Price::Pricer> edge_pricer;
206 
207  std::unique_ptr<ABC::BaseBrancher> branch_controller;
208 
209  bool branch_engaged = false;
210 
211  OutPrefs output_prefs;
212 
213  int num_augs = 0;
214  std::vector<AugObj> aug_chart;
215 
216  std::array<char, 80> p_bar;
217  void place_pivot(double low_limit, double best_tourlen, double piv_val);
218 
219  Timer time_overall{"Solver Overall"};
220  Timer time_piv{"Pivoting", &time_overall};
221  Timer time_price{"Pricing", &time_overall};
222  Timer time_branch{"Branching", &time_overall};
223 
224  using TimerCalled = std::pair<Timer, bool>;
225 
226  std::map<std::string, TimerCalled> sep_times{
227  {"CutPool", {Timer("CutPool", &time_overall), false}},
228  {"SegmentCuts", {Timer("SegmentCuts", &time_overall), false}},
229  {"ConnectCuts", {Timer("ConnectCuts", &time_overall), false}},
230  {"ExactSub", {Timer("ExactSub", &time_overall), false}},
231  {"FastBlossoms", {Timer("FastBlossoms", &time_overall), false}},
232  {"ExactBlossoms", {Timer("FastBlossoms", &time_overall), false}},
233  {"BlockCombs", {Timer("BlockCombs", &time_overall), false}},
234  {"SimpleDP", {Timer("SimpleDP", &time_overall), false}},
235  {"LocalCuts", {Timer("LocalCuts", &time_overall), false}},
236  {"Decker", {Timer("Decker", &time_overall), false}},
237  {"Handling", {Timer("Handling", &time_overall), false}},
238  {"Teething", {Timer("Teething", &time_overall), false}},
239  {"Consec1", {Timer("Consec1", &time_overall), false}},
240  {"Tighten", {Timer("Tighten", &time_overall), false}},
241  {"TightenPool", {Timer("TightenPool", &time_overall), false}},
242  {"SafeGMI", {Timer("SafeGMI", &time_overall), false}},
243  };
244 };
245 
246 std::ostream &operator<<(std::ostream &os, Solver::Aug aug);
247 
248 
250 
251 
257 template <typename SelectionRule>
258 LP::PivType Solver::abc(bool do_price)
259 {
260  using std::cout;
261  using std::cerr;
262  using std::endl;
263  using std::runtime_error;
264  using std::logic_error;
265 
266  using LP::PivType;
267 
268  runtime_error err("Problem in Solver::abc");
269 
270  PivType piv = PivType::Frac;
271 
272  try { piv = cutting_loop(do_price, true, true); }
273  CMR_CATCH_PRINT_THROW("running cutting_loop", err);
274 
275  if (piv != PivType::Frac) {
276  if (piv == PivType::FathomedTour) {
277  return piv;
278  }
279  else {
280  cerr << "Pivot status " << piv << " in abc.\n";
281  throw logic_error("Invalid pivot type for running Solver::abc.");
282  }
283  }
284 
285  if (do_price) {
286  try {
287  time_price.resume();
288  edge_pricer->elim_edges(true);
289  core_lp.primal_opt();
290  time_price.stop();
291  cout << "\tcol count " << core_lp.num_cols()
292  << ", opt objval " << core_lp.get_objval() << endl;
293  } CMR_CATCH_PRINT_THROW("eliminating and optimizing", err);
294  } else {
295  try {
296  core_lp.primal_opt();
297  } CMR_CATCH_PRINT_THROW("optimizing at root", err);
298  cout << "\tRoot LP optimized with obj val " << core_lp.get_objval()
299  << endl;
300  }
301 
302 
303  cout << "\tCommencing ABC search....\n";
304 
305  try {
306  branch_controller = util::make_unique<SelectionRule>(tsp_instance,
307  best_info(),
308  graph_info(),
309  core_lp);
310  } CMR_CATCH_PRINT_THROW("allocating/instantiating Brancher", err);
311 
312  branch_engaged = true;
313  branch_controller->verbose = output_prefs.verbose;
314 
315  if (cut_sel.safeGMI) {
316  cout << "(Disabling GMI and purging cuts for branching.....)\n";
317  cut_sel.safeGMI = false;
318  try { core_lp.purge_gmi(true); }
319  CMR_CATCH_PRINT_THROW("dumping gmi cuts before abc", err);
320  }
321 
322  try { piv = abc_bcp(do_price); }
323  CMR_CATCH_PRINT_THROW("running abc_bcp", err);
324 
325  cout << "\n\tABC search completed, optimal tour has length "
326  << best_data.min_tour_value << endl;
327 
328 
329  int max_depth = 0;
330  const ABC::BranchHistory &BH = branch_controller->get_history();
331  for (const auto &B : BH)
332  if (B.depth > max_depth)
333  max_depth = B.depth;
334 
335  cout << "\t" << BH.size() << " branch nodes, max depth "
336  << max_depth << endl;
337 
338  report_cuts();
339 
340  return piv;
341 }
342 
343 
344 }
345 
346 #endif
const double initial_piv
The first pivot val before adding cuts.
Definition: solver.hpp:180
Classes for node selection rules.
Aug
Types of augmentations that can take place.
Definition: solver.hpp:120
Tracking objective values of pivots within a cut_and_piv loop.
Definition: solver.hpp:170
Pricing sets of edges.
PivType
Enum class for categorizing lp solutions.
Definition: lp_util.hpp:34
Information about the current best tour.
Definition: datagroups.hpp:154
Which separation routines should be called.
Definition: solver.hpp:77
Data group structures.
LP::PivType abc(bool do_price)
Augment-branch-cut search.
Definition: solver.hpp:258
Add safe Gomory cuts.
Definition: solver.hpp:82
Graph structures for the edges currently in a CoreLP::Relaxation.
Definition: datagroups.hpp:100
Some straightforward separation routines.
Storing TSP instance data.
Definition: datagroups.hpp:36
ERROR HANDLING CLASSES AND ROUTINES.
Karp partitions of TSP instances.
Information about the active tour in a CoreLP.
Definition: active_tour.hpp:30
Utility functions, macros, and structures.
Preferences related to tour file output and verbosity.
Definition: util.hpp:25
A class for recording CPU and wall clock time.
Definition: timer.hpp:10
Presets
Preset selection routine choices. Each contains the one before it.
Definition: solver.hpp:79
Solution of TSP instances.
Definition: solver.hpp:37
EdgePlan
Edge generation protocol to use.
Definition: datagroups.hpp:94
The namespace for this project.
Definition: abc_nodesel.hpp:20
PivStats(double first_piv)
Construct PivStats from the first pivot before adding cuts.
Definition: solver.hpp:172
#define CMR_CATCH_PRINT_THROW(msg, new_ex)
Macro for handling errors in function with multiple failure points.
Definition: err_util.hpp:25
Class for storing the core lp associated to a TSP instance and pivoting.
Definition: core_lp.hpp:33
Class for computing and storing Karp partitions.
Definition: karp.hpp:30
Definition: branch_node.hpp:25
The default initializations indicated below.
Definition: solver.hpp:80
Managing Core LP relaxations of TSP instances.
Add cut metamorphoses/local cuts.
Definition: solver.hpp:81
Separating with cut metamorphoses.