OR-Tools  9.2
cp_model_lns.h
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #ifndef OR_TOOLS_SAT_CP_MODEL_LNS_H_
15 #define OR_TOOLS_SAT_CP_MODEL_LNS_H_
16 
17 #include <cstdint>
18 #include <vector>
19 
20 #include "absl/container/flat_hash_map.h"
21 #include "absl/random/bit_gen_ref.h"
22 #include "absl/synchronization/mutex.h"
23 #include "absl/types/span.h"
27 #include "ortools/sat/model.h"
28 #include "ortools/sat/subsolver.h"
31 #include "ortools/util/logging.h"
32 
33 namespace operations_research {
34 namespace sat {
35 
36 // Neighborhood returned by Neighborhood generators.
37 struct Neighborhood {
38  // True if neighborhood generator was able to generate a neighborhood.
39  bool is_generated = false;
40 
41  // True if an optimal solution to the neighborhood is also an optimal solution
42  // to the original model.
43  bool is_reduced = false;
44 
45  // True if this neighborhood was just obtained by fixing some variables.
46  bool is_simple = false;
47 
48  // Specification of the delta between the initial model and the lns fragment.
49  // The delta will contains all variables from the initial model, potentially
50  // with updated domains.
51  // It can contains new variables and new constraints, and solution hinting.
53  std::vector<int> constraints_to_ignore;
54 
55  // Neighborhood Id. Used to identify the neighborhood by a generator.
56  // Currently only used by WeightedRandomRelaxationNeighborhoodGenerator.
57  // TODO(user): Make sure that the id is unique for each generated
58  // neighborhood for each generator.
59  int64_t id = 0;
60 
61  // Used for identifying the source of the neighborhood if it is generated
62  // using solution repositories.
63  std::string source_info = "";
64 
65  // Statistic, only filled when is_simple is true.
68 
69  // Only filled when is_simple is true. If we solve the fragment to optimality,
70  // then we can just fix the variable listed here to that optimal solution.
71  //
72  // This can happen if the neighborhood fully cover some part that are
73  // completely independent from the rest of the model. Like for instance an
74  // unused but not yet fixed variable.
75  //
76  // WARNING: all such variables should be fixed at once in a lock-like manner,
77  // because they can be multiple optimal solutions on these variables.
79 };
80 
81 // Contains pre-computed information about a given CpModelProto that is meant
82 // to be used to generate LNS neighborhood. This class can be shared between
83 // more than one generator in order to reduce memory usage.
84 //
85 // Note that its implement the SubSolver interface to be able to Synchronize()
86 // the bounds of the base problem with the external world.
88  public:
92  SharedTimeLimit* shared_time_limit = nullptr,
93  SharedBoundsManager* shared_bounds = nullptr);
94 
95  // SubSolver interface.
96  bool TaskIsAvailable() override { return false; }
97  std::function<void()> GenerateTask(int64_t task_id) override { return {}; }
98  void Synchronize() override;
99 
100  // Returns the LNS fragment where the given variables are fixed to the value
101  // they take in the given solution.
103  const CpSolverResponse& base_solution,
104  const absl::flat_hash_set<int>& variables_to_fix) const;
105 
106  // Returns the neighborhood where the given constraints are removed.
108  const std::vector<int>& constraints_to_remove) const;
109 
110  // Returns the LNS fragment which will relax all inactive variables and all
111  // variables in relaxed_variables.
113  const CpSolverResponse& initial_solution,
114  const std::vector<int>& relaxed_variables) const;
115 
116  // Returns a trivial model by fixing all active variables to the initial
117  // solution values.
118  Neighborhood FixAllVariables(const CpSolverResponse& initial_solution) const;
119 
120  // Returns a neighborhood that correspond to the full problem.
122 
123  // Returns a neighborhood that will just be skipped.
124  // It usually indicate that the generator failed to generated a neighborhood.
126 
127  // Adds solution hinting to the neighborhood from the value of the initial
128  // solution.
129  void AddSolutionHinting(const CpSolverResponse& initial_solution,
130  CpModelProto* model_proto) const;
131 
132  // Indicates if the variable can be frozen. It happens if the variable is non
133  // constant, and if it is a decision variable, or if
134  // focus_on_decision_variables is false.
135  bool IsActive(int var) const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_);
136 
137  // Returns the list of "active" variables.
138  std::vector<int> ActiveVariables() const {
139  std::vector<int> result;
140  absl::ReaderMutexLock lock(&graph_mutex_);
141  result = active_variables_;
142  return result;
143  }
144 
145  int NumActiveVariables() const {
146  absl::ReaderMutexLock lock(&graph_mutex_);
147  return active_variables_.size();
148  }
149 
150  bool DifficultyMeansFullNeighborhood(double difficulty) const {
151  absl::ReaderMutexLock lock(&graph_mutex_);
152  const int target_size = std::ceil(difficulty * active_variables_.size());
153  return target_size == active_variables_.size();
154  }
155 
156  // Returns the vector of active variables. The graph_mutex_ must be
157  // locked before calling this method.
158  const std::vector<int>& ActiveVariablesWhileHoldingLock() const
159  ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_) {
160  return active_variables_;
161  }
162 
163  // Constraints <-> Variables graph.
164  // Note that only non-constant variable are listed here.
165  const std::vector<std::vector<int>>& ConstraintToVar() const
166  ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_) {
167  return constraint_to_var_;
168  }
169  const std::vector<std::vector<int>>& VarToConstraint() const
170  ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_) {
171  return var_to_constraint_;
172  }
173 
174  // Returns all the constraints indices of a given type.
175  const absl::Span<const int> TypeToConstraints(
176  ConstraintProto::ConstraintCase type) const {
177  if (type >= type_to_constraints_.size()) return {};
178  return absl::MakeSpan(type_to_constraints_[type]);
179  }
180 
181  // Returns the list of indices of active interval constraints according
182  // to the initial_solution and the parameter lns_focus_on_performed_intervals.
183  // If true, this method returns the list of performed intervals in the
184  // solution. If false, it returns all intervals of the model.
185  std::vector<int> GetActiveIntervals(
186  const CpSolverResponse& initial_solution) const;
187 
188  // Returns one sub-vector per circuit or per single vehicle ciruit in a routes
189  // constraints. Each circuit is non empty, and does not contain any
190  // self-looping arcs. Path are sorted, starting from the arc with the lowest
191  // tail index, and going in sequence up to the last arc before the circuit is
192  // closed. Each entry correspond to the arc literal on the circuit.
193  std::vector<std::vector<int>> GetRoutingPaths(
194  const CpSolverResponse& initial_solution) const;
195 
196  // The initial problem.
197  // Note that the domain of the variables are not updated here.
198  const CpModelProto& ModelProto() const { return model_proto_; }
199  const SatParameters& Parameters() const { return parameters_; }
200 
202  return *shared_response_;
203  }
204 
205  // TODO(user): Refactor the class to be thread-safe instead, it should be
206  // safer and more easily maintenable. Some complication with accessing the
207  // variable<->constraint graph efficiently though.
208 
209  // Note: This mutex needs to be public for thread annotations.
210  mutable absl::Mutex graph_mutex_;
211 
212  // TODO(user): Display LNS statistics through the StatisticsString()
213  // method.
214 
215  private:
216  // Precompute stuff that will never change. During the execution, only the
217  // domain of the variable will change, so data that only depends on the
218  // constraints need to be computed just once.
219  void InitializeHelperData();
220 
221  // Recompute most of the class member. This needs to be called when the
222  // domains of the variables are updated.
223  void RecomputeHelperData();
224 
225  // Indicates if a variable is fixed in the model.
226  bool IsConstant(int var) const ABSL_SHARED_LOCKS_REQUIRED(domain_mutex_);
227 
228  // Returns true if the domain on the objective is constraining and we might
229  // get a lower objective value at optimum without it.
230  bool ObjectiveDomainIsConstraining() const
231  ABSL_SHARED_LOCKS_REQUIRED(domain_mutex_);
232 
233  const SatParameters& parameters_;
234  const CpModelProto& model_proto_;
235  int shared_bounds_id_;
236  SharedTimeLimit* shared_time_limit_;
237  SharedBoundsManager* shared_bounds_;
238  SharedResponseManager* shared_response_;
239  SharedRelaxationSolutionRepository* shared_relaxation_solutions_;
240 
241  // This proto will only contain the field variables() with an updated version
242  // of the domains compared to model_proto_.variables(). We do it like this to
243  // reduce the memory footprint of the helper when the model is large.
244  //
245  // TODO(user): Use custom domain repository rather than a proto?
246  CpModelProto model_proto_with_only_variables_ ABSL_GUARDED_BY(domain_mutex_);
247 
248  // Constraints by types. This never changes.
249  std::vector<std::vector<int>> type_to_constraints_;
250 
251  // Whether a model_proto_ variable appear in the objective. This never
252  // changes.
253  std::vector<bool> is_in_objective_;
254 
255  // A copy of CpModelProto where we did some basic presolving to remove all
256  // constraint that are always true. The Variable-Constraint graph is based on
257  // this model. Note that only the constraints field is present here.
258  CpModelProto simplied_model_proto_ ABSL_GUARDED_BY(graph_mutex_);
259 
260  // Variable-Constraint graph.
261  // We replace an interval by its variables in the scheduling constraints.
262  //
263  // TODO(user): Note that the objective is not considered here. Which is fine
264  // except if the objective domain is constraining.
265  std::vector<std::vector<int>> constraint_to_var_
266  ABSL_GUARDED_BY(graph_mutex_);
267  std::vector<std::vector<int>> var_to_constraint_
268  ABSL_GUARDED_BY(graph_mutex_);
269 
270  // Connected components of the variable-constraint graph. If a variable is
271  // constant, it will not appear in any component and
272  // var_to_component_index_[var] will be -1.
273  std::vector<std::vector<int>> components_ ABSL_GUARDED_BY(graph_mutex_);
274  std::vector<int> var_to_component_index_ ABSL_GUARDED_BY(graph_mutex_);
275 
276  // The set of active variables which is currently the list of non-constant
277  // variables. It is stored both as a list and as a set (using a Boolean
278  // vector).
279  std::vector<bool> active_variables_set_ ABSL_GUARDED_BY(graph_mutex_);
280  std::vector<int> active_variables_ ABSL_GUARDED_BY(graph_mutex_);
281 
282  mutable absl::Mutex domain_mutex_;
283 };
284 
285 // Base class for a CpModelProto neighborhood generator.
287  public:
288  NeighborhoodGenerator(const std::string& name,
289  NeighborhoodGeneratorHelper const* helper)
290  : name_(name), helper_(*helper), difficulty_(0.5) {}
292 
293  // Generates a "local" subproblem for the given seed.
294  //
295  // The difficulty will be in [0, 1] and is related to the asked neighborhood
296  // size (and thus local problem difficulty). A difficulty of 0.0 means empty
297  // neighborhood and a difficulty of 1.0 means the full problem. The algorithm
298  // should try to generate a neighborhood according to this difficulty which
299  // will be dynamically adjusted depending on whether or not we can solve the
300  // subproblem in a given time limit.
301  //
302  // The given initial_solution should contain a feasible solution to the
303  // initial CpModelProto given to this class. Any solution to the returned
304  // CPModelProto should also be valid solution to the same initial model.
305  //
306  // This function should be thread-safe.
307  virtual Neighborhood Generate(const CpSolverResponse& initial_solution,
308  double difficulty, absl::BitGenRef random) = 0;
309 
310  // Returns true if the neighborhood generator can generate a neighborhood.
311  virtual bool ReadyToGenerate() const;
312 
313  // Returns true if the neighborhood generator generates relaxation of the
314  // given problem.
315  virtual bool IsRelaxationGenerator() const { return false; }
316 
317  // Uses UCB1 algorithm to compute the score (Multi armed bandit problem).
318  // Details are at
319  // https://lilianweng.github.io/lil-log/2018/01/23/the-multi-armed-bandit-problem-and-its-solutions.html.
320  // 'total_num_calls' should be the sum of calls across all generators part of
321  // the multi armed bandit problem.
322  // If the generator is called less than 10 times then the method returns
323  // infinity as score in order to get more data about the generator
324  // performance.
325  double GetUCBScore(int64_t total_num_calls) const;
326 
327  // Adds solve data about one "solved" neighborhood.
328  struct SolveData {
329  // Neighborhood Id. Used to identify the neighborhood by a generator.
330  // Currently only used by WeightedRandomRelaxationNeighborhoodGenerator.
331  int64_t neighborhood_id = 0;
332 
333  // The status of the sub-solve.
335 
336  // The difficulty when this neighborhood was generated.
337  double difficulty = 0.0;
338 
339  // The determinitic time limit given to the solver for this neighborhood.
340  double deterministic_limit = 0.0;
341 
342  // The time it took to solve this neighborhood.
343  double deterministic_time = 0.0;
344 
345  // Objective information. These only refer to the "internal" objective
346  // without scaling or offset so we are exact and it is always in the
347  // minimization direction.
348  // - The initial best objective is the one of the best known solution at the
349  // time the neighborhood was generated.
350  // - The base objective is the one of the base solution from which this
351  // neighborhood was generated.
352  // - The new objective is the objective of the best solution found by
353  // solving the neighborhood.
354  IntegerValue initial_best_objective = IntegerValue(0);
355  IntegerValue base_objective = IntegerValue(0);
356  IntegerValue new_objective = IntegerValue(0);
357 
358  // Bounds data is only used by relaxation neighborhoods.
359  IntegerValue initial_best_objective_bound = IntegerValue(0);
360  IntegerValue new_objective_bound = IntegerValue(0);
361 
362  // This is just used to construct a deterministic order for the updates.
363  bool operator<(const SolveData& o) const {
364  return std::tie(status, difficulty, deterministic_limit,
365  deterministic_time, initial_best_objective,
366  base_objective, new_objective,
367  initial_best_objective_bound, new_objective_bound,
368  neighborhood_id) <
369  std::tie(o.status, o.difficulty, o.deterministic_limit,
373  o.neighborhood_id);
374  }
375  };
376  void AddSolveData(SolveData data) {
377  absl::MutexLock mutex_lock(&generator_mutex_);
378  solve_data_.push_back(data);
379  }
380 
381  // Process all the recently added solve data and update this generator
382  // score and difficulty.
383  void Synchronize();
384 
385  // Returns a short description of the generator.
386  std::string name() const { return name_; }
387 
388  // Number of times this generator was called.
389  int64_t num_calls() const {
390  absl::MutexLock mutex_lock(&generator_mutex_);
391  return num_calls_;
392  }
393 
394  // Number of time the neighborhood was fully solved (OPTIMAL/INFEASIBLE).
395  int64_t num_fully_solved_calls() const {
396  absl::MutexLock mutex_lock(&generator_mutex_);
397  return num_fully_solved_calls_;
398  }
399 
400  // The current difficulty of this generator
401  double difficulty() const {
402  absl::MutexLock mutex_lock(&generator_mutex_);
403  return difficulty_.value();
404  }
405 
406  // The current time limit that the sub-solve should use on this generator.
407  double deterministic_limit() const {
408  absl::MutexLock mutex_lock(&generator_mutex_);
409  return deterministic_limit_;
410  }
411 
412  // The sum of the deterministic time spent in this generator.
413  double deterministic_time() const {
414  absl::MutexLock mutex_lock(&generator_mutex_);
415  return deterministic_time_;
416  }
417 
418  protected:
419  // Triggered with each call to Synchronize() for each recently added
420  // SolveData. This is meant to be used for processing feedbacks by specific
421  // neighborhood generators to adjust the neighborhood generation process.
422  virtual void AdditionalProcessingOnSynchronize(const SolveData& solve_data) {}
423 
424  const std::string name_;
426  mutable absl::Mutex generator_mutex_;
427 
428  private:
429  std::vector<SolveData> solve_data_;
430 
431  // Current parameters to be used when generating/solving a neighborhood with
432  // this generator. Only updated on Synchronize().
433  AdaptiveParameterValue difficulty_;
434  double deterministic_limit_ = 0.1;
435 
436  // Current statistics of the last solved neighborhood.
437  // Only updated on Synchronize().
438  int64_t num_calls_ = 0;
439  int64_t num_fully_solved_calls_ = 0;
440  int64_t num_consecutive_non_improving_calls_ = 0;
441  double deterministic_time_ = 0.0;
442  double current_average_ = 0.0;
443 };
444 
445 // Pick a random subset of variables.
446 //
447 // TODO(user): In the presence of connected components, this should just work
448 // on one of them.
450  public:
452  NeighborhoodGeneratorHelper const* helper, const std::string& name)
453  : NeighborhoodGenerator(name, helper) {}
454  Neighborhood Generate(const CpSolverResponse& initial_solution,
455  double difficulty, absl::BitGenRef random) final;
456 };
457 
458 // Pick a random subset of constraints and relax all the variables of these
459 // constraints. Note that to satisfy the difficulty, we might not relax all the
460 // variable of the "last" constraint.
461 //
462 // TODO(user): In the presence of connected components, this should just work
463 // on one of them.
465  public:
467  NeighborhoodGeneratorHelper const* helper, const std::string& name)
468  : NeighborhoodGenerator(name, helper) {}
469  Neighborhood Generate(const CpSolverResponse& initial_solution,
470  double difficulty, absl::BitGenRef random) final;
471 };
472 
473 // Pick a random subset of variables that are constructed by a BFS in the
474 // variable <-> constraint graph. That is, pick a random variable, then all the
475 // variable connected by some constraint to the first one, and so on. The
476 // variable of the last "level" are selected randomly.
477 //
478 // Note that in the presence of connected component, this works correctly
479 // already.
481  public:
483  NeighborhoodGeneratorHelper const* helper, const std::string& name)
484  : NeighborhoodGenerator(name, helper) {}
485  Neighborhood Generate(const CpSolverResponse& initial_solution,
486  double difficulty, absl::BitGenRef random) final;
487 };
488 
489 // Pick a random subset of constraint and relax all of their variables. We are a
490 // bit smarter than this because after the first constraint is selected, we only
491 // select constraints that share at least one variable with the already selected
492 // constraints. The variable from the "last" constraint are selected randomly.
494  public:
496  NeighborhoodGeneratorHelper const* helper, const std::string& name)
497  : NeighborhoodGenerator(name, helper) {}
498  Neighborhood Generate(const CpSolverResponse& initial_solution,
499  double difficulty, absl::BitGenRef random) final;
500 };
501 
502 // Helper method for the scheduling neighborhood generators. Returns the model
503 // as neighborhood for the given set of intervals to relax. For each no_overlap
504 // constraints, it adds strict relation order between the non-relaxed intervals.
506  const absl::Span<const int> intervals_to_relax,
507  const CpSolverResponse& initial_solution,
508  const NeighborhoodGeneratorHelper& helper);
509 
510 // Only make sense for scheduling problem. This select a random set of interval
511 // of the problem according to the difficulty. Then, for each no_overlap
512 // constraints, it adds strict relation order between the non-relaxed intervals.
513 //
514 // TODO(user): Also deal with cumulative constraint.
516  public:
518  NeighborhoodGeneratorHelper const* helper, const std::string& name)
519  : NeighborhoodGenerator(name, helper) {}
520 
521  Neighborhood Generate(const CpSolverResponse& initial_solution,
522  double difficulty, absl::BitGenRef random) final;
523 };
524 
525 // Similar to SchedulingNeighborhoodGenerator except the set of intervals that
526 // are relaxed are from a specific random time interval.
528  public:
530  NeighborhoodGeneratorHelper const* helper, const std::string& name)
531  : NeighborhoodGenerator(name, helper) {}
532 
533  Neighborhood Generate(const CpSolverResponse& initial_solution,
534  double difficulty, absl::BitGenRef random) final;
535 };
536 
537 // This routing based LNS generator will relax random arcs in all the paths of
538 // the circuit or routes constraints.
540  public:
542  const std::string& name)
543  : NeighborhoodGenerator(name, helper) {}
544 
545  Neighborhood Generate(const CpSolverResponse& initial_solution,
546  double difficulty, absl::BitGenRef random) final;
547 };
548 
549 // This routing based LNS generator will relax small sequences of arcs randomly
550 // chosen in all the paths of the circuit or routes constraints.
552  public:
554  const std::string& name)
555  : NeighborhoodGenerator(name, helper) {}
556 
557  Neighborhood Generate(const CpSolverResponse& initial_solution,
558  double difficulty, absl::BitGenRef random) final;
559 };
560 
561 // This routing based LNS generator aims are relaxing one full path, and make
562 // some room on the other paths to absorb the nodes of the relaxed path.
563 //
564 // In order to do so, it will relax the first and the last arc of each path in
565 // the circuit or routes constraints. Then it will relax all arc literals in one
566 // random path. Then it will relax random arcs in the remaining paths until it
567 // reaches the given difficulty.
569  public:
571  NeighborhoodGeneratorHelper const* helper, const std::string& name)
572  : NeighborhoodGenerator(name, helper) {}
573 
574  Neighborhood Generate(const CpSolverResponse& initial_solution,
575  double difficulty, absl::BitGenRef random) final;
576 };
577 
578 // Generates a neighborhood by fixing the variables to solutions reported in
579 // various repositories. This is inspired from RINS published in "Exploring
580 // relaxation induced neighborhoods to improve MIP solutions" 2004 by E. Danna
581 // et.
582 //
583 // If incomplete_solutions is provided, this generates a neighborhood by fixing
584 // the variable values to a solution in the SharedIncompleteSolutionManager and
585 // ignores the other repositories.
586 //
587 // Otherwise, if response_manager is not provided, this generates a neighborhood
588 // using only the linear/general relaxation values. The domain of the variables
589 // are reduced to the integer values around their lp solution/relaxation
590 // solution values. This was published in "RENS – The Relaxation Enforced
591 // Neighborhood" 2009 by Timo Berthold.
593  public:
595  NeighborhoodGeneratorHelper const* helper,
596  const SharedResponseManager* response_manager,
600  const std::string& name)
601  : NeighborhoodGenerator(name, helper),
602  response_manager_(response_manager),
603  relaxation_solutions_(relaxation_solutions),
604  lp_solutions_(lp_solutions),
605  incomplete_solutions_(incomplete_solutions) {
606  CHECK(lp_solutions_ != nullptr || relaxation_solutions_ != nullptr ||
607  incomplete_solutions != nullptr);
608  }
609 
610  // Both initial solution and difficulty values are ignored.
611  Neighborhood Generate(const CpSolverResponse& initial_solution,
612  double difficulty, absl::BitGenRef random) final;
613 
614  // Returns true if the required solutions are available.
615  bool ReadyToGenerate() const override;
616 
617  private:
618  const SharedResponseManager* response_manager_;
619  const SharedRelaxationSolutionRepository* relaxation_solutions_;
620  const SharedLPSolutionRepository* lp_solutions_;
621  SharedIncompleteSolutionManager* incomplete_solutions_;
622 };
623 
624 // Generates a relaxation of the original model by removing a consecutive span
625 // of constraints starting at a random index. The number of constraints removed
626 // is in sync with the difficulty passed to the generator.
628  : public NeighborhoodGenerator {
629  public:
631  NeighborhoodGeneratorHelper const* helper, const std::string& name)
632  : NeighborhoodGenerator(name, helper) {}
633  Neighborhood Generate(const CpSolverResponse& initial_solution,
634  double difficulty, absl::BitGenRef random) final;
635 
636  bool IsRelaxationGenerator() const override { return true; }
637  bool ReadyToGenerate() const override { return true; }
638 };
639 
640 // Generates a relaxation of the original model by removing some constraints
641 // randomly with a given weight for each constraint that controls the
642 // probability of constraint getting removed. The number of constraints removed
643 // is in sync with the difficulty passed to the generator. Higher weighted
644 // constraints are more likely to get removed.
646  : public NeighborhoodGenerator {
647  public:
649  NeighborhoodGeneratorHelper const* helper, const std::string& name);
650 
651  // Generates the neighborhood as described above. Also stores the removed
652  // constraints indices for adjusting the weights.
653  Neighborhood Generate(const CpSolverResponse& initial_solution,
654  double difficulty, absl::BitGenRef random) final;
655 
656  bool IsRelaxationGenerator() const override { return true; }
657  bool ReadyToGenerate() const override { return true; }
658 
659  private:
660  // Adjusts the weights of the constraints removed to get the neighborhood
661  // based on the solve_data.
662  void AdditionalProcessingOnSynchronize(const SolveData& solve_data) override
663  ABSL_EXCLUSIVE_LOCKS_REQUIRED(generator_mutex_);
664 
665  // Higher weighted constraints are more likely to get removed.
666  std::vector<double> constraint_weights_;
667  int num_removable_constraints_ = 0;
668 
669  // Indices of the removed constraints per generated neighborhood.
670  absl::flat_hash_map<int64_t, std::vector<int>> removed_constraints_
671  ABSL_GUARDED_BY(generator_mutex_);
672 
673  // TODO(user): Move this to parent class if other generators start using
674  // feedbacks.
675  int64_t next_available_id_ ABSL_GUARDED_BY(generator_mutex_) = 0;
676 };
677 
678 } // namespace sat
679 } // namespace operations_research
680 
681 #endif // OR_TOOLS_SAT_CP_MODEL_LNS_H_
SchedulingNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const std::string &name)
Definition: cp_model_lns.h:517
#define CHECK(condition)
Definition: base/logging.h:495
VariableGraphNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const std::string &name)
Definition: cp_model_lns.h:482
ConstraintGraphNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const std::string &name)
Definition: cp_model_lns.h:495
Neighborhood GenerateSchedulingNeighborhoodForRelaxation(const absl::Span< const int > intervals_to_relax, const CpSolverResponse &initial_solution, const NeighborhoodGeneratorHelper &helper)
SharedLPSolutionRepository * lp_solutions
Neighborhood RemoveMarkedConstraints(const std::vector< int > &constraints_to_remove) const
NeighborhoodGeneratorHelper(CpModelProto const *model_proto, SatParameters const *parameters, SharedResponseManager *shared_response, SharedTimeLimit *shared_time_limit=nullptr, SharedBoundsManager *shared_bounds=nullptr)
Definition: cp_model_lns.cc:39
Neighborhood FixGivenVariables(const CpSolverResponse &base_solution, const absl::flat_hash_set< int > &variables_to_fix) const
bool IsActive(int var) const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
Neighborhood FixAllVariables(const CpSolverResponse &initial_solution) const
const absl::Span< const int > TypeToConstraints(ConstraintProto::ConstraintCase type) const
Definition: cp_model_lns.h:175
SchedulingTimeWindowNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const std::string &name)
Definition: cp_model_lns.h:529
std::function< void()> GenerateTask(int64_t task_id) override
Definition: cp_model_lns.h:97
std::vector< int > constraints_to_ignore
Definition: cp_model_lns.h:53
RelaxRandomVariablesGenerator(NeighborhoodGeneratorHelper const *helper, const std::string &name)
Definition: cp_model_lns.h:451
bool DifficultyMeansFullNeighborhood(double difficulty) const
Definition: cp_model_lns.h:150
RoutingPathNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const std::string &name)
Definition: cp_model_lns.h:553
const std::vector< int > & ActiveVariablesWhileHoldingLock() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
Definition: cp_model_lns.h:158
void AddSolutionHinting(const CpSolverResponse &initial_solution, CpModelProto *model_proto) const
SharedIncompleteSolutionManager * incomplete_solutions
Definition: cleanup.h:22
const SharedResponseManager & shared_response() const
Definition: cp_model_lns.h:201
virtual void AdditionalProcessingOnSynchronize(const SolveData &solve_data)
Definition: cp_model_lns.h:422
const std::vector< std::vector< int > > & VarToConstraint() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
Definition: cp_model_lns.h:169
ConsecutiveConstraintsRelaxationNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const std::string &name)
Definition: cp_model_lns.h:630
RoutingRandomNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const std::string &name)
Definition: cp_model_lns.h:541
CpModelProto const * model_proto
RoutingFullPathNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const std::string &name)
Definition: cp_model_lns.h:570
std::vector< int > variables_that_can_be_fixed_to_local_optimum
Definition: cp_model_lns.h:78
const std::vector< std::vector< int > > & ConstraintToVar() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
Definition: cp_model_lns.h:165
NeighborhoodGenerator(const std::string &name, NeighborhoodGeneratorHelper const *helper)
Definition: cp_model_lns.h:288
RelaxRandomConstraintsGenerator(NeighborhoodGeneratorHelper const *helper, const std::string &name)
Definition: cp_model_lns.h:466
std::vector< std::vector< int > > GetRoutingPaths(const CpSolverResponse &initial_solution) const
Neighborhood RelaxGivenVariables(const CpSolverResponse &initial_solution, const std::vector< int > &relaxed_variables) const
SharedRelaxationSolutionRepository * relaxation_solutions
Collection of objects used to extend the Constraint Solver library.
SatParameters parameters
IntVar * var
Definition: expr_array.cc:1874
std::vector< int > GetActiveIntervals(const CpSolverResponse &initial_solution) const
const NeighborhoodGeneratorHelper & helper_
Definition: cp_model_lns.h:425
RelaxationInducedNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const SharedResponseManager *response_manager, const SharedRelaxationSolutionRepository *relaxation_solutions, const SharedLPSolutionRepository *lp_solutions, SharedIncompleteSolutionManager *incomplete_solutions, const std::string &name)
Definition: cp_model_lns.h:594