OR-Tools  8.1
bop_base.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 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_base.h"
15 
16 #include <limits>
17 #include <string>
18 #include <vector>
19 
20 #include "absl/synchronization/mutex.h"
22 
23 namespace operations_research {
24 namespace bop {
25 
26 using ::operations_research::sat::LinearBooleanProblem;
27 using ::operations_research::sat::LinearObjective;
28 
30  : name_(name), stats_(name) {
32 }
33 
36 }
37 
39  switch (status) {
41  return "OPTIMAL_SOLUTION_FOUND";
42  case SOLUTION_FOUND:
43  return "SOLUTION_FOUND";
44  case INFEASIBLE:
45  return "INFEASIBLE";
46  case LIMIT_REACHED:
47  return "LIMIT_REACHED";
48  case INFORMATION_FOUND:
49  return "INFORMATION_FOUND";
50  case CONTINUE:
51  return "CONTINUE";
52  case ABORT:
53  return "ABORT";
54  }
55  // Fallback. We don't use "default:" so the compiler will return an error
56  // if we forgot one enum case above.
57  LOG(DFATAL) << "Invalid Status " << static_cast<int>(status);
58  return "UNKNOWN Status";
59 }
60 
61 //------------------------------------------------------------------------------
62 // ProblemState
63 //------------------------------------------------------------------------------
65 
66 ProblemState::ProblemState(const LinearBooleanProblem& problem)
67  : original_problem_(problem),
68  parameters_(),
69  update_stamp_(kInitialStampValue + 1),
70  is_fixed_(problem.num_variables(), false),
71  fixed_values_(problem.num_variables(), false),
72  lp_values_(),
73  solution_(problem, "AllZero"),
74  assignment_preference_(),
75  lower_bound_(kint64min),
76  upper_bound_(kint64max) {
77  // TODO(user): Extract to a function used by all solvers.
78  // Compute trivial unscaled lower bound.
79  const LinearObjective& objective = problem.objective();
80  lower_bound_ = 0;
81  for (int i = 0; i < objective.coefficients_size(); ++i) {
82  // Fix template version for or-tools.
83  lower_bound_ += std::min<int64>(int64{0}, objective.coefficients(i));
84  }
85  upper_bound_ = solution_.IsFeasible() ? solution_.GetCost() : kint64max;
86 }
87 
88 // TODO(user): refactor this to not rely on the optimization status.
89 // All the information can be encoded in the learned_info bounds.
91  const LearnedInfo& learned_info,
92  BopOptimizerBase::Status optimization_status) {
93  const std::string kIndent(25, ' ');
94 
95  bool new_lp_values = false;
96  if (!learned_info.lp_values.empty()) {
97  if (lp_values_ != learned_info.lp_values) {
98  lp_values_ = learned_info.lp_values;
99  new_lp_values = true;
100  VLOG(1) << kIndent + "New LP values.";
101  }
102  }
103 
104  bool new_binary_clauses = false;
105  if (!learned_info.binary_clauses.empty()) {
106  const int old_num = binary_clause_manager_.NumClauses();
107  for (sat::BinaryClause c : learned_info.binary_clauses) {
108  const int num_vars = original_problem_.num_variables();
109  if (c.a.Variable() < num_vars && c.b.Variable() < num_vars) {
110  binary_clause_manager_.Add(c);
111  }
112  }
113  if (binary_clause_manager_.NumClauses() > old_num) {
114  new_binary_clauses = true;
115  VLOG(1) << kIndent + "Num binary clauses: "
116  << binary_clause_manager_.NumClauses();
117  }
118  }
119 
120  bool new_solution = false;
121  if (learned_info.solution.IsFeasible() &&
122  (!solution_.IsFeasible() ||
123  learned_info.solution.GetCost() < solution_.GetCost())) {
124  solution_ = learned_info.solution;
125  new_solution = true;
126  VLOG(1) << kIndent + "New solution.";
127  }
128 
129  bool new_lower_bound = false;
130  if (learned_info.lower_bound > lower_bound()) {
131  lower_bound_ = learned_info.lower_bound;
132  new_lower_bound = true;
133  VLOG(1) << kIndent + "New lower bound.";
134  }
135 
136  if (solution_.IsFeasible()) {
137  upper_bound_ = std::min(upper_bound(), solution_.GetCost());
138  if (upper_bound() <= lower_bound() ||
139  (upper_bound() - lower_bound() <=
140  parameters_.relative_gap_limit() *
141  std::max(std::abs(upper_bound()), std::abs(lower_bound())))) {
142  // The lower bound might be greater that the cost of a feasible solution
143  // due to rounding errors in the problem scaling and Glop.
144  // As a feasible solution was found, the solution is proved optimal.
145  MarkAsOptimal();
146  }
147  }
148 
149  // Merge fixed variables. Note that variables added during search, i.e. not
150  // in the original problem, are ignored.
151  int num_newly_fixed_variables = 0;
152  for (const sat::Literal literal : learned_info.fixed_literals) {
153  const VariableIndex var(literal.Variable().value());
154  if (var >= original_problem_.num_variables()) {
155  continue;
156  }
157  const bool value = literal.IsPositive();
158  if (is_fixed_[var]) {
159  if (fixed_values_[var] != value) {
161  return true;
162  }
163  } else {
164  is_fixed_[var] = true;
165  fixed_values_[var] = value;
166  ++num_newly_fixed_variables;
167  }
168  }
169  if (num_newly_fixed_variables > 0) {
170  int num_fixed_variables = 0;
171  for (const bool is_fixed : is_fixed_) {
172  if (is_fixed) {
173  ++num_fixed_variables;
174  }
175  }
176  VLOG(1) << kIndent << num_newly_fixed_variables
177  << " newly fixed variables (" << num_fixed_variables << " / "
178  << is_fixed_.size() << ").";
179  if (num_fixed_variables == is_fixed_.size()) {
180  // Set the solution to the fixed variables.
181  BopSolution fixed_solution = solution_;
182  for (VariableIndex var(0); var < is_fixed_.size(); ++var) {
183  fixed_solution.SetValue(var, fixed_values_[var]);
184  }
185  if (fixed_solution.IsFeasible()) {
186  solution_ = fixed_solution;
187  }
188  if (solution_.IsFeasible()) {
189  MarkAsOptimal();
190  VLOG(1) << kIndent << "Optimal";
191  } else {
193  }
194  }
195  }
196 
197  bool known_status = false;
198  if (optimization_status == BopOptimizerBase::OPTIMAL_SOLUTION_FOUND) {
199  MarkAsOptimal();
200  known_status = true;
201  } else if (optimization_status == BopOptimizerBase::INFEASIBLE) {
203  known_status = true;
204  }
205 
206  const bool updated = new_lp_values || new_binary_clauses || new_solution ||
207  new_lower_bound || num_newly_fixed_variables > 0 ||
208  known_status;
209  if (updated) ++update_stamp_;
210  return updated;
211 }
212 
214  LearnedInfo learned_info(original_problem_);
215  for (VariableIndex var(0); var < is_fixed_.size(); ++var) {
216  if (is_fixed_[var]) {
217  learned_info.fixed_literals.push_back(
218  sat::Literal(sat::BooleanVariable(var.value()), fixed_values_[var]));
219  }
220  }
221  learned_info.solution = solution_;
222  learned_info.lower_bound = lower_bound();
223  learned_info.lp_values = lp_values_;
224  learned_info.binary_clauses = NewlyAddedBinaryClauses();
225 
226  return learned_info;
227 }
228 
230  CHECK(solution_.IsFeasible());
231  lower_bound_ = upper_bound();
232  ++update_stamp_;
233 }
234 
236  // Mark as infeasible, i.e. set a lower_bound greater than the upper_bound.
237  CHECK(!solution_.IsFeasible());
238  if (upper_bound() == kint64max) {
239  lower_bound_ = kint64max;
240  upper_bound_ = kint64max - 1;
241  } else {
242  lower_bound_ = upper_bound_ - 1;
243  }
244  ++update_stamp_;
245 }
246 
247 const std::vector<sat::BinaryClause>& ProblemState::NewlyAddedBinaryClauses()
248  const {
249  return binary_clause_manager_.newly_added();
250 }
251 
253  binary_clause_manager_.ClearNewlyAdded();
254 }
255 
256 } // namespace bop
257 } // namespace operations_research
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::sat::Literal::Variable
BooleanVariable Variable() const
Definition: sat_base.h:80
min
int64 min
Definition: alldiff_cst.cc:138
VLOG
#define VLOG(verboselevel)
Definition: base/logging.h:978
operations_research::bop::BopOptimizerBase::SOLUTION_FOUND
@ SOLUTION_FOUND
Definition: bop_base.h:63
operations_research::sat::BinaryClauseManager::Add
bool Add(BinaryClause c)
Definition: clause.h:391
max
int64 max
Definition: alldiff_cst.cc:139
IF_STATS_ENABLED
#define IF_STATS_ENABLED(instructions)
Definition: stats.h:435
LOG
#define LOG(severity)
Definition: base/logging.h:420
absl::StrongVector::size
size_type size() const
Definition: strong_vector.h:147
operations_research::bop::ProblemState::lower_bound
int64 lower_bound() const
Definition: bop_base.h:206
operations_research::bop::ProblemState::upper_bound
int64 upper_bound() const
Definition: bop_base.h:207
operations_research::bop::BopOptimizerBase::LIMIT_REACHED
@ LIMIT_REACHED
Definition: bop_base.h:65
operations_research::bop::ProblemState::MarkAsInfeasible
void MarkAsInfeasible()
Definition: bop_base.cc:235
operations_research::sat::BinaryClauseManager::newly_added
const std::vector< BinaryClause > & newly_added() const
Definition: clause.h:403
value
int64 value
Definition: demon_profiler.cc:43
operations_research::bop::BopOptimizerBase::BopOptimizerBase
BopOptimizerBase(const std::string &name)
Definition: bop_base.cc:29
operations_research::bop::LearnedInfo::solution
BopSolution solution
Definition: bop_base.h:266
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
operations_research::bop::BopOptimizerBase::INFORMATION_FOUND
@ INFORMATION_FOUND
Definition: bop_base.h:72
kint64min
static const int64 kint64min
Definition: integral_types.h:60
int64
int64_t int64
Definition: integral_types.h:34
operations_research::bop::ProblemState::SynchronizationDone
void SynchronizationDone()
Definition: bop_base.cc:252
operations_research::bop::BopOptimizerBase::~BopOptimizerBase
virtual ~BopOptimizerBase()
Definition: bop_base.cc:34
operations_research::bop::ProblemState::ProblemState
ProblemState(const sat::LinearBooleanProblem &problem)
Definition: bop_base.cc:66
operations_research::bop::BopOptimizerBase::GetStatusString
static std::string GetStatusString(Status status)
Definition: bop_base.cc:38
operations_research::bop::BopSolution
Definition: bop_solution.h:31
operations_research::sat::BinaryClauseManager::NumClauses
int NumClauses() const
Definition: clause.h:387
SCOPED_TIME_STAT
#define SCOPED_TIME_STAT(stats)
Definition: stats.h:436
operations_research::bop::BopOptimizerBase::stats_
StatsGroup stats_
Definition: bop_base.h:100
operations_research::bop::LearnedInfo::fixed_literals
std::vector< sat::Literal > fixed_literals
Definition: bop_base.h:263
operations_research::bop::ProblemState::is_fixed
const absl::StrongVector< VariableIndex, bool > & is_fixed() const
Definition: bop_base.h:173
operations_research::bop::BopOptimizerBase::INFEASIBLE
@ INFEASIBLE
Definition: bop_base.h:64
operations_research::bop::LearnedInfo
Definition: bop_base.h:245
operations_research::bop::LearnedInfo::binary_clauses
std::vector< sat::BinaryClause > binary_clauses
Definition: bop_base.h:278
operations_research::sat::BinaryClause
Definition: clause.h:375
operations_research::bop::ProblemState::NewlyAddedBinaryClauses
const std::vector< sat::BinaryClause > & NewlyAddedBinaryClauses() const
Definition: bop_base.cc:247
operations_research::bop::BopOptimizerBase::OPTIMAL_SOLUTION_FOUND
@ OPTIMAL_SOLUTION_FOUND
Definition: bop_base.h:62
operations_research::bop::LearnedInfo::lower_bound
int64 lower_bound
Definition: bop_base.h:269
operations_research::sat::Literal
Definition: sat_base.h:64
operations_research::bop::ProblemState::MarkAsOptimal
void MarkAsOptimal()
Definition: bop_base.cc:229
operations_research::bop::LearnedInfo::lp_values
glop::DenseRow lp_values
Definition: bop_base.h:275
operations_research::sat::BinaryClause::b
Literal b
Definition: clause.h:380
operations_research::bop::BopSolution::IsFeasible
bool IsFeasible() const
Definition: bop_solution.h:69
operations_research::bop::ProblemState::MergeLearnedInfo
bool MergeLearnedInfo(const LearnedInfo &learned_info, BopOptimizerBase::Status optimization_status)
Definition: bop_base.cc:90
operations_research::sat::BinaryClause::a
Literal a
Definition: clause.h:379
boolean_problem.h
operations_research::bop::ProblemState::GetLearnedInfo
LearnedInfo GetLearnedInfo() const
Definition: bop_base.cc:213
bop_base.h
operations_research::bop::BopOptimizerBase::CONTINUE
@ CONTINUE
Definition: bop_base.h:76
operations_research::bop::BopSolution::GetCost
int64 GetCost() const
Definition: bop_solution.h:50
operations_research::StatsGroup::StatString
std::string StatString() const
Definition: stats.cc:71
literal
Literal literal
Definition: optimization.cc:84
absl::StrongVector::empty
bool empty() const
Definition: strong_vector.h:156
operations_research::bop::BopOptimizerBase::Status
Status
Definition: bop_base.h:61
operations_research::bop::ProblemState::kInitialStampValue
static const int64 kInitialStampValue
Definition: bop_base.h:152
operations_research::sat::BinaryClauseManager::ClearNewlyAdded
void ClearNewlyAdded()
Definition: clause.h:404
CHECK
#define CHECK(condition)
Definition: base/logging.h:495
name
const std::string name
Definition: default_search.cc:808
operations_research::bop::BopOptimizerBase::ABORT
@ ABORT
Definition: bop_base.h:79
operations_research::bop::BopSolution::SetValue
void SetValue(VariableIndex var, bool value)
Definition: bop_solution.h:36
kint64max
static const int64 kint64max
Definition: integral_types.h:62