OR-Tools  9.6
complete_optimizer.cc
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 
15 
16 #include <algorithm>
17 #include <cstdint>
18 #include <string>
19 #include <vector>
20 
21 #include "ortools/bop/bop_util.h"
23 
24 namespace operations_research {
25 namespace bop {
26 
29  state_update_stamp_(ProblemState::kInitialStampValue),
30  initialized_(false),
31  assumptions_already_added_(false) {
32  // This is in term of number of variables not at their minimal value.
33  lower_bound_ = sat::Coefficient(0);
34  upper_bound_ = sat::kCoefficientMax;
35 }
36 
38 
39 BopOptimizerBase::Status SatCoreBasedOptimizer::SynchronizeIfNeeded(
40  const ProblemState& problem_state) {
41  if (state_update_stamp_ == problem_state.update_stamp()) {
43  }
44  state_update_stamp_ = problem_state.update_stamp();
45 
46  // Note that if the solver is not empty, this only load the newly learned
47  // information.
49  LoadStateProblemToSatSolver(problem_state, &solver_);
51 
52  if (!initialized_) {
53  // Initialize the algorithm.
55  problem_state.original_problem().objective(), &offset_, &repository_);
56  initialized_ = true;
57 
58  // This is used by the "stratified" approach.
59  stratified_lower_bound_ = sat::Coefficient(0);
60  for (sat::EncodingNode* n : nodes_) {
61  stratified_lower_bound_ = std::max(stratified_lower_bound_, n->weight());
62  }
63  }
64 
65  // Extract the new upper bound.
66  if (problem_state.solution().IsFeasible()) {
67  upper_bound_ = problem_state.solution().GetCost() + offset_;
68  }
70 }
71 
72 sat::SatSolver::Status SatCoreBasedOptimizer::SolveWithAssumptions() {
73  const std::vector<sat::Literal> assumptions =
75  stratified_lower_bound_,
76  &lower_bound_, &nodes_, &solver_);
77  return solver_.ResetAndSolveWithGivenAssumptions(assumptions);
78 }
79 
80 // Only run this if there is an objective.
82  const ProblemState& problem_state) const {
83  return problem_state.original_problem().objective().literals_size() > 0;
84 }
85 
87  const BopParameters& parameters, const ProblemState& problem_state,
88  LearnedInfo* learned_info, TimeLimit* time_limit) {
90  CHECK(learned_info != nullptr);
91  CHECK(time_limit != nullptr);
92  learned_info->Clear();
93 
94  const BopOptimizerBase::Status sync_status =
95  SynchronizeIfNeeded(problem_state);
96  if (sync_status != BopOptimizerBase::CONTINUE) {
97  return sync_status;
98  }
99 
100  int64_t conflict_limit = parameters.max_number_of_conflicts_in_random_lns();
101  double deterministic_time_at_last_sync = solver_.deterministic_time();
102  while (!time_limit->LimitReached()) {
103  sat::SatParameters sat_params = solver_.parameters();
104  sat_params.set_max_time_in_seconds(time_limit->GetTimeLeft());
105  sat_params.set_max_deterministic_time(
106  time_limit->GetDeterministicTimeLeft());
107  sat_params.set_random_seed(parameters.random_seed());
108  sat_params.set_max_number_of_conflicts(conflict_limit);
109  solver_.SetParameters(sat_params);
110 
111  const int64_t old_num_conflicts = solver_.num_failures();
112  const sat::SatSolver::Status sat_status =
113  assumptions_already_added_ ? solver_.Solve() : SolveWithAssumptions();
114  time_limit->AdvanceDeterministicTime(solver_.deterministic_time() -
115  deterministic_time_at_last_sync);
116  deterministic_time_at_last_sync = solver_.deterministic_time();
117 
118  assumptions_already_added_ = true;
119  conflict_limit -= solver_.num_failures() - old_num_conflicts;
120  learned_info->lower_bound = lower_bound_.value() - offset_.value();
121 
122  // This is possible because we over-constrain the objective.
123  if (sat_status == sat::SatSolver::INFEASIBLE) {
124  return problem_state.solution().IsFeasible()
127  }
128 
129  ExtractLearnedInfoFromSatSolver(&solver_, learned_info);
130  if (sat_status == sat::SatSolver::LIMIT_REACHED || conflict_limit < 0) {
132  }
133  if (sat_status == sat::SatSolver::FEASIBLE) {
134  stratified_lower_bound_ =
135  MaxNodeWeightSmallerThan(nodes_, stratified_lower_bound_);
136 
137  // We found a better solution!
138  SatAssignmentToBopSolution(solver_.Assignment(), &learned_info->solution);
139  if (stratified_lower_bound_ > 0) {
140  assumptions_already_added_ = false;
142  }
144  }
145 
146  // The interesting case: we have a core.
147  // TODO(user): Check that this cannot fail because of the conflict limit.
148  std::vector<sat::Literal> core = solver_.GetLastIncompatibleDecisions();
149  sat::MinimizeCore(&solver_, &core);
150 
151  const sat::Coefficient min_weight = sat::ComputeCoreMinWeight(nodes_, core);
152  sat::ProcessCore(core, min_weight, &repository_, &nodes_, &solver_);
153  assumptions_already_added_ = false;
154  }
156 }
157 
158 } // namespace bop
159 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
const sat::LinearBooleanProblem & original_problem() const
Definition: bop_base.h:204
const BopSolution & solution() const
Definition: bop_base.h:199
bool ShouldBeRun(const ProblemState &problem_state) const override
Status Optimize(const BopParameters &parameters, const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override
const SatParameters & parameters() const
Definition: sat_solver.cc:132
Status ResetAndSolveWithGivenAssumptions(const std::vector< Literal > &assumptions)
Definition: sat_solver.cc:1058
const VariablesAssignment & Assignment() const
Definition: sat_solver.h:388
void SetParameters(const SatParameters &parameters)
Definition: sat_solver.cc:137
std::vector< Literal > GetLastIncompatibleDecisions()
Definition: sat_solver.cc:1386
SatParameters parameters
ModelSharedTimeLimit * time_limit
const std::string name
absl::Status status
Definition: g_gurobi.cc:41
BopOptimizerBase::Status LoadStateProblemToSatSolver(const ProblemState &problem_state, sat::SatSolver *sat_solver)
Definition: bop_util.cc:89
void SatAssignmentToBopSolution(const sat::VariablesAssignment &assignment, BopSolution *solution)
Definition: bop_util.cc:123
void ExtractLearnedInfoFromSatSolver(sat::SatSolver *solver, LearnedInfo *info)
Definition: bop_util.cc:100
std::tuple< int64_t, int64_t, const double > Coefficient
Coefficient ComputeCoreMinWeight(const std::vector< EncodingNode * > &nodes, const std::vector< Literal > &core)
Definition: encoding.cc:525
std::vector< Literal > ReduceNodesAndExtractAssumptions(Coefficient upper_bound, Coefficient stratified_lower_bound, Coefficient *lower_bound, std::vector< EncodingNode * > *nodes, SatSolver *solver)
Definition: encoding.cc:471
void MinimizeCore(SatSolver *solver, std::vector< Literal > *core)
Definition: sat_solver.cc:2666
bool ProcessCore(const std::vector< Literal > &core, Coefficient min_weight, std::deque< EncodingNode > *repository, std::vector< EncodingNode * > *nodes, SatSolver *solver)
Definition: encoding.cc:551
Coefficient MaxNodeWeightSmallerThan(const std::vector< EncodingNode * > &nodes, Coefficient upper_bound)
Definition: encoding.cc:539
std::vector< EncodingNode * > CreateInitialEncodingNodes(const std::vector< Literal > &literals, const std::vector< Coefficient > &coeffs, Coefficient *offset, std::deque< EncodingNode > *repository)
Definition: encoding.cc:409
const Coefficient kCoefficientMax(std::numeric_limits< Coefficient::ValueType >::max())
Collection of objects used to extend the Constraint Solver library.
#define SCOPED_TIME_STAT(stats)
Definition: stats.h:439