TCPSPSuite
swag.hpp
1 #ifndef TCPSPSUITE_SWAG_HPP
2 #define TCPSPSUITE_SWAG_HPP
3 
4 #include "../datastructures/fast_reset_vector.hpp"
5 #include "../datastructures/skyline_interface.hpp" // for Sky...
6 #include "../instance/job.hpp" // for Job
7 #include "../instance/solution.hpp" // for Sol...
8 #include "../instance/traits.hpp"
9 #include "../manager/solvers.hpp" // for get...
10 #include "../manager/timer.hpp" // for Timer
11 #include "../util/log.hpp" // for Log
12 #include "elitepoolscorer.hpp"
13 #include "matrixedgescorer.hpp"
14 
15 #include <bitset>
16 #include <random> // for mt1...
17 #include <stddef.h> // for size_t
18 #include <string> // for string
19 #include <tuple> // for tuple
20 #include <utility> // for pair
21 #include <vector> // for vector
22 
23 class AdditionalResultStorage;
24 class Instance;
25 class SolverConfig;
26 namespace solvers {
27 template <unsigned int>
28 struct registry_hook;
29 }
30 
31 namespace swag {
32 namespace detail {
33 
34 class Edge {
35 public:
36  Edge(Job::JobId target, size_t rev_index_in, bool permanent)
37  : t(target), rev_index(rev_index_in)
38  {
39  this->set_permanent(permanent);
40  this->set_marked(false);
41  }
42 
43  Edge() : t(0), rev_index(0) {}
44 
45  Job::JobId t;
46  size_t rev_index;
47 
48  bool
49  is_permanent() const noexcept
50  {
51  return this->flags[FLAG_INDEX_PERMANENT];
52  }
53 
54  bool
55  is_marked() const noexcept
56  {
57  return this->flags[FLAG_INDEX_MARKED];
58  }
59  void
60  set_marked(bool value) noexcept
61  {
62  this->flags[FLAG_INDEX_MARKED] = value;
63  }
64 
65  bool
66  is_seen() const noexcept
67  {
68  return this->flags[FLAG_INDEX_SEEN];
69  }
70  void
71  set_seen(bool value) noexcept
72  {
73  this->flags[FLAG_INDEX_SEEN] = value;
74  }
75 
76 private:
77  void
78  set_permanent(bool value) noexcept
79  {
80  this->flags[FLAG_INDEX_PERMANENT] = value;
81  }
82 
83  std::bitset<2> flags;
84  static constexpr size_t FLAG_INDEX_PERMANENT = 0;
85  static constexpr size_t FLAG_INDEX_MARKED = 1;
86  static constexpr size_t FLAG_INDEX_SEEN = 2;
87 };
88 
89 struct ReverseEdge
90 {
91  Job::JobId s;
92  size_t forward_index;
93 };
94 
95 template <bool use_mes, bool use_eps>
96 class SWAGSolver {
97 public:
98  SWAGSolver(const Instance & instance, AdditionalResultStorage & additional,
99  const SolverConfig & sconf);
100  void run();
101  Solution get_solution();
102 
103  void dbg_verify();
104 
105 private:
106  void graph_insert_edge(Job::JobId s, Job::JobId t,
107  bool permanent = false) noexcept;
108  void graph_delete_edge(Job::JobId s, size_t s_adj_list_index) noexcept;
109  void graph_delete_edge(Edge * e) noexcept;
110 
111  void initialize_graph() noexcept;
112  void initialize_times() noexcept;
113  void initialize_skyline() noexcept;
114 
115  /* Takes its input via push_es_forward_queue, outputs via
116  * changed_nodes_buf. */
117  void push_es_forward(bool force_complete, bool range_changed) noexcept;
118  void rebuild_es_forward() noexcept;
119 
120  /* Takes its input via push_lf_backwards_queue */
121  void push_lf_backward(bool force_complete, bool range_changed) noexcept;
122  void rebuild_lf_backward() noexcept;
123 
124  void insert_edge(Job::JobId s, Job::JobId t, bool force_complete) noexcept;
125 
126  void delete_edge(Edge * e) noexcept;
127  void delete_edge(Job::JobId s, size_t s_adj_list_index) noexcept;
128 
129  bool iteration_insert_edge(bool force_complete) noexcept;
130  void iteration_regenerate_candidates() noexcept;
131  void iteration_unstick() noexcept;
132  void iteration_propagate(bool complete, bool range_changed) noexcept;
133  void iteration() noexcept;
134  void reset() noexcept;
135 
136  /* Candidate building & selection */
137  void build_candidate_jobs() noexcept;
138  // Returns the score sum
139  void build_candidate_edges() noexcept;
140  void build_candidate_edges_batched() noexcept;
141  size_t batch_offset;
142 
143  // Force-Creates new candidates by deleting edges
144  void create_new_candidate_edges() noexcept;
145  unsigned int find_edges_to_delete_backwards(Job::JobId t, unsigned int amount,
146  size_t max_depth);
147  void edgedel_update_current_values_backwards(Job::JobId t);
148 
149  unsigned int find_edges_to_delete_forwards(Job::JobId s, unsigned int amount,
150  size_t max_depth);
151  void edgedel_update_current_values_forwards(Job::JobId s);
152 
153  void bulk_delete();
154 
155  void dbg_verify_graph();
156  void dbg_verify_cycle_free();
157  void dbg_verify_solution();
158  void dbg_verify_times();
159  void dbg_generate_dot(std::ostringstream & buf);
160  void dbg_print_graph();
161  void dbg_write_graph(std::string filename);
162  void dbg_print_adjacencies();
163  void dbg_verify_active_range();
164 
165  void dbg_verify_values_during_forwards_bfs();
166  void dbg_verify_values_during_backwards_bfs();
167  void dbg_verify_limits_during_partial_propagation();
168  void dbg_verify_correctly_partially_propagated();
169 
170  const Instance & instance;
171  double timelimit;
172  const SolverConfig & sconf;
173  AdditionalResultStorage & additional;
174  bool disaggregate_time;
175  double intermediate_interval;
176  double intermediate_score_interval;
177  size_t deletion_trials;
178  size_t deletion_max_depth;
179  size_t deletions_before_reset;
180  size_t force_complete_push_after;
181  size_t force_range_check_after;
182  bool randomize_edge_candidates;
183  size_t edge_candidate_batchsize;
184  double deletion_undermove_penalty;
185 
186  size_t deletions_remaining;
187  size_t last_complete_push;
188  size_t last_range_check;
189  Timer run_timer;
190 
191  std::vector<std::vector<Edge>> adjacency_list;
192  std::vector<std::vector<ReverseEdge>> rev_adjacency_list;
193 
194  ds::SkyLine rsl;
195 
196  std::vector<unsigned int> earliest_starts;
197  std::vector<unsigned int> latest_finishs;
198 
199  std::vector<unsigned int> base_earliest_starts;
200  std::vector<unsigned int> base_latest_finishs;
201  std::vector<std::vector<Edge>> base_adjacency_list;
202  std::vector<std::vector<ReverseEdge>> base_rev_adjacency_list;
203 
204  double best_score;
205  std::vector<unsigned int> best_start_times;
206 
207  std::mt19937 rnd;
208 
209  /* Scoring */
210  utilities::OptionalMember<MatrixEdgeScorer, use_mes> mes;
211  utilities::OptionalMember<ElitePoolScorer, use_eps> eps;
212  double score_sum;
213 
214  /* Statistics - Counts */
215  size_t iteration_count;
216  size_t insertion_count;
217  size_t solution_count;
218  size_t deletion_count;
219  size_t reset_count;
220 
221  /* Statistics - Times */
222  double skyline_update_time;
223  double propagate_time;
224  double reset_time;
225  double job_selection_time;
226  double edge_selection_time;
227  double unstick_time;
228 
229  // Periodic logging
230  Timer log_timer;
231  double last_log_time;
232  size_t last_log_iteration;
233 
234  /* Intermediate results */
235  double intermediate_score_last_time;
236  size_t intermediate_score_number;
237 
238  /* Caching this makes things a lot faster. */
239  std::vector<decltype(Job().get_duration())> durations;
240  std::vector<decltype(Job().get_deadline())> deadlines;
241  std::vector<decltype(Job().get_release())> releases;
242  const size_t job_count;
243 
244  /* Allocate-once buffers */
245  std::vector<Job::JobId> candidates_buf;
246  utilities::ConditionalMember<
247  std::vector<std::tuple<double, Job::JobId, Job::JobId>>,
248  std::vector<std::pair<Job::JobId, Job::JobId>>, use_mes || use_eps>
249  candidate_edge_buf;
250  std::vector<std::pair<Job::JobId, unsigned int>> active_jobs_buf;
251 
252  std::pair<unsigned int, unsigned int> active_range;
253 
254  // TODO change queues to circular vector?
255  std::vector<Job::JobId> push_lf_backward_queue;
256  std::vector<Job::JobId> push_lf_backward_out_of_range;
257  std::vector<Job::JobId> push_es_forward_queue;
258  std::vector<Job::JobId> push_es_forward_out_of_range;
259 
260  // TODO change queues to circular vector?
261  std::vector<Job::JobId> rebuild_es_forward_queue;
262  std::vector<Job::JobId> rebuild_lf_backward_queue;
263 
264  std::vector<Job::JobId> changed_nodes_buf;
265  FastResetVector<bool> node_moved_buf;
266 
267  /*
268  * Bulk deletion buffers
269  */
270  // forward_deletion_buckets[s] stores the list of indices into
271  // adjacency_list[s] that should be deleted
272  std::vector<std::vector<size_t>> forward_deletion_buckets;
273  // reverse_deletion_buckets[t] stores the list of indices into
274  // rev_adjacency_list[t] that should be deleted
275  std::vector<std::vector<size_t>> reverse_deletion_buckets;
276  // forward_pointers_changed[s] stores (edge_index, new_rev_index), where
277  // adjacency_list[s][edge_index].rev_index should be new_rev_index
278  std::vector<std::vector<std::pair<size_t, size_t>>> forward_pointers_changed;
279  // reverse_pointers_changed[t] stores (edge_index, new_forward_index), where
280  // rev_adj_list[t][edge_index].forward_index should be new_forward_index
281  std::vector<std::vector<std::pair<size_t, size_t>>> reverse_pointers_changed;
282 
283  /* Edge-deletion related buffers
284  *
285  * The set of edges that we currently consider for deletion consists of:
286  *
287  * * all marked edges in bfs_buf
288  * * all the edges in committed_deletion_buffer;
289  *
290  */
291  struct EdgeBFSEntry
292  {
293  Edge * e;
294  size_t depth;
295 
296  EdgeBFSEntry(Edge * e_in, size_t depth_in) : e(e_in), depth(depth_in) {}
297  EdgeBFSEntry() : e(nullptr), depth(0) {}
298  };
299 
300  /* For forward search:
301  * stores the length of the (taut) critical path from
302  * this->latest_finishs[wanted_t] to this->latest_finishs[i]
303  *
304  * For backward search:
305  * stores the length of the (taut) critical path from
306  * this->earliest_starts[i] to this->earliest_starts[wanted_s]
307  */
308 
309  /* Stores the length of the (taut) critical path of [i] to the
310  * wanted_t or wanted_s */
311  // std::vector<unsigned int> edgedel_critical_paths_lengths;
312  /* TODO */
313  // std::vector<unsigned int> edgedel_worst_in_upstream;
314 
315  /* Stores whether the edgedel_critical_paths_lengths and
316  * edgedel_max_useful_movement
317  * for a vertex have already been set in this BFS */
318  FastResetVector<bool> edgedel_vertex_seen;
319  std::vector<Edge *> edgedel_edge_seen;
320 
321  // TODO
322  std::vector<unsigned int> edgedel_current_value;
323  std::vector<Job::JobId> edgedel_sorted_by_start_buf;
324  std::vector<Job::JobId> edgedel_sorted_by_end_buf;
325 
326  /* TODO FIXME DEBUG */
327  // CircularVector<EdgeBFSEntry> bfs_buf;
328  std::deque<EdgeBFSEntry> bfs_buf;
329  std::deque<Job::JobId> rebuild_queue;
330  // CircularVector<Job::JobId> rebuild_queue;
331  // std::vector<EdgeBFSEntry> bfs_buf;
332  // std::vector<Job::JobId> rebuild_queue;
333 
334  std::vector<Edge *> bfs_pruned_buffer;
335  std::vector<Job::JobId> bfs_ran_out_of_buffer; // TODO do we still need this?
336 
337  std::vector<Edge *> delete_backwards_edges_buf;
338  std::vector<Edge *> delete_forwards_edges_buf;
339 
340  Log l;
341 };
342 
343 } // namespace detail
344 
345 /*
346  * This class acts only as a dispatcher to the correct specialization
347  */
348 class SWAGSolver {
349 public:
350  SWAGSolver(const Instance & instance, AdditionalResultStorage & additional,
351  const SolverConfig & sconf);
352  void run();
353  Solution get_solution();
354  static std::string get_id();
355  Maybe<double> get_lower_bound();
356  static const Traits & get_requirements();
357 
358 private:
359  size_t impl_index;
360  static const Traits required_traits;
361 
362  std::tuple<detail::SWAGSolver<false, false>, detail::SWAGSolver<false, true>,
363  detail::SWAGSolver<true, false>, detail::SWAGSolver<true, true>>
364  impl;
365 };
366 } // namespace swag
367 
368 // Register the solver
369 namespace solvers {
370 
371 template <>
372 struct registry_hook<solvers::get_free_N<swag::SWAGSolver>()>
373 {
374  constexpr static unsigned int my_N = solvers::get_free_N<swag::SWAGSolver>();
375 
376  auto
377  operator()()
378  {
379  return solvers::register_class<swag::SWAGSolver, my_N>{}();
380  }
381 };
382 
383 } // namespace solvers
384 
385 #endif // TCPSPSUITE_SWAG_HPP
Instance
a TCPSP instance
Definition: instance.hpp:24
Job
A job of an TCPSP instance.
Definition: job.hpp:21
Solution
a soultion for a TCPSP instance
Definition: solution.hpp:17