OR-Tools  9.6
bop_fs.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_fs.h"
15 
16 #include <algorithm>
17 #include <cstdint>
18 #include <limits>
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/memory/memory.h"
25 #include "absl/strings/str_format.h"
26 #include "google/protobuf/text_format.h"
29 #include "ortools/base/stl_util.h"
30 #include "ortools/glop/lp_solver.h"
33 #include "ortools/sat/lp_utils.h"
34 #include "ortools/sat/sat_solver.h"
35 #include "ortools/sat/symmetry.h"
36 #include "ortools/sat/util.h"
37 #include "ortools/util/bitset.h"
38 
39 namespace operations_research {
40 namespace bop {
41 namespace {
42 
43 using ::operations_research::glop::ColIndex;
45 using ::operations_research::glop::GlopParameters;
46 using ::operations_research::glop::RowIndex;
47 
48 BopOptimizerBase::Status SolutionStatus(const BopSolution& solution,
49  int64_t lower_bound) {
50  // The lower bound might be greater that the cost of a feasible solution due
51  // to rounding errors in the problem scaling and Glop.
52  return solution.IsFeasible() ? (solution.GetCost() <= lower_bound
56 }
57 
58 bool AllIntegralValues(const DenseRow& values, double tolerance) {
59  for (const glop::Fractional value : values) {
60  // Note that this test is correct because in this part of the code, Bop
61  // only deals with boolean variables.
62  if (value >= tolerance && value + tolerance < 1.0) {
63  return false;
64  }
65  }
66  return true;
67 }
68 
69 void DenseRowToBopSolution(const DenseRow& values, BopSolution* solution) {
70  CHECK(solution != nullptr);
71  CHECK_EQ(solution->Size(), values.size());
72  for (VariableIndex var(0); var < solution->Size(); ++var) {
73  solution->SetValue(var, round(values[ColIndex(var.value())]));
74  }
75 }
76 } // anonymous namespace
77 
78 //------------------------------------------------------------------------------
79 // GuidedSatFirstSolutionGenerator
80 //------------------------------------------------------------------------------
81 
83  const std::string& name, Policy policy)
85  policy_(policy),
86  abort_(false),
87  state_update_stamp_(ProblemState::kInitialStampValue),
88  sat_solver_() {}
89 
91 
92 BopOptimizerBase::Status GuidedSatFirstSolutionGenerator::SynchronizeIfNeeded(
93  const ProblemState& problem_state) {
94  if (state_update_stamp_ == problem_state.update_stamp()) {
96  }
97  state_update_stamp_ = problem_state.update_stamp();
98 
99  // Create the sat_solver if not already done.
100  if (!sat_solver_) {
101  sat_solver_ = std::make_unique<sat::SatSolver>();
102 
103  // Add in symmetries.
104  if (problem_state.GetParameters()
105  .exploit_symmetry_in_sat_first_solution()) {
106  std::vector<std::unique_ptr<SparsePermutation>> generators;
108  &generators);
109  std::unique_ptr<sat::SymmetryPropagator> propagator(
111  for (int i = 0; i < generators.size(); ++i) {
112  propagator->AddSymmetry(std::move(generators[i]));
113  }
114  sat_solver_->AddPropagator(propagator.get());
115  sat_solver_->TakePropagatorOwnership(std::move(propagator));
116  }
117  }
118 
119  const BopOptimizerBase::Status load_status =
120  LoadStateProblemToSatSolver(problem_state, sat_solver_.get());
121  if (load_status != BopOptimizerBase::CONTINUE) return load_status;
122 
123  switch (policy_) {
124  case Policy::kNotGuided:
125  break;
126  case Policy::kLpGuided:
127  for (ColIndex col(0); col < problem_state.lp_values().size(); ++col) {
128  const double value = problem_state.lp_values()[col];
129  sat_solver_->SetAssignmentPreference(
130  sat::Literal(sat::BooleanVariable(col.value()), round(value) == 1),
131  1 - fabs(value - round(value)));
132  }
133  break;
136  sat_solver_.get());
137  break;
138  case Policy::kUserGuided:
139  for (int i = 0; i < problem_state.assignment_preference().size(); ++i) {
140  sat_solver_->SetAssignmentPreference(
141  sat::Literal(sat::BooleanVariable(i),
142  problem_state.assignment_preference()[i]),
143  1.0);
144  }
145  break;
146  }
148 }
149 
151  const ProblemState& problem_state) const {
152  if (abort_) return false;
153  if (policy_ == Policy::kLpGuided && problem_state.lp_values().empty()) {
154  return false;
155  }
156  if (policy_ == Policy::kUserGuided &&
157  problem_state.assignment_preference().empty()) {
158  return false;
159  }
160  return true;
161 }
162 
164  const BopParameters& parameters, const ProblemState& problem_state,
165  LearnedInfo* learned_info, TimeLimit* time_limit) {
166  CHECK(learned_info != nullptr);
167  CHECK(time_limit != nullptr);
168  learned_info->Clear();
169 
170  const BopOptimizerBase::Status sync_status =
171  SynchronizeIfNeeded(problem_state);
172  if (sync_status != BopOptimizerBase::CONTINUE) return sync_status;
173 
174  sat::SatParameters sat_params;
175  sat_params.set_max_time_in_seconds(time_limit->GetTimeLeft());
176  sat_params.set_max_deterministic_time(time_limit->GetDeterministicTimeLeft());
177  sat_params.set_random_seed(parameters.random_seed());
178 
179  // We use a relatively small conflict limit so that other optimizer get a
180  // chance to run if this one is slow. Note that if this limit is reached, we
181  // will return BopOptimizerBase::CONTINUE so that Optimize() will be called
182  // again later to resume the current work.
183  sat_params.set_max_number_of_conflicts(
184  parameters.guided_sat_conflicts_chunk());
185  sat_solver_->SetParameters(sat_params);
186 
187  const double initial_deterministic_time = sat_solver_->deterministic_time();
188  const sat::SatSolver::Status sat_status = sat_solver_->Solve();
189  time_limit->AdvanceDeterministicTime(sat_solver_->deterministic_time() -
190  initial_deterministic_time);
191 
192  if (sat_status == sat::SatSolver::INFEASIBLE) {
193  if (policy_ != Policy::kNotGuided) abort_ = true;
194  if (problem_state.upper_bound() != std::numeric_limits<int64_t>::max()) {
195  // As the solution in the state problem is feasible, it is proved optimal.
196  learned_info->lower_bound = problem_state.upper_bound();
198  }
199  // The problem is proved infeasible
201  }
202 
203  ExtractLearnedInfoFromSatSolver(sat_solver_.get(), learned_info);
204  if (sat_status == sat::SatSolver::FEASIBLE) {
205  SatAssignmentToBopSolution(sat_solver_->Assignment(),
206  &learned_info->solution);
207  return SolutionStatus(learned_info->solution, problem_state.lower_bound());
208  }
209 
211 }
212 
213 //------------------------------------------------------------------------------
214 // BopRandomFirstSolutionGenerator
215 //------------------------------------------------------------------------------
217  const std::string& name, const BopParameters& parameters,
218  sat::SatSolver* sat_propagator, absl::BitGenRef random)
220  random_(random),
221  sat_propagator_(sat_propagator) {}
222 
224 
225 // Only run the RandomFirstSolution when there is an objective to minimize.
227  const ProblemState& problem_state) const {
228  return problem_state.original_problem().objective().literals_size() > 0;
229 }
230 
232  const BopParameters& parameters, const ProblemState& problem_state,
233  LearnedInfo* learned_info, TimeLimit* time_limit) {
234  CHECK(learned_info != nullptr);
235  CHECK(time_limit != nullptr);
236  learned_info->Clear();
237 
238  // Save the current solver heuristics.
239  const sat::SatParameters saved_params = sat_propagator_->parameters();
240  const std::vector<std::pair<sat::Literal, double>> saved_prefs =
241  sat_propagator_->AllPreferences();
242 
243  const int kMaxNumConflicts = 10;
244  int64_t best_cost = problem_state.solution().IsFeasible()
245  ? problem_state.solution().GetCost()
247  int64_t remaining_num_conflicts =
248  parameters.max_number_of_conflicts_in_random_solution_generation();
249  int64_t old_num_failures = 0;
250 
251  // Optimization: Since each Solve() is really fast, we want to limit as
252  // much as possible the work around one.
253  bool objective_need_to_be_overconstrained =
254  (best_cost != std::numeric_limits<int64_t>::max());
255 
256  bool solution_found = false;
257  while (remaining_num_conflicts > 0 && !time_limit->LimitReached()) {
258  sat_propagator_->Backtrack(0);
259  old_num_failures = sat_propagator_->num_failures();
260 
261  sat::SatParameters sat_params = saved_params;
262  sat::RandomizeDecisionHeuristic(random_, &sat_params);
263  sat_params.set_max_number_of_conflicts(kMaxNumConflicts);
264  sat_propagator_->SetParameters(sat_params);
265  sat_propagator_->ResetDecisionHeuristic();
266 
267  if (objective_need_to_be_overconstrained) {
269  problem_state.original_problem(), false, sat::Coefficient(0),
270  true, sat::Coefficient(best_cost) - 1, sat_propagator_)) {
271  // The solution is proved optimal (if any).
272  learned_info->lower_bound = best_cost;
273  return best_cost == std::numeric_limits<int64_t>::max()
276  }
277  objective_need_to_be_overconstrained = false;
278  }
279 
280  // Special assignment preference parameters.
281  const int preference = absl::Uniform(random_, 0, 4);
282  if (preference == 0) {
284  sat_propagator_);
285  } else if (preference == 1 && !problem_state.lp_values().empty()) {
286  // Assign SAT assignment preference based on the LP solution.
287  for (ColIndex col(0); col < problem_state.lp_values().size(); ++col) {
288  const double value = problem_state.lp_values()[col];
289  sat_propagator_->SetAssignmentPreference(
290  sat::Literal(sat::BooleanVariable(col.value()), round(value) == 1),
291  1 - fabs(value - round(value)));
292  }
293  }
294 
295  const sat::SatSolver::Status sat_status =
296  sat_propagator_->SolveWithTimeLimit(time_limit);
297  if (sat_status == sat::SatSolver::FEASIBLE) {
298  objective_need_to_be_overconstrained = true;
299  solution_found = true;
300  SatAssignmentToBopSolution(sat_propagator_->Assignment(),
301  &learned_info->solution);
302  CHECK_LT(learned_info->solution.GetCost(), best_cost);
303  best_cost = learned_info->solution.GetCost();
304  } else if (sat_status == sat::SatSolver::INFEASIBLE) {
305  // The solution is proved optimal (if any).
306  learned_info->lower_bound = best_cost;
307  return best_cost == std::numeric_limits<int64_t>::max()
310  }
311 
312  // The number of failure is a good approximation of the number of conflicts.
313  // Note that the number of failures of the SAT solver is not reinitialized.
314  remaining_num_conflicts -=
315  sat_propagator_->num_failures() - old_num_failures;
316  }
317 
318  // Restore sat_propagator_ to its original state.
319  // Note that if the function is aborted before that, it means we solved the
320  // problem to optimality (or proven it to be infeasible), so we don't need
321  // to do any extra work in these cases since the sat_propagator_ will not be
322  // used anymore.
323  CHECK_EQ(0, sat_propagator_->AssumptionLevel());
324  sat_propagator_->RestoreSolverToAssumptionLevel();
325  sat_propagator_->SetParameters(saved_params);
326  sat_propagator_->ResetDecisionHeuristicAndSetAllPreferences(saved_prefs);
327 
328  // This can be proved during the call to RestoreSolverToAssumptionLevel().
329  if (sat_propagator_->IsModelUnsat()) {
330  // The solution is proved optimal (if any).
331  learned_info->lower_bound = best_cost;
332  return best_cost == std::numeric_limits<int64_t>::max()
335  }
336 
337  ExtractLearnedInfoFromSatSolver(sat_propagator_, learned_info);
338 
339  return solution_found ? BopOptimizerBase::SOLUTION_FOUND
341 }
342 
343 //------------------------------------------------------------------------------
344 // LinearRelaxation
345 //------------------------------------------------------------------------------
347  const std::string& name)
349  parameters_(parameters),
350  state_update_stamp_(ProblemState::kInitialStampValue),
351  lp_model_loaded_(false),
352  num_full_solves_(0),
353  lp_model_(),
354  lp_solver_(),
355  scaling_(1),
356  offset_(0),
357  num_fixed_variables_(-1),
358  problem_already_solved_(false),
359  scaled_solution_cost_(glop::kInfinity) {}
360 
362 
363 BopOptimizerBase::Status LinearRelaxation::SynchronizeIfNeeded(
364  const ProblemState& problem_state) {
365  if (state_update_stamp_ == problem_state.update_stamp()) {
367  }
368  state_update_stamp_ = problem_state.update_stamp();
369 
370  // If this is a pure feasibility problem, obey
371  // `BopParameters.max_lp_solve_for_feasibility_problems`.
372  if (problem_state.original_problem().objective().literals_size() == 0 &&
373  parameters_.max_lp_solve_for_feasibility_problems() >= 0 &&
374  num_full_solves_ >= parameters_.max_lp_solve_for_feasibility_problems()) {
376  }
377 
378  // Check if the number of fixed variables is greater than last time.
379  // TODO(user): Consider checking changes in number of conflicts too.
380  int num_fixed_variables = 0;
381  for (const bool is_fixed : problem_state.is_fixed()) {
382  if (is_fixed) {
383  ++num_fixed_variables;
384  }
385  }
386  problem_already_solved_ =
387  problem_already_solved_ && num_fixed_variables_ >= num_fixed_variables;
388  if (problem_already_solved_) return BopOptimizerBase::ABORT;
389 
390  // Create the LP model based on the current problem state.
391  num_fixed_variables_ = num_fixed_variables;
392  if (!lp_model_loaded_) {
393  lp_model_.Clear();
395  &lp_model_);
396  lp_model_loaded_ = true;
397  }
398  for (VariableIndex var(0); var < problem_state.is_fixed().size(); ++var) {
399  if (problem_state.IsVariableFixed(var)) {
400  const glop::Fractional value =
401  problem_state.GetVariableFixedValue(var) ? 1.0 : 0.0;
402  lp_model_.SetVariableBounds(ColIndex(var.value()), value, value);
403  }
404  }
405 
406  // Add learned binary clauses.
407  if (parameters_.use_learned_binary_clauses_in_lp()) {
408  for (const sat::BinaryClause& clause :
409  problem_state.NewlyAddedBinaryClauses()) {
410  const RowIndex constraint_index = lp_model_.CreateNewConstraint();
411  const int64_t coefficient_a = clause.a.IsPositive() ? 1 : -1;
412  const int64_t coefficient_b = clause.b.IsPositive() ? 1 : -1;
413  const int64_t rhs = 1 + (clause.a.IsPositive() ? 0 : -1) +
414  (clause.b.IsPositive() ? 0 : -1);
415  const ColIndex col_a(clause.a.Variable().value());
416  const ColIndex col_b(clause.b.Variable().value());
417  const std::string name_a = lp_model_.GetVariableName(col_a);
418  const std::string name_b = lp_model_.GetVariableName(col_b);
419 
420  lp_model_.SetConstraintName(
421  constraint_index,
422  (clause.a.IsPositive() ? name_a : "not(" + name_a + ")") + " or " +
423  (clause.b.IsPositive() ? name_b : "not(" + name_b + ")"));
424  lp_model_.SetCoefficient(constraint_index, col_a, coefficient_a);
425  lp_model_.SetCoefficient(constraint_index, col_b, coefficient_b);
426  lp_model_.SetConstraintBounds(constraint_index, rhs, glop::kInfinity);
427  }
428  }
429 
430  scaling_ = problem_state.original_problem().objective().scaling_factor();
431  offset_ = problem_state.original_problem().objective().offset();
432  scaled_solution_cost_ =
433  problem_state.solution().IsFeasible()
434  ? problem_state.solution().GetScaledCost()
435  : (lp_model_.IsMaximizationProblem() ? -glop::kInfinity
436  : glop::kInfinity);
438 }
439 
440 // Always let the LP solver run if there is an objective. If there isn't, only
441 // let the LP solver run if the user asked for it by setting
442 // `BopParameters.max_lp_solve_for_feasibility_problems` to a non-zero value
443 // (a negative value means no limit).
444 // TODO(user): also deal with problem_already_solved_
445 bool LinearRelaxation::ShouldBeRun(const ProblemState& problem_state) const {
446  return problem_state.original_problem().objective().literals_size() > 0 ||
447  parameters_.max_lp_solve_for_feasibility_problems() != 0;
448 }
449 
451  const BopParameters& parameters, const ProblemState& problem_state,
452  LearnedInfo* learned_info, TimeLimit* time_limit) {
453  CHECK(learned_info != nullptr);
454  CHECK(time_limit != nullptr);
455  learned_info->Clear();
456 
457  const BopOptimizerBase::Status sync_status =
458  SynchronizeIfNeeded(problem_state);
459  if (sync_status != BopOptimizerBase::CONTINUE) {
460  return sync_status;
461  }
462 
463  const glop::ProblemStatus lp_status = Solve(false, time_limit);
464  VLOG(1) << " LP: "
465  << absl::StrFormat("%.6f", lp_solver_.GetObjectiveValue())
466  << " status: " << GetProblemStatusString(lp_status);
467 
468  if (lp_status == glop::ProblemStatus::OPTIMAL ||
469  lp_status == glop::ProblemStatus::IMPRECISE) {
470  ++num_full_solves_;
471  problem_already_solved_ = true;
472  }
473 
474  if (lp_status == glop::ProblemStatus::INIT) {
476  }
477  if (lp_status != glop::ProblemStatus::OPTIMAL &&
478  lp_status != glop::ProblemStatus::IMPRECISE &&
481  }
482  learned_info->lp_values = lp_solver_.variable_values();
483 
484  if (lp_status == glop::ProblemStatus::OPTIMAL) {
485  // The lp returns the objective with the offset and scaled, so we need to
486  // unscale it and then remove the offset.
487  double lower_bound = lp_solver_.GetObjectiveValue();
488  if (parameters_.use_lp_strong_branching()) {
489  lower_bound =
490  ComputeLowerBoundUsingStrongBranching(learned_info, time_limit);
491  VLOG(1) << " LP: "
492  << absl::StrFormat("%.6f", lower_bound)
493  << " using strong branching.";
494  }
495 
496  const int tolerance_sign = scaling_ < 0 ? 1 : -1;
497  const double unscaled_cost =
498  (lower_bound +
499  tolerance_sign *
500  lp_solver_.GetParameters().solution_feasibility_tolerance()) /
501  scaling_ -
502  offset_;
503  learned_info->lower_bound = static_cast<int64_t>(ceil(unscaled_cost));
504 
505  if (AllIntegralValues(
506  learned_info->lp_values,
507  lp_solver_.GetParameters().primal_feasibility_tolerance())) {
508  DenseRowToBopSolution(learned_info->lp_values, &learned_info->solution);
509  CHECK(learned_info->solution.IsFeasible());
511  }
512  }
513 
515 }
516 
517 // TODO(user): It is possible to stop the search earlier using the glop
518 // parameter objective_lower_limit / objective_upper_limit. That
519 // can be used when a feasible solution is known, or when the false
520 // best bound is computed.
521 glop::ProblemStatus LinearRelaxation::Solve(bool incremental_solve,
523  GlopParameters glop_params;
524  if (incremental_solve) {
525  glop_params.set_use_dual_simplex(true);
526  glop_params.set_allow_simplex_algorithm_change(true);
527  glop_params.set_use_preprocessing(false);
528  lp_solver_.SetParameters(glop_params);
529  }
530  NestedTimeLimit nested_time_limit(time_limit, time_limit->GetTimeLeft(),
531  parameters_.lp_max_deterministic_time());
532  const glop::ProblemStatus lp_status = lp_solver_.SolveWithTimeLimit(
533  lp_model_, nested_time_limit.GetTimeLimit());
534  return lp_status;
535 }
536 
537 double LinearRelaxation::ComputeLowerBoundUsingStrongBranching(
538  LearnedInfo* learned_info, TimeLimit* time_limit) {
539  const glop::DenseRow initial_lp_values = lp_solver_.variable_values();
540  const double tolerance =
541  lp_solver_.GetParameters().primal_feasibility_tolerance();
542  double best_lp_objective = lp_solver_.GetObjectiveValue();
543  for (glop::ColIndex col(0); col < initial_lp_values.size(); ++col) {
544  // TODO(user): Order the variables by some meaningful quantity (probably
545  // the cost variation when we snap it to one of its bound) so
546  // we can try the one that seems the most promising first.
547  // That way we can stop the strong branching earlier.
548  if (time_limit->LimitReached()) break;
549 
550  // Skip fixed variables.
551  if (lp_model_.variable_lower_bounds()[col] ==
552  lp_model_.variable_upper_bounds()[col]) {
553  continue;
554  }
555  CHECK_EQ(0.0, lp_model_.variable_lower_bounds()[col]);
556  CHECK_EQ(1.0, lp_model_.variable_upper_bounds()[col]);
557 
558  // Note(user): Experiments show that iterating on all variables can be
559  // costly and doesn't lead to better solutions when a SAT optimizer is used
560  // afterward, e.g. BopSatLpFirstSolutionGenerator, and no feasible solutions
561  // are available.
562  // No variables are skipped when a feasible solution is know as the best
563  // bound / cost comparison can be used to deduce fixed variables, and be
564  // useful for other optimizers.
565  if ((scaled_solution_cost_ == glop::kInfinity ||
566  scaled_solution_cost_ == -glop::kInfinity) &&
567  (initial_lp_values[col] < tolerance ||
568  initial_lp_values[col] + tolerance > 1)) {
569  continue;
570  }
571 
572  double objective_true = best_lp_objective;
573  double objective_false = best_lp_objective;
574 
575  // Set to true.
576  lp_model_.SetVariableBounds(col, 1.0, 1.0);
577  const glop::ProblemStatus status_true = Solve(true, time_limit);
578  // TODO(user): Deal with PRIMAL_INFEASIBLE, DUAL_INFEASIBLE and
579  // INFEASIBLE_OR_UNBOUNDED statuses. In all cases, if the
580  // original lp was feasible, this means that the variable can
581  // be fixed to the other bound.
582  if (status_true == glop::ProblemStatus::OPTIMAL ||
583  status_true == glop::ProblemStatus::DUAL_FEASIBLE) {
584  objective_true = lp_solver_.GetObjectiveValue();
585 
586  // Set to false.
587  lp_model_.SetVariableBounds(col, 0.0, 0.0);
588  const glop::ProblemStatus status_false = Solve(true, time_limit);
589  if (status_false == glop::ProblemStatus::OPTIMAL ||
590  status_false == glop::ProblemStatus::DUAL_FEASIBLE) {
591  objective_false = lp_solver_.GetObjectiveValue();
592 
593  // Compute the new min.
594  best_lp_objective =
595  lp_model_.IsMaximizationProblem()
596  ? std::min(best_lp_objective,
597  std::max(objective_true, objective_false))
598  : std::max(best_lp_objective,
599  std::min(objective_true, objective_false));
600  }
601  }
602 
603  if (CostIsWorseThanSolution(objective_true, tolerance)) {
604  // Having variable col set to true can't possibly lead to and better
605  // solution than the current one. Set the variable to false.
606  lp_model_.SetVariableBounds(col, 0.0, 0.0);
607  learned_info->fixed_literals.push_back(
608  sat::Literal(sat::BooleanVariable(col.value()), false));
609  } else if (CostIsWorseThanSolution(objective_false, tolerance)) {
610  // Having variable col set to false can't possibly lead to and better
611  // solution than the current one. Set the variable to true.
612  lp_model_.SetVariableBounds(col, 1.0, 1.0);
613  learned_info->fixed_literals.push_back(
614  sat::Literal(sat::BooleanVariable(col.value()), true));
615  } else {
616  // Unset. This is safe to use 0.0 and 1.0 as the variable is not fixed.
617  lp_model_.SetVariableBounds(col, 0.0, 1.0);
618  }
619  }
620  return best_lp_objective;
621 }
622 
623 bool LinearRelaxation::CostIsWorseThanSolution(double scaled_cost,
624  double tolerance) const {
625  return lp_model_.IsMaximizationProblem()
626  ? scaled_cost + tolerance < scaled_solution_cost_
627  : scaled_cost > scaled_solution_cost_ + tolerance;
628 }
629 
630 } // namespace bop
631 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
bool empty() const
Provides a way to nest time limits for algorithms where a certain part of the computation is bounded ...
Definition: time_limit.h:445
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
bool ShouldBeRun(const ProblemState &problem_state) const override
Definition: bop_fs.cc:226
Status Optimize(const BopParameters &parameters, const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override
Definition: bop_fs.cc:231
BopRandomFirstSolutionGenerator(const std::string &name, const BopParameters &parameters, sat::SatSolver *sat_propagator, absl::BitGenRef random)
Definition: bop_fs.cc:216
bool ShouldBeRun(const ProblemState &problem_state) const override
Definition: bop_fs.cc:150
GuidedSatFirstSolutionGenerator(const std::string &name, Policy policy)
Definition: bop_fs.cc:82
Status Optimize(const BopParameters &parameters, const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override
Definition: bop_fs.cc:163
bool ShouldBeRun(const ProblemState &problem_state) const override
Definition: bop_fs.cc:445
Status Optimize(const BopParameters &parameters, const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override
Definition: bop_fs.cc:450
LinearRelaxation(const BopParameters &parameters, const std::string &name)
Definition: bop_fs.cc:346
const BopParameters & GetParameters() const
Definition: bop_base.h:126
const sat::LinearBooleanProblem & original_problem() const
Definition: bop_base.h:204
const std::vector< bool > assignment_preference() const
Definition: bop_base.h:133
const glop::DenseRow & lp_values() const
Definition: bop_base.h:194
const std::vector< sat::BinaryClause > & NewlyAddedBinaryClauses() const
Definition: bop_base.cc:251
bool IsVariableFixed(VariableIndex var) const
Definition: bop_base.h:178
bool GetVariableFixedValue(VariableIndex var) const
Definition: bop_base.h:185
const BopSolution & solution() const
Definition: bop_base.h:199
const absl::StrongVector< VariableIndex, bool > & is_fixed() const
Definition: bop_base.h:179
const GlopParameters & GetParameters() const
Definition: lp_solver.cc:130
const DenseRow & variable_values() const
Definition: lp_solver.h:105
Fractional GetObjectiveValue() const
Definition: lp_solver.cc:508
ABSL_MUST_USE_RESULT ProblemStatus SolveWithTimeLimit(const LinearProgram &lp, TimeLimit *time_limit)
Definition: lp_solver.cc:142
void SetParameters(const GlopParameters &parameters)
Definition: lp_solver.cc:118
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:250
std::string GetVariableName(ColIndex col) const
Definition: lp_data.cc:361
void SetConstraintName(RowIndex row, absl::string_view name)
Definition: lp_data.cc:246
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Definition: lp_data.cc:318
const DenseRow & variable_lower_bounds() const
Definition: lp_data.h:230
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:310
const DenseRow & variable_upper_bounds() const
Definition: lp_data.h:233
std::vector< std::pair< Literal, double > > AllPreferences() const
Definition: sat_solver.h:161
const SatParameters & parameters() const
Definition: sat_solver.cc:132
void ResetDecisionHeuristicAndSetAllPreferences(const std::vector< std::pair< Literal, double >> &prefs)
Definition: sat_solver.h:167
Status SolveWithTimeLimit(TimeLimit *time_limit)
Definition: sat_solver.cc:1083
void SetAssignmentPreference(Literal literal, double weight)
Definition: sat_solver.h:158
const VariablesAssignment & Assignment() const
Definition: sat_solver.h:388
void SetParameters(const SatParameters &parameters)
Definition: sat_solver.cc:137
void Backtrack(int target_level)
Definition: sat_solver.cc:1004
SatParameters parameters
ModelSharedTimeLimit * time_limit
const std::string name
int64_t value
IntVar * var
Definition: expr_array.cc:1874
const int64_t offset_
Definition: interval.cc:2109
ColIndex col
Definition: markowitz.cc:186
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
StrictITIVector< ColIndex, Fractional > DenseRow
Definition: lp_types.h:341
std::string GetProblemStatusString(ProblemStatus problem_status)
Definition: lp_types.cc:21
constexpr double kInfinity
Definition: lp_types.h:88
std::tuple< int64_t, int64_t, const double > Coefficient
void RandomizeDecisionHeuristic(absl::BitGenRef random, SatParameters *parameters)
Definition: sat/util.cc:61
bool AddObjectiveConstraint(const LinearBooleanProblem &problem, bool use_lower_bound, Coefficient lower_bound, bool use_upper_bound, Coefficient upper_bound, SatSolver *solver)
void UseObjectiveForSatAssignmentPreference(const LinearBooleanProblem &problem, SatSolver *solver)
void ConvertBooleanProblemToLinearProgram(const LinearBooleanProblem &problem, glop::LinearProgram *lp)
void FindLinearBooleanProblemSymmetries(const LinearBooleanProblem &problem, std::vector< std::unique_ptr< SparsePermutation >> *generators)
Collection of objects used to extend the Constraint Solver library.
Fractional scaled_cost
IntVar * lower_bound
Definition: routing.cc:1086
constexpr double kInfinity
#define VLOG(verboselevel)
Definition: vlog.h:39