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