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