OR-Tools  9.6
bop_util.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 
14 #include "ortools/bop/bop_util.h"
15 
16 #include <algorithm>
17 #include <limits>
18 #include <vector>
19 
22 #include "ortools/bop/bop_base.h"
25 #include "ortools/sat/sat_solver.h"
26 
27 namespace operations_research {
28 namespace bop {
29 namespace {
30 static const int kMaxLubyIndex = 30;
31 static const int kMaxBoost = 30;
32 
33 // Loads the problem state into the SAT solver. If the problem has already been
34 // loaded in the sat_solver, fixed variables and objective bounds are updated.
35 // Returns false when the problem is proved UNSAT.
36 bool InternalLoadStateProblemToSatSolver(const ProblemState& problem_state,
37  sat::SatSolver* sat_solver) {
38  const bool first_time = (sat_solver->NumVariables() == 0);
39  if (first_time) {
40  sat_solver->SetNumVariables(
41  problem_state.original_problem().num_variables());
42  } else {
43  // Backtrack the solver to be able to add new constraints.
44  sat_solver->Backtrack(0);
45  }
46 
47  // Set the fixed variables first so that loading the problem will be faster.
48  for (VariableIndex var(0); var < problem_state.is_fixed().size(); ++var) {
49  if (problem_state.is_fixed()[var]) {
50  if (!sat_solver->AddUnitClause(
51  sat::Literal(sat::BooleanVariable(var.value()),
52  problem_state.fixed_values()[var]))) {
53  return false;
54  }
55  }
56  }
57 
58  // Load the problem if not done yet.
59  if (first_time &&
60  !LoadBooleanProblem(problem_state.original_problem(), sat_solver)) {
61  return false;
62  }
63 
64  // Constrain the objective cost to be greater or equal to the lower bound,
65  // and to be smaller than the upper bound. If enforcing the strictier upper
66  // bound constraint leads to an UNSAT problem, it means the current solution
67  // is proved optimal (if the solution is feasible, else the problem is proved
68  // infeasible).
70  problem_state.original_problem(),
71  problem_state.lower_bound() != std::numeric_limits<int64_t>::min(),
72  sat::Coefficient(problem_state.lower_bound()),
73  problem_state.upper_bound() != std::numeric_limits<int64_t>::max(),
74  sat::Coefficient(problem_state.upper_bound() - 1), sat_solver)) {
75  return false;
76  }
77 
78  // Adds the new binary clauses.
79  sat_solver->TrackBinaryClauses(true);
80  if (!sat_solver->AddBinaryClauses(problem_state.NewlyAddedBinaryClauses())) {
81  return false;
82  }
83  sat_solver->ClearNewlyAddedBinaryClauses();
84 
85  return true;
86 }
87 } // anonymous namespace
88 
90  const ProblemState& problem_state, sat::SatSolver* sat_solver) {
91  if (InternalLoadStateProblemToSatSolver(problem_state, sat_solver)) {
93  }
94 
95  return problem_state.solution().IsFeasible()
98 }
99 
101  LearnedInfo* info) {
102  CHECK(nullptr != solver);
103  CHECK(nullptr != info);
104 
105  // This should never be called if the problem is UNSAT.
106  CHECK(!solver->IsModelUnsat());
107 
108  // Fixed variables.
109  info->fixed_literals.clear();
110  const sat::Trail& propagation_trail = solver->LiteralTrail();
111  const int root_size = solver->CurrentDecisionLevel() == 0
112  ? propagation_trail.Index()
113  : solver->Decisions().front().trail_index;
114  for (int trail_index = 0; trail_index < root_size; ++trail_index) {
115  info->fixed_literals.push_back(propagation_trail[trail_index]);
116  }
117 
118  // Binary clauses.
119  info->binary_clauses = solver->NewlyAddedBinaryClauses();
121 }
122 
124  BopSolution* solution) {
125  CHECK(solution != nullptr);
126 
127  // Only extract the variables of the initial problem.
128  CHECK_LE(solution->Size(), assignment.NumberOfVariables());
129  for (sat::BooleanVariable var(0); var < solution->Size(); ++var) {
130  CHECK(assignment.VariableIsAssigned(var));
131  const bool value = assignment.LiteralIsTrue(sat::Literal(var, true));
132  const VariableIndex bop_var_id(var.value());
133  solution->SetValue(bop_var_id, value);
134  }
135 }
136 
137 //------------------------------------------------------------------------------
138 // AdaptiveParameterValue
139 //------------------------------------------------------------------------------
141  : value_(initial_value), num_changes_(0) {}
142 
143 void AdaptiveParameterValue::Reset() { num_changes_ = 0; }
144 
146  ++num_changes_;
147  const double factor = 1.0 + 1.0 / (num_changes_ / 2.0 + 1);
148  value_ = std::min(1.0 - (1.0 - value_) / factor, value_ * factor);
149 }
150 
152  ++num_changes_;
153  const double factor = 1.0 + 1.0 / (num_changes_ / 2.0 + 1);
154  value_ = std::max(value_ / factor, 1.0 - (1.0 - value_) * factor);
155 }
156 
157 //------------------------------------------------------------------------------
158 // LubyAdaptiveParameterValue
159 //------------------------------------------------------------------------------
161  : luby_id_(0),
162  luby_boost_(0),
163  luby_value_(0),
164  difficulties_(kMaxLubyIndex, AdaptiveParameterValue(initial_value)) {
165  Reset();
166 }
167 
169  luby_id_ = 0;
170  luby_boost_ = 0;
171  luby_value_ = 0;
172  for (int i = 0; i < difficulties_.size(); ++i) {
173  difficulties_[i].Reset();
174  }
175 }
176 
178  const int luby_msb = MostSignificantBitPosition64(luby_value_);
179  difficulties_[luby_msb].Increase();
180 }
181 
183  const int luby_msb = MostSignificantBitPosition64(luby_value_);
184  difficulties_[luby_msb].Decrease();
185 }
186 
188  const int luby_msb = MostSignificantBitPosition64(luby_value_);
189  return difficulties_[luby_msb].value();
190 }
191 
193  ++luby_boost_;
194  return luby_boost_ >= kMaxBoost;
195 }
196 
198  ++luby_id_;
199  luby_value_ = sat::SUniv(luby_id_) << luby_boost_;
200 }
201 } // namespace bop
202 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
void SetValue(VariableIndex var, bool value)
Definition: bop_solution.h:40
const BopSolution & solution() const
Definition: bop_base.h:199
const Trail & LiteralTrail() const
Definition: sat_solver.h:387
const std::vector< BinaryClause > & NewlyAddedBinaryClauses()
Definition: sat_solver.cc:1043
const std::vector< Decision > & Decisions() const
Definition: sat_solver.h:385
bool VariableIsAssigned(BooleanVariable var) const
Definition: sat_base.h:172
bool LiteralIsTrue(Literal literal) const
Definition: sat_base.h:164
int64_t value
IntVar * var
Definition: expr_array.cc:1874
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
bool AddObjectiveConstraint(const LinearBooleanProblem &problem, bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, SatSolver *solver)
bool LoadBooleanProblem(const LinearBooleanProblem &problem, SatSolver *solver)
Collection of objects used to extend the Constraint Solver library.
int MostSignificantBitPosition64(uint64_t n)
Definition: bitset.h:232
std::vector< sat::Literal > fixed_literals
Definition: bop_base.h:269
std::vector< sat::BinaryClause > binary_clauses
Definition: bop_base.h:284