14#ifndef OR_TOOLS_SAT_CP_MODEL_LNS_H_
15#define OR_TOOLS_SAT_CP_MODEL_LNS_H_
25#include "absl/base/thread_annotations.h"
26#include "absl/container/flat_hash_set.h"
27#include "absl/log/check.h"
28#include "absl/random/bit_gen_ref.h"
29#include "absl/strings/string_view.h"
30#include "absl/synchronization/mutex.h"
31#include "absl/types/span.h"
32#include "google/protobuf/arena.h"
33#include "ortools/sat/cp_model.pb.h"
36#include "ortools/sat/sat_parameters.pb.h"
111 const CpSolverResponse& base_solution,
112 const absl::flat_hash_set<int>& variables_to_fix)
const;
117 const CpSolverResponse& initial_solution,
118 const std::vector<int>& relaxed_variables)
const;
134 CpModelProto* model_proto)
const;
143 std::vector<int> result;
145 result = active_variables_;
151 return active_variables_.size();
155 std::vector<int> result;
157 result = active_objective_variables_;
163 const int target_size =
164 static_cast<int>(std::ceil(difficulty * active_variables_.size()));
165 return target_size == active_variables_.size();
172 return active_variables_;
179 std::vector<int> result;
180 result = active_objective_variables_;
190 return constraint_to_var_;
194 return var_to_constraint_;
199 ConstraintProto::ConstraintCase
type)
const {
200 if (
type >= type_to_constraints_.size())
return {};
201 return absl::MakeSpan(type_to_constraints_[
type]);
207 absl::Span<const int> unfiltered_intervals,
208 const CpSolverResponse& initial_solution)
const;
215 const CpSolverResponse& initial_solution)
const;
223 const CpSolverResponse& initial_solution)
const;
235 const CpSolverResponse& initial_solution)
const;
241 const absl::flat_hash_set<int>& ignored_intervals,
242 const CpSolverResponse& initial_solution, absl::BitGenRef random)
const;
249 const CpModelProto&
ModelProto()
const {
return model_proto_; }
250 const SatParameters&
Parameters()
const {
return parameters_; }
253 return *shared_response_;
270 void InitializeHelperData();
274 void RecomputeHelperData();
277 bool IsConstant(
int var)
const ABSL_SHARED_LOCKS_REQUIRED(domain_mutex_);
281 bool ObjectiveDomainIsConstraining() const
282 ABSL_SHARED_LOCKS_REQUIRED(domain_mutex_);
287 bool IntervalIsActive(
int index,
288 const CpSolverResponse& initial_solution) const
289 ABSL_SHARED_LOCKS_REQUIRED(domain_mutex_);
291 const SatParameters& parameters_;
292 const CpModelProto& model_proto_;
293 int shared_bounds_id_;
300 google::protobuf::Arena local_arena_;
307 CpModelProto* model_proto_with_only_variables_ ABSL_GUARDED_BY(domain_mutex_);
310 std::vector<
std::vector<
int>> type_to_constraints_;
314 std::vector<
bool> is_in_objective_;
319 CpModelProto* simplified_model_proto_ ABSL_GUARDED_BY(
graph_mutex_);
335 std::vector<
int> var_to_component_index_ ABSL_GUARDED_BY(
graph_mutex_);
344 std::vector<
int> active_objective_variables_ ABSL_GUARDED_BY(
graph_mutex_);
346 std::vector<
int> tmp_row_;
348 mutable
absl::Mutex domain_mutex_;
356 : name_(
name), helper_(*helper), difficulty_(0.5) {}
374 double difficulty, absl::BitGenRef random) = 0;
377 virtual bool ReadyToGenerate()
const;
387 double GetUCBScore(int64_t total_num_calls)
const;
392 CpSolverStatus
status = CpSolverStatus::UNKNOWN;
395 double difficulty = 0.0;
398 double deterministic_limit = 0.0;
401 double deterministic_time = 0.0;
412 IntegerValue initial_best_objective = IntegerValue(0);
413 IntegerValue base_objective = IntegerValue(0);
414 IntegerValue new_objective = IntegerValue(0);
418 return std::tie(
status, difficulty, deterministic_limit,
419 deterministic_time, initial_best_objective,
420 base_objective, new_objective) <
427 absl::MutexLock mutex_lock(&generator_mutex_);
428 solve_data_.push_back(data);
437 std::string
name()
const {
return name_; }
441 absl::MutexLock mutex_lock(&generator_mutex_);
447 absl::MutexLock mutex_lock(&generator_mutex_);
448 return num_fully_solved_calls_;
453 absl::MutexLock mutex_lock(&generator_mutex_);
454 return num_improving_calls_;
461 absl::MutexLock mutex_lock(&generator_mutex_);
462 return num_consecutive_non_improving_calls_;
467 absl::MutexLock mutex_lock(&generator_mutex_);
468 return difficulty_.value();
473 absl::MutexLock mutex_lock(&generator_mutex_);
474 return deterministic_limit_;
483 std::vector<SolveData> solve_data_;
488 double deterministic_limit_ = 0.1;
492 int64_t num_calls_ = 0;
493 int64_t num_fully_solved_calls_ = 0;
494 int64_t num_improving_calls_ = 0;
495 int64_t num_consecutive_non_improving_calls_ = 0;
496 int64_t next_time_limit_bump_ = 50;
497 double current_average_ = 0.0;
509 Neighborhood Generate(
const CpSolverResponse& initial_solution,
510 double difficulty, absl::BitGenRef random)
final;
524 Neighborhood Generate(
const CpSolverResponse& initial_solution,
525 double difficulty, absl::BitGenRef random)
final;
540 Neighborhood Generate(
const CpSolverResponse& initial_solution,
541 double difficulty, absl::BitGenRef random)
final;
551 Neighborhood Generate(
const CpSolverResponse& initial_solution,
552 double difficulty, absl::BitGenRef random)
final;
564 Neighborhood Generate(
const CpSolverResponse& initial_solution,
565 double difficulty, absl::BitGenRef random)
final;
584 Neighborhood Generate(
const CpSolverResponse& initial_solution,
585 double difficulty, absl::BitGenRef random)
final;
601 std::function<
void(CpModelProto,
Model*)> solve_callback,
604 solve_callback_(
std::move(solve_callback)),
605 global_time_limit_(global_time_limit) {}
606 Neighborhood Generate(
const CpSolverResponse& initial_solution,
607 double difficulty, absl::BitGenRef random)
final;
610 const std::function<void(CpModelProto,
Model*)> solve_callback_;
619 absl::Span<const int> intervals_to_relax,
620 absl::Span<const int> variables_to_fix,
621 const CpSolverResponse& initial_solution, absl::BitGenRef random,
628 absl::Span<
const std::pair<int, int>> precedences,
629 const CpSolverResponse& initial_solution,
642 Neighborhood Generate(
const CpSolverResponse& initial_solution,
643 double difficulty, absl::BitGenRef random)
final;
658 Neighborhood Generate(
const CpSolverResponse& initial_solution,
659 double difficulty, absl::BitGenRef random)
final;
670 Neighborhood Generate(
const CpSolverResponse& initial_solution,
671 double difficulty, absl::BitGenRef random)
final;
682 const std::vector<std::vector<int>>& intervals_in_constraints,
683 absl::string_view
name)
685 intervals_in_constraints_(intervals_in_constraints) {}
687 Neighborhood Generate(
const CpSolverResponse& initial_solution,
688 double difficulty, absl::BitGenRef random)
final;
691 const std::vector<std::vector<int>> intervals_in_constraints_;
704 Neighborhood Generate(
const CpSolverResponse& initial_solution,
705 double difficulty, absl::BitGenRef random)
final;
719 Neighborhood Generate(
const CpSolverResponse& initial_solution,
720 double difficulty, absl::BitGenRef random)
final;
732 Neighborhood Generate(
const CpSolverResponse& initial_solution,
733 double difficulty, absl::BitGenRef random)
final;
741 absl::string_view
name)
744 Neighborhood Generate(
const CpSolverResponse& initial_solution,
745 double difficulty, absl::BitGenRef random)
final;
753 absl::string_view
name)
756 Neighborhood Generate(
const CpSolverResponse& initial_solution,
757 double difficulty, absl::BitGenRef random)
final;
773 Neighborhood Generate(
const CpSolverResponse& initial_solution,
774 double difficulty, absl::BitGenRef random)
final;
798 absl::string_view
name)
800 response_manager_(response_manager),
801 lp_solutions_(lp_solutions),
802 incomplete_solutions_(incomplete_solutions) {
803 CHECK(lp_solutions_ !=
nullptr);
804 CHECK(incomplete_solutions !=
nullptr);
808 Neighborhood Generate(
const CpSolverResponse& initial_solution,
809 double difficulty, absl::BitGenRef random)
final;
812 bool ReadyToGenerate()
const override;
ArcGraphNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
ConstraintGraphNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
DecompositionGraphNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
LocalBranchingLpBasedNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name, std::function< void(CpModelProto, Model *)> solve_callback, ModelSharedTimeLimit *const global_time_limit)
The model "singleton" shared time limit.
Neighborhood FullNeighborhood() const
Returns a neighborhood that correspond to the full problem.
bool IsActive(int var) const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
CpModelProto UpdatedModelProtoCopy() const
Returns a copy of the problem proto with updated domains.
Neighborhood RelaxGivenVariables(const CpSolverResponse &initial_solution, const std::vector< int > &relaxed_variables) const
Neighborhood FixAllVariables(const CpSolverResponse &initial_solution) const
Neighborhood FixGivenVariables(const CpSolverResponse &base_solution, const absl::flat_hash_set< int > &variables_to_fix) const
Neighborhood NoNeighborhood() const
const std::vector< int > & ActiveVariablesWhileHoldingLock() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
const CompactVectorVector< int, int > & VarToConstraint() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
int NumActiveVariables() const
std::vector< std::pair< int, int > > GetActiveRectangles(const CpSolverResponse &initial_solution) const
const SharedResponseManager & shared_response() const
void Synchronize() override
NeighborhoodGeneratorHelper(CpModelProto const *model_proto, SatParameters const *parameters, SharedResponseManager *shared_response, SharedBoundsManager *shared_bounds=nullptr)
std::vector< int > ActiveVariables() const
Returns the list of "active" variables.
std::vector< std::vector< int > > GetUniqueIntervalSets() const
const CompactVectorVector< int, int > & ConstraintToVar() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
bool DifficultyMeansFullNeighborhood(double difficulty) const
const CpModelProto & ModelProto() const
void AddSolutionHinting(const CpSolverResponse &initial_solution, CpModelProto *model_proto) const
std::vector< std::vector< int > > GetRoutingPaths(const CpSolverResponse &initial_solution) const
std::vector< int > ActiveObjectiveVariablesWhileHoldingLock() const ABSL_SHARED_LOCKS_REQUIRED(graph_mutex_)
std::function< void()> GenerateTask(int64_t) override
const SatParameters & Parameters() const
std::vector< int > GetActiveIntervals(const CpSolverResponse &initial_solution) const
std::vector< std::pair< int, int > > GetSchedulingPrecedences(const absl::flat_hash_set< int > &ignored_intervals, const CpSolverResponse &initial_solution, absl::BitGenRef random) const
absl::Span< const int > TypeToConstraints(ConstraintProto::ConstraintCase type) const
Returns all the constraints indices of a given type.
bool TaskIsAvailable() override
SubSolver interface.
std::vector< int > ActiveObjectiveVariables() const
std::vector< int > KeepActiveIntervals(absl::Span< const int > unfiltered_intervals, const CpSolverResponse &initial_solution) const
Base class for a CpModelProto neighborhood generator.
virtual Neighborhood Generate(const CpSolverResponse &initial_solution, double difficulty, absl::BitGenRef random)=0
double deterministic_limit() const
The current time limit that the sub-solve should use on this generator.
int64_t num_improving_calls() const
Out of num_calls(), how many improved the given solution.
void AddSolveData(SolveData data)
std::string name() const
Returns a short description of the generator.
virtual ~NeighborhoodGenerator()=default
absl::Mutex generator_mutex_
double difficulty() const
The current difficulty of this generator.
int64_t num_calls() const
Number of times this generator was called.
const NeighborhoodGeneratorHelper & helper_
int64_t num_fully_solved_calls() const
Number of time the neighborhood was fully solved (OPTIMAL/INFEASIBLE).
int64_t num_consecutive_non_improving_calls() const
NeighborhoodGenerator(absl::string_view name, NeighborhoodGeneratorHelper const *helper)
RandomIntervalSchedulingNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
RandomPrecedenceSchedulingNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
RandomPrecedencesPackingNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
RandomRectanglesPackingNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
RelaxRandomConstraintsGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
RelaxRandomVariablesGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
RelaxationInducedNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const SharedResponseManager *response_manager, const SharedLPSolutionRepository *lp_solutions, SharedIncompleteSolutionManager *incomplete_solutions, absl::string_view name)
RoutingFullPathNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
RoutingPathNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
RoutingRandomNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
SchedulingResourceWindowsNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, const std::vector< std::vector< int > > &intervals_in_constraints, absl::string_view name)
SchedulingTimeWindowNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
SlicePackingNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
SubsolverType type() const
Returns the type of the subsolver.
std::string name() const
Returns the name of this SubSolver. Used in logs.
VariableGraphNeighborhoodGenerator(NeighborhoodGeneratorHelper const *helper, absl::string_view name)
const std::string name
A name for logging purposes.
Neighborhood GenerateSchedulingNeighborhoodFromIntervalPrecedences(const absl::Span< const std::pair< int, int > > precedences, const CpSolverResponse &initial_solution, const NeighborhoodGeneratorHelper &helper)
Neighborhood GenerateSchedulingNeighborhoodFromRelaxedIntervals(absl::Span< const int > intervals_to_relax, absl::Span< const int > variables_to_fix, const CpSolverResponse &initial_solution, absl::BitGenRef random, const NeighborhoodGeneratorHelper &helper)
In SWIG mode, we don't want anything besides these top-level includes.
Adds solve data about one "solved" neighborhood.
double deterministic_time
The time it took to solve this neighborhood.
IntegerValue initial_best_objective
IntegerValue new_objective
double difficulty
The difficulty when this neighborhood was generated.
double deterministic_limit
The deterministic time limit given to the solver for this neighborhood.
CpSolverStatus status
The status of the sub-solve.
bool operator<(const SolveData &o) const
This is just used to construct a deterministic order for the updates.
IntegerValue base_objective
Neighborhood returned by Neighborhood generators.
int num_relaxed_variables_in_objective
std::string source_info
Overwrites the name of the neighborhood generator in the logs.
bool is_simple
True if this neighborhood was just obtained by fixing some variables.
int num_relaxed_variables
Statistic, only filled when is_simple is true.
bool is_generated
True if neighborhood generator was able to generate a neighborhood.
std::vector< int > variables_that_can_be_fixed_to_local_optimum