OR-Tools  8.1
bop_ls.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_ls.h"
15 
16 #include "absl/memory/memory.h"
17 #include "absl/strings/str_format.h"
18 #include "ortools/bop/bop_util.h"
20 
21 namespace operations_research {
22 namespace bop {
23 
24 using ::operations_research::sat::LinearBooleanConstraint;
25 using ::operations_research::sat::LinearBooleanProblem;
26 using ::operations_research::sat::LinearObjective;
27 
28 //------------------------------------------------------------------------------
29 // LocalSearchOptimizer
30 //------------------------------------------------------------------------------
31 
33  int max_num_decisions,
34  sat::SatSolver* sat_propagator)
36  state_update_stamp_(ProblemState::kInitialStampValue),
37  max_num_decisions_(max_num_decisions),
38  sat_wrapper_(sat_propagator),
39  assignment_iterator_() {}
40 
42 
43 bool LocalSearchOptimizer::ShouldBeRun(
44  const ProblemState& problem_state) const {
45  return problem_state.solution().IsFeasible();
46 }
47 
48 BopOptimizerBase::Status LocalSearchOptimizer::Optimize(
49  const BopParameters& parameters, const ProblemState& problem_state,
50  LearnedInfo* learned_info, TimeLimit* time_limit) {
51  CHECK(learned_info != nullptr);
52  CHECK(time_limit != nullptr);
53  learned_info->Clear();
54 
55  if (assignment_iterator_ == nullptr) {
56  assignment_iterator_ = absl::make_unique<LocalSearchAssignmentIterator>(
57  problem_state, max_num_decisions_,
58  parameters.max_num_broken_constraints_in_ls(), &sat_wrapper_);
59  }
60 
61  if (state_update_stamp_ != problem_state.update_stamp()) {
62  // We have a new problem_state.
63  state_update_stamp_ = problem_state.update_stamp();
64  assignment_iterator_->Synchronize(problem_state);
65  }
66  assignment_iterator_->SynchronizeSatWrapper();
67 
68  double prev_deterministic_time = assignment_iterator_->deterministic_time();
69  assignment_iterator_->UseTranspositionTable(
70  parameters.use_transposition_table_in_ls());
71  assignment_iterator_->UsePotentialOneFlipRepairs(
72  parameters.use_potential_one_flip_repairs_in_ls());
73  int64 num_assignments_to_explore =
74  parameters.max_number_of_explored_assignments_per_try_in_ls();
75 
76  while (!time_limit->LimitReached() && num_assignments_to_explore > 0 &&
77  assignment_iterator_->NextAssignment()) {
78  time_limit->AdvanceDeterministicTime(
79  assignment_iterator_->deterministic_time() - prev_deterministic_time);
80  prev_deterministic_time = assignment_iterator_->deterministic_time();
81  --num_assignments_to_explore;
82  }
83  if (sat_wrapper_.IsModelUnsat()) {
84  // TODO(user): we do that all the time, return an UNSAT satus instead and
85  // do this only once.
86  return problem_state.solution().IsFeasible()
89  }
90 
91  // TODO(user): properly abort when we found a new solution and then finished
92  // the ls? note that this is minor.
93  sat_wrapper_.ExtractLearnedInfo(learned_info);
94  if (assignment_iterator_->BetterSolutionHasBeenFound()) {
95  // TODO(user): simply use vector<bool> instead of a BopSolution internally.
96  learned_info->solution = assignment_iterator_->LastReferenceAssignment();
98  }
99 
100  if (time_limit->LimitReached()) {
101  // The time limit is reached without finding a solution.
103  }
104 
105  if (num_assignments_to_explore <= 0) {
106  // Explore the remaining assignments in a future call to Optimize().
108  }
109 
110  // All assignments reachable in max_num_decisions_ or less have been explored,
111  // don't call optimize() with the same initial solution again.
113 }
114 
115 //------------------------------------------------------------------------------
116 // BacktrackableIntegerSet
117 //------------------------------------------------------------------------------
118 
119 template <typename IntType>
121  size_ = 0;
122  saved_sizes_.clear();
123  saved_stack_sizes_.clear();
124  stack_.clear();
125  in_stack_.assign(n.value(), false);
126 }
127 
128 template <typename IntType>
130  bool should_be_inside) {
131  size_ += should_be_inside ? 1 : -1;
132  if (!in_stack_[i.value()]) {
133  in_stack_[i.value()] = true;
134  stack_.push_back(i);
135  }
136 }
137 
138 template <typename IntType>
140  saved_stack_sizes_.push_back(stack_.size());
141  saved_sizes_.push_back(size_);
142 }
143 
144 template <typename IntType>
146  if (saved_stack_sizes_.empty()) {
147  BacktrackAll();
148  } else {
149  for (int i = saved_stack_sizes_.back(); i < stack_.size(); ++i) {
150  in_stack_[stack_[i].value()] = false;
151  }
152  stack_.resize(saved_stack_sizes_.back());
153  saved_stack_sizes_.pop_back();
154  size_ = saved_sizes_.back();
155  saved_sizes_.pop_back();
156  }
157 }
158 
159 template <typename IntType>
161  for (int i = 0; i < stack_.size(); ++i) {
162  in_stack_[stack_[i].value()] = false;
163  }
164  stack_.clear();
165  saved_stack_sizes_.clear();
166  size_ = 0;
167  saved_sizes_.clear();
168 }
169 
170 // Explicit instantiation of BacktrackableIntegerSet.
171 // TODO(user): move the code in a separate .h and -inl.h to avoid this.
173 
174 //------------------------------------------------------------------------------
175 // AssignmentAndConstraintFeasibilityMaintainer
176 //------------------------------------------------------------------------------
177 
180  const LinearBooleanProblem& problem)
181  : by_variable_matrix_(problem.num_variables()),
182  constraint_lower_bounds_(),
183  constraint_upper_bounds_(),
184  assignment_(problem, "Assignment"),
185  reference_(problem, "Assignment"),
186  constraint_values_(),
187  flipped_var_trail_backtrack_levels_(),
188  flipped_var_trail_() {
189  // Add the objective constraint as the first constraint.
190  const LinearObjective& objective = problem.objective();
191  CHECK_EQ(objective.literals_size(), objective.coefficients_size());
192  for (int i = 0; i < objective.literals_size(); ++i) {
193  CHECK_GT(objective.literals(i), 0);
194  CHECK_NE(objective.coefficients(i), 0);
195 
196  const VariableIndex var(objective.literals(i) - 1);
197  const int64 weight = objective.coefficients(i);
198  by_variable_matrix_[var].push_back(
199  ConstraintEntry(kObjectiveConstraint, weight));
200  }
201  constraint_lower_bounds_.push_back(kint64min);
202  constraint_values_.push_back(0);
203  constraint_upper_bounds_.push_back(kint64max);
204 
205  // Add each constraint.
206  ConstraintIndex num_constraints_with_objective(1);
207  for (const LinearBooleanConstraint& constraint : problem.constraints()) {
208  if (constraint.literals_size() <= 2) {
209  // Infeasible binary constraints are automatically repaired by propagation
210  // (when possible). Then there are no needs to consider the binary
211  // constraints here, the propagation is delegated to the SAT propagator.
212  continue;
213  }
214 
215  CHECK_EQ(constraint.literals_size(), constraint.coefficients_size());
216  for (int i = 0; i < constraint.literals_size(); ++i) {
217  const VariableIndex var(constraint.literals(i) - 1);
218  const int64 weight = constraint.coefficients(i);
219  by_variable_matrix_[var].push_back(
220  ConstraintEntry(num_constraints_with_objective, weight));
221  }
222  constraint_lower_bounds_.push_back(
223  constraint.has_lower_bound() ? constraint.lower_bound() : kint64min);
224  constraint_values_.push_back(0);
225  constraint_upper_bounds_.push_back(
226  constraint.has_upper_bound() ? constraint.upper_bound() : kint64max);
227 
228  ++num_constraints_with_objective;
229  }
230 
231  // Initialize infeasible_constraint_set_;
232  infeasible_constraint_set_.ClearAndResize(
233  ConstraintIndex(constraint_values_.size()));
234 
235  CHECK_EQ(constraint_values_.size(), constraint_lower_bounds_.size());
236  CHECK_EQ(constraint_values_.size(), constraint_upper_bounds_.size());
237 }
238 
239 const ConstraintIndex
241 
243  const BopSolution& reference_solution) {
244  CHECK(reference_solution.IsFeasible());
245  infeasible_constraint_set_.BacktrackAll();
246 
247  assignment_ = reference_solution;
248  reference_ = assignment_;
249  flipped_var_trail_backtrack_levels_.clear();
250  flipped_var_trail_.clear();
251  AddBacktrackingLevel(); // To handle initial propagation.
252 
253  // Recompute the value of all constraints.
254  constraint_values_.assign(NumConstraints(), 0);
255  for (VariableIndex var(0); var < assignment_.Size(); ++var) {
256  if (assignment_.Value(var)) {
257  for (const ConstraintEntry& entry : by_variable_matrix_[var]) {
258  constraint_values_[entry.constraint] += entry.weight;
259  }
260  }
261  }
262 
263  MakeObjectiveConstraintInfeasible(1);
264 }
265 
268  for (const VariableIndex var : flipped_var_trail_) {
269  reference_.SetValue(var, assignment_.Value(var));
270  }
271  flipped_var_trail_.clear();
272  flipped_var_trail_backtrack_levels_.clear();
273  AddBacktrackingLevel(); // To handle initial propagation.
274  MakeObjectiveConstraintInfeasible(1);
275 }
276 
277 void AssignmentAndConstraintFeasibilityMaintainer::
278  MakeObjectiveConstraintInfeasible(int delta) {
279  CHECK(IsFeasible());
280  CHECK(flipped_var_trail_.empty());
281  constraint_upper_bounds_[kObjectiveConstraint] =
282  constraint_values_[kObjectiveConstraint] - delta;
283  infeasible_constraint_set_.BacktrackAll();
284  infeasible_constraint_set_.ChangeState(kObjectiveConstraint, true);
285  infeasible_constraint_set_.AddBacktrackingLevel();
287  CHECK(!IsFeasible());
288  if (DEBUG_MODE) {
289  for (ConstraintIndex ct(1); ct < NumConstraints(); ++ct) {
291  }
292  }
293 }
294 
296  const std::vector<sat::Literal>& literals) {
297  for (const sat::Literal& literal : literals) {
298  const VariableIndex var(literal.Variable().value());
299  const bool value = literal.IsPositive();
300  if (assignment_.Value(var) != value) {
301  flipped_var_trail_.push_back(var);
302  assignment_.SetValue(var, value);
303  for (const ConstraintEntry& entry : by_variable_matrix_[var]) {
304  const bool was_feasible = ConstraintIsFeasible(entry.constraint);
305  constraint_values_[entry.constraint] +=
306  value ? entry.weight : -entry.weight;
307  if (ConstraintIsFeasible(entry.constraint) != was_feasible) {
308  infeasible_constraint_set_.ChangeState(entry.constraint,
309  was_feasible);
310  }
311  }
312  }
313  }
314 }
315 
317  flipped_var_trail_backtrack_levels_.push_back(flipped_var_trail_.size());
318  infeasible_constraint_set_.AddBacktrackingLevel();
319 }
320 
322  // Backtrack each literal of the last level.
323  for (int i = flipped_var_trail_backtrack_levels_.back();
324  i < flipped_var_trail_.size(); ++i) {
325  const VariableIndex var(flipped_var_trail_[i]);
326  const bool new_value = !assignment_.Value(var);
327  DCHECK_EQ(new_value, reference_.Value(var));
328  assignment_.SetValue(var, new_value);
329  for (const ConstraintEntry& entry : by_variable_matrix_[var]) {
330  constraint_values_[entry.constraint] +=
331  new_value ? entry.weight : -entry.weight;
332  }
333  }
334  flipped_var_trail_.resize(flipped_var_trail_backtrack_levels_.back());
335  flipped_var_trail_backtrack_levels_.pop_back();
336  infeasible_constraint_set_.BacktrackOneLevel();
337 }
338 
340  while (!flipped_var_trail_backtrack_levels_.empty()) BacktrackOneLevel();
341 }
342 
343 const std::vector<sat::Literal>&
345  if (!constraint_set_hasher_.IsInitialized()) {
346  InitializeConstraintSetHasher();
347  }
348 
349  // First, we compute the hash that a Literal should have in order to repair
350  // all the infeasible constraint (ignoring the objective).
351  //
352  // TODO(user): If this starts to show-up in a performance profile, we can
353  // easily maintain this hash incrementally.
354  uint64 hash = 0;
355  for (const ConstraintIndex ci : PossiblyInfeasibleConstraints()) {
356  const int64 value = ConstraintValue(ci);
357  if (value > ConstraintUpperBound(ci)) {
358  hash ^= constraint_set_hasher_.Hash(FromConstraintIndex(ci, false));
359  } else if (value < ConstraintLowerBound(ci)) {
360  hash ^= constraint_set_hasher_.Hash(FromConstraintIndex(ci, true));
361  }
362  }
363 
364  tmp_potential_repairs_.clear();
365  const auto it = hash_to_potential_repairs_.find(hash);
366  if (it != hash_to_potential_repairs_.end()) {
367  for (const sat::Literal literal : it->second) {
368  // We only returns the flips.
369  if (assignment_.Value(VariableIndex(literal.Variable().value())) !=
370  literal.IsPositive()) {
371  tmp_potential_repairs_.push_back(literal);
372  }
373  }
374  }
375  return tmp_potential_repairs_;
376 }
377 
379  std::string str;
380  str += "curr: ";
381  for (bool value : assignment_) {
382  str += value ? " 1 " : " 0 ";
383  }
384  str += "\nFlipped variables: ";
385  // TODO(user): show the backtrack levels.
386  for (const VariableIndex var : flipped_var_trail_) {
387  str += absl::StrFormat(" %d", var.value());
388  }
389  str += "\nmin curr max\n";
390  for (ConstraintIndex ct(0); ct < constraint_values_.size(); ++ct) {
391  if (constraint_lower_bounds_[ct] == kint64min) {
392  str += absl::StrFormat("- %d %d\n", constraint_values_[ct],
393  constraint_upper_bounds_[ct]);
394  } else {
395  str +=
396  absl::StrFormat("%d %d %d\n", constraint_lower_bounds_[ct],
397  constraint_values_[ct], constraint_upper_bounds_[ct]);
398  }
399  }
400  return str;
401 }
402 
403 void AssignmentAndConstraintFeasibilityMaintainer::
404  InitializeConstraintSetHasher() {
405  const int num_constraints_with_objective = constraint_upper_bounds_.size();
406 
407  // Initialize the potential one flip repair. Note that we ignore the
408  // objective constraint completely so that we consider a repair even if the
409  // objective constraint is not infeasible.
410  constraint_set_hasher_.Initialize(2 * num_constraints_with_objective);
411  constraint_set_hasher_.IgnoreElement(
412  FromConstraintIndex(kObjectiveConstraint, true));
413  constraint_set_hasher_.IgnoreElement(
414  FromConstraintIndex(kObjectiveConstraint, false));
415  for (VariableIndex var(0); var < by_variable_matrix_.size(); ++var) {
416  // We add two entries, one for a positive flip (from false to true) and one
417  // for a negative flip (from true to false).
418  for (const bool flip_is_positive : {true, false}) {
419  uint64 hash = 0;
420  for (const ConstraintEntry& entry : by_variable_matrix_[var]) {
421  const bool coeff_is_positive = entry.weight > 0;
422  hash ^= constraint_set_hasher_.Hash(FromConstraintIndex(
423  entry.constraint,
424  /*up=*/flip_is_positive ? coeff_is_positive : !coeff_is_positive));
425  }
426  hash_to_potential_repairs_[hash].push_back(
427  sat::Literal(sat::BooleanVariable(var.value()), flip_is_positive));
428  }
429  }
430 }
431 
432 //------------------------------------------------------------------------------
433 // OneFlipConstraintRepairer
434 //------------------------------------------------------------------------------
435 
437  const LinearBooleanProblem& problem,
439  const sat::VariablesAssignment& sat_assignment)
440  : by_constraint_matrix_(problem.constraints_size() + 1),
441  maintainer_(maintainer),
442  sat_assignment_(sat_assignment) {
443  // Fill the by_constraint_matrix_.
444  //
445  // IMPORTANT: The order of the constraint needs to exactly match the one of
446  // the constraint in the AssignmentAndConstraintFeasibilityMaintainer.
447 
448  // Add the objective constraint as the first constraint.
449  ConstraintIndex num_constraint(0);
450  const LinearObjective& objective = problem.objective();
451  CHECK_EQ(objective.literals_size(), objective.coefficients_size());
452  for (int i = 0; i < objective.literals_size(); ++i) {
453  CHECK_GT(objective.literals(i), 0);
454  CHECK_NE(objective.coefficients(i), 0);
455 
456  const VariableIndex var(objective.literals(i) - 1);
457  const int64 weight = objective.coefficients(i);
458  by_constraint_matrix_[num_constraint].push_back(
460  }
461 
462  // Add the non-binary problem constraints.
463  for (const LinearBooleanConstraint& constraint : problem.constraints()) {
464  if (constraint.literals_size() <= 2) {
465  // Infeasible binary constraints are automatically repaired by propagation
466  // (when possible). Then there are no needs to consider the binary
467  // constraints here, the propagation is delegated to the SAT propagator.
468  continue;
469  }
470 
471  ++num_constraint;
472  CHECK_EQ(constraint.literals_size(), constraint.coefficients_size());
473  for (int i = 0; i < constraint.literals_size(); ++i) {
474  const VariableIndex var(constraint.literals(i) - 1);
475  const int64 weight = constraint.coefficients(i);
476  by_constraint_matrix_[num_constraint].push_back(
478  }
479  }
480 
481  SortTermsOfEachConstraints(problem.num_variables());
482 }
483 
484 const ConstraintIndex OneFlipConstraintRepairer::kInvalidConstraint(-1);
485 const TermIndex OneFlipConstraintRepairer::kInitTerm(-1);
486 const TermIndex OneFlipConstraintRepairer::kInvalidTerm(-2);
487 
489  ConstraintIndex selected_ct = kInvalidConstraint;
490  int32 selected_num_branches = kint32max;
491  int num_infeasible_constraints_left = maintainer_.NumInfeasibleConstraints();
492 
493  // Optimization: We inspect the constraints in reverse order because the
494  // objective one will always be first (in our current code) and with some
495  // luck, we will break early instead of fully exploring it.
496  const std::vector<ConstraintIndex>& infeasible_constraints =
497  maintainer_.PossiblyInfeasibleConstraints();
498  for (int index = infeasible_constraints.size() - 1; index >= 0; --index) {
499  const ConstraintIndex& i = infeasible_constraints[index];
500  if (maintainer_.ConstraintIsFeasible(i)) continue;
501  --num_infeasible_constraints_left;
502 
503  // Optimization: We return the only candidate without inspecting it.
504  // This is critical at the beginning of the search or later if the only
505  // candidate is the objective constraint which can be really long.
506  if (num_infeasible_constraints_left == 0 &&
507  selected_ct == kInvalidConstraint) {
508  return i;
509  }
510 
511  const int64 constraint_value = maintainer_.ConstraintValue(i);
512  const int64 lb = maintainer_.ConstraintLowerBound(i);
513  const int64 ub = maintainer_.ConstraintUpperBound(i);
514 
515  int32 num_branches = 0;
516  for (const ConstraintTerm& term : by_constraint_matrix_[i]) {
517  if (sat_assignment_.VariableIsAssigned(
518  sat::BooleanVariable(term.var.value()))) {
519  continue;
520  }
521  const int64 new_value =
522  constraint_value +
523  (maintainer_.Assignment(term.var) ? -term.weight : term.weight);
524  if (new_value >= lb && new_value <= ub) {
525  ++num_branches;
526  if (num_branches >= selected_num_branches) break;
527  }
528  }
529 
530  // The constraint can't be repaired in one decision.
531  if (num_branches == 0) continue;
532  if (num_branches < selected_num_branches) {
533  selected_ct = i;
534  selected_num_branches = num_branches;
535  if (num_branches == 1) break;
536  }
537  }
538  return selected_ct;
539 }
540 
542  ConstraintIndex ct_index, TermIndex init_term_index,
543  TermIndex start_term_index) const {
545  by_constraint_matrix_[ct_index];
546  const int64 constraint_value = maintainer_.ConstraintValue(ct_index);
547  const int64 lb = maintainer_.ConstraintLowerBound(ct_index);
548  const int64 ub = maintainer_.ConstraintUpperBound(ct_index);
549 
550  const TermIndex end_term_index(terms.size() + init_term_index + 1);
551  for (TermIndex loop_term_index(
552  start_term_index + 1 +
553  (start_term_index < init_term_index ? terms.size() : 0));
554  loop_term_index < end_term_index; ++loop_term_index) {
555  const TermIndex term_index(loop_term_index % terms.size());
556  const ConstraintTerm term = terms[term_index];
557  if (sat_assignment_.VariableIsAssigned(
558  sat::BooleanVariable(term.var.value()))) {
559  continue;
560  }
561  const int64 new_value =
562  constraint_value +
563  (maintainer_.Assignment(term.var) ? -term.weight : term.weight);
564  if (new_value >= lb && new_value <= ub) {
565  return term_index;
566  }
567  }
568  return kInvalidTerm;
569 }
570 
571 bool OneFlipConstraintRepairer::RepairIsValid(ConstraintIndex ct_index,
572  TermIndex term_index) const {
573  if (maintainer_.ConstraintIsFeasible(ct_index)) return false;
574  const ConstraintTerm term = by_constraint_matrix_[ct_index][term_index];
575  if (sat_assignment_.VariableIsAssigned(
576  sat::BooleanVariable(term.var.value()))) {
577  return false;
578  }
579  const int64 new_value =
580  maintainer_.ConstraintValue(ct_index) +
581  (maintainer_.Assignment(term.var) ? -term.weight : term.weight);
582 
583  const int64 lb = maintainer_.ConstraintLowerBound(ct_index);
584  const int64 ub = maintainer_.ConstraintUpperBound(ct_index);
585  return (new_value >= lb && new_value <= ub);
586 }
587 
589  TermIndex term_index) const {
590  const ConstraintTerm term = by_constraint_matrix_[ct_index][term_index];
591  const bool value = maintainer_.Assignment(term.var);
592  return sat::Literal(sat::BooleanVariable(term.var.value()), !value);
593 }
594 
595 void OneFlipConstraintRepairer::SortTermsOfEachConstraints(int num_variables) {
596  absl::StrongVector<VariableIndex, int64> objective(num_variables, 0);
597  for (const ConstraintTerm& term :
598  by_constraint_matrix_[AssignmentAndConstraintFeasibilityMaintainer::
600  objective[term.var] = std::abs(term.weight);
601  }
603  by_constraint_matrix_) {
604  std::sort(terms.begin(), terms.end(),
605  [&objective](const ConstraintTerm& a, const ConstraintTerm& b) {
606  return objective[a.var] > objective[b.var];
607  });
608  }
609 }
610 
611 //------------------------------------------------------------------------------
612 // SatWrapper
613 //------------------------------------------------------------------------------
614 
615 SatWrapper::SatWrapper(sat::SatSolver* sat_solver) : sat_solver_(sat_solver) {}
616 
617 void SatWrapper::BacktrackAll() { sat_solver_->Backtrack(0); }
618 
619 std::vector<sat::Literal> SatWrapper::FullSatTrail() const {
620  std::vector<sat::Literal> propagated_literals;
621  const sat::Trail& trail = sat_solver_->LiteralTrail();
622  for (int trail_index = 0; trail_index < trail.Index(); ++trail_index) {
623  propagated_literals.push_back(trail[trail_index]);
624  }
625  return propagated_literals;
626 }
627 
629  std::vector<sat::Literal>* propagated_literals) {
630  CHECK(!sat_solver_->Assignment().VariableIsAssigned(
631  decision_literal.Variable()));
632  CHECK(propagated_literals != nullptr);
633 
634  propagated_literals->clear();
635  const int old_decision_level = sat_solver_->CurrentDecisionLevel();
636  const int new_trail_index =
637  sat_solver_->EnqueueDecisionAndBackjumpOnConflict(decision_literal);
638  if (sat_solver_->IsModelUnsat()) {
639  return old_decision_level + 1;
640  }
641 
642  // Return the propagated literals, whenever there is a conflict or not.
643  // In case of conflict, these literals will have to be added to the last
644  // decision point after backtrack.
645  const sat::Trail& propagation_trail = sat_solver_->LiteralTrail();
646  for (int trail_index = new_trail_index;
647  trail_index < propagation_trail.Index(); ++trail_index) {
648  propagated_literals->push_back(propagation_trail[trail_index]);
649  }
650 
651  return old_decision_level + 1 - sat_solver_->CurrentDecisionLevel();
652 }
653 
655  const int old_decision_level = sat_solver_->CurrentDecisionLevel();
656  if (old_decision_level > 0) {
657  sat_solver_->Backtrack(old_decision_level - 1);
658  }
659 }
660 
662  bop::ExtractLearnedInfoFromSatSolver(sat_solver_, info);
663 }
664 
666  return sat_solver_->deterministic_time();
667 }
668 
669 //------------------------------------------------------------------------------
670 // LocalSearchAssignmentIterator
671 //------------------------------------------------------------------------------
672 
674  const ProblemState& problem_state, int max_num_decisions,
675  int max_num_broken_constraints, SatWrapper* sat_wrapper)
676  : max_num_decisions_(max_num_decisions),
677  max_num_broken_constraints_(max_num_broken_constraints),
678  maintainer_(problem_state.original_problem()),
679  sat_wrapper_(sat_wrapper),
680  repairer_(problem_state.original_problem(), maintainer_,
681  sat_wrapper->SatAssignment()),
682  search_nodes_(),
683  initial_term_index_(
684  problem_state.original_problem().constraints_size() + 1,
685  OneFlipConstraintRepairer::kInitTerm),
686  use_transposition_table_(false),
687  use_potential_one_flip_repairs_(false),
688  num_nodes_(0),
689  num_skipped_nodes_(0),
690  num_improvements_(0),
691  num_improvements_by_one_flip_repairs_(0),
692  num_inspected_one_flip_repairs_(0) {}
693 
695  VLOG(1) << "LS " << max_num_decisions_
696  << "\n num improvements: " << num_improvements_
697  << "\n num improvements with one flip repairs: "
698  << num_improvements_by_one_flip_repairs_
699  << "\n num inspected one flip repairs: "
700  << num_inspected_one_flip_repairs_;
701 }
702 
704  const ProblemState& problem_state) {
705  better_solution_has_been_found_ = false;
706  maintainer_.SetReferenceSolution(problem_state.solution());
707  for (const SearchNode& node : search_nodes_) {
708  initial_term_index_[node.constraint] = node.term_index;
709  }
710  search_nodes_.clear();
711  transposition_table_.clear();
712  num_nodes_ = 0;
713  num_skipped_nodes_ = 0;
714 }
715 
716 // In order to restore the synchronization from any state, we backtrack
717 // everything and retry to take the same decisions as before. We stop at the
718 // first one that can't be taken.
720  CHECK_EQ(better_solution_has_been_found_, false);
721  const std::vector<SearchNode> copy = search_nodes_;
722  sat_wrapper_->BacktrackAll();
723  maintainer_.BacktrackAll();
724 
725  // Note(user): at this stage, the sat trail contains the fixed variables.
726  // There will almost always be at the same value in the reference solution.
727  // However since the objective may be over-constrained in the sat_solver, it
728  // is possible that some variable where propagated to some other values.
729  maintainer_.Assign(sat_wrapper_->FullSatTrail());
730 
731  search_nodes_.clear();
732  for (const SearchNode& node : copy) {
733  if (!repairer_.RepairIsValid(node.constraint, node.term_index)) break;
734  search_nodes_.push_back(node);
735  ApplyDecision(repairer_.GetFlip(node.constraint, node.term_index));
736  }
737 }
738 
739 void LocalSearchAssignmentIterator::UseCurrentStateAsReference() {
740  better_solution_has_been_found_ = true;
741  maintainer_.UseCurrentStateAsReference();
742  sat_wrapper_->BacktrackAll();
743 
744  // Note(user): Here, there should be no discrepancies between the fixed
745  // variable and the new reference, so there is no need to do:
746  // maintainer_.Assign(sat_wrapper_->FullSatTrail());
747 
748  for (const SearchNode& node : search_nodes_) {
749  initial_term_index_[node.constraint] = node.term_index;
750  }
751  search_nodes_.clear();
752  transposition_table_.clear();
753  num_nodes_ = 0;
754  num_skipped_nodes_ = 0;
755  ++num_improvements_;
756 }
757 
759  if (sat_wrapper_->IsModelUnsat()) return false;
760  if (maintainer_.IsFeasible()) {
761  UseCurrentStateAsReference();
762  return true;
763  }
764 
765  // We only look for potential one flip repairs if we reached the end of the
766  // LS tree. I tried to do that at every level, but it didn't change the
767  // result much on the set-partitionning example I was using.
768  //
769  // TODO(user): Perform more experiments with this.
770  if (use_potential_one_flip_repairs_ &&
771  search_nodes_.size() == max_num_decisions_) {
772  for (const sat::Literal literal : maintainer_.PotentialOneFlipRepairs()) {
773  if (sat_wrapper_->SatAssignment().VariableIsAssigned(
774  literal.Variable())) {
775  continue;
776  }
777  ++num_inspected_one_flip_repairs_;
778 
779  // Temporarily apply the potential repair and see if it worked!
780  ApplyDecision(literal);
781  if (maintainer_.IsFeasible()) {
782  num_improvements_by_one_flip_repairs_++;
783  UseCurrentStateAsReference();
784  return true;
785  }
786  maintainer_.BacktrackOneLevel();
787  sat_wrapper_->BacktrackOneLevel();
788  }
789  }
790 
791  // If possible, go deeper, i.e. take one more decision.
792  if (!GoDeeper()) {
793  // If not, backtrack to the first node that still has untried way to fix
794  // its associated constraint. Update it to the next untried way.
795  Backtrack();
796  }
797 
798  // All nodes have been explored.
799  if (search_nodes_.empty()) {
800  VLOG(1) << std::string(27, ' ') + "LS " << max_num_decisions_
801  << " finished."
802  << " #explored:" << num_nodes_
803  << " #stored:" << transposition_table_.size()
804  << " #skipped:" << num_skipped_nodes_;
805  return false;
806  }
807 
808  // Apply the next decision, i.e. the literal of the flipped variable.
809  const SearchNode node = search_nodes_.back();
810  ApplyDecision(repairer_.GetFlip(node.constraint, node.term_index));
811  return true;
812 }
813 
814 // TODO(user): The 1.2 multiplier is an approximation only based on the time
815 // spent in the SAT wrapper. So far experiments show a good
816 // correlation with real time, but we might want to be more
817 // accurate.
819  return sat_wrapper_->deterministic_time() * 1.2;
820 }
821 
823  std::string str = "Search nodes:\n";
824  for (int i = 0; i < search_nodes_.size(); ++i) {
825  str += absl::StrFormat(" %d: %d %d\n", i,
826  search_nodes_[i].constraint.value(),
827  search_nodes_[i].term_index.value());
828  }
829  return str;
830 }
831 
832 void LocalSearchAssignmentIterator::ApplyDecision(sat::Literal literal) {
833  ++num_nodes_;
834  const int num_backtracks =
835  sat_wrapper_->ApplyDecision(literal, &tmp_propagated_literals_);
836 
837  // Sync the maintainer with SAT.
838  if (num_backtracks == 0) {
839  maintainer_.AddBacktrackingLevel();
840  maintainer_.Assign(tmp_propagated_literals_);
841  } else {
842  CHECK_GT(num_backtracks, 0);
843  CHECK_LE(num_backtracks, search_nodes_.size());
844 
845  // Only backtrack -1 decisions as the last one has not been pushed yet.
846  for (int i = 0; i < num_backtracks - 1; ++i) {
847  maintainer_.BacktrackOneLevel();
848  }
849  maintainer_.Assign(tmp_propagated_literals_);
850  search_nodes_.resize(search_nodes_.size() - num_backtracks);
851  }
852 }
853 
854 void LocalSearchAssignmentIterator::InitializeTranspositionTableKey(
855  std::array<int32, kStoredMaxDecisions>* a) {
856  int i = 0;
857  for (const SearchNode& n : search_nodes_) {
858  // Negated because we already fliped this variable, so GetFlip() will
859  // returns the old value.
860  (*a)[i] = -repairer_.GetFlip(n.constraint, n.term_index).SignedValue();
861  ++i;
862  }
863 
864  // 'a' is not zero-initialized, so we need to complete it with zeros.
865  while (i < kStoredMaxDecisions) {
866  (*a)[i] = 0;
867  ++i;
868  }
869 }
870 
871 bool LocalSearchAssignmentIterator::NewStateIsInTranspositionTable(
872  sat::Literal l) {
873  if (search_nodes_.size() + 1 > kStoredMaxDecisions) return false;
874 
875  // Fill the transposition table element, i.e the array 'a' of decisions.
876  std::array<int32, kStoredMaxDecisions> a;
877  InitializeTranspositionTableKey(&a);
878  a[search_nodes_.size()] = l.SignedValue();
879  std::sort(a.begin(), a.begin() + 1 + search_nodes_.size());
880 
881  if (transposition_table_.find(a) == transposition_table_.end()) {
882  return false;
883  } else {
884  ++num_skipped_nodes_;
885  return true;
886  }
887 }
888 
889 void LocalSearchAssignmentIterator::InsertInTranspositionTable() {
890  // If there is more decision that kStoredMaxDecisions, do nothing.
891  if (search_nodes_.size() > kStoredMaxDecisions) return;
892 
893  // Fill the transposition table element, i.e the array 'a' of decisions.
894  std::array<int32, kStoredMaxDecisions> a;
895  InitializeTranspositionTableKey(&a);
896  std::sort(a.begin(), a.begin() + search_nodes_.size());
897 
898  transposition_table_.insert(a);
899 }
900 
901 bool LocalSearchAssignmentIterator::EnqueueNextRepairingTermIfAny(
902  ConstraintIndex ct_to_repair, TermIndex term_index) {
903  if (term_index == initial_term_index_[ct_to_repair]) return false;
904  if (term_index == OneFlipConstraintRepairer::kInvalidTerm) {
905  term_index = initial_term_index_[ct_to_repair];
906  }
907  while (true) {
908  term_index = repairer_.NextRepairingTerm(
909  ct_to_repair, initial_term_index_[ct_to_repair], term_index);
910  if (term_index == OneFlipConstraintRepairer::kInvalidTerm) return false;
911  if (!use_transposition_table_ ||
912  !NewStateIsInTranspositionTable(
913  repairer_.GetFlip(ct_to_repair, term_index))) {
914  search_nodes_.push_back(SearchNode(ct_to_repair, term_index));
915  return true;
916  }
917  if (term_index == initial_term_index_[ct_to_repair]) return false;
918  }
919 }
920 
921 bool LocalSearchAssignmentIterator::GoDeeper() {
922  // Can we add one more decision?
923  if (search_nodes_.size() >= max_num_decisions_) {
924  return false;
925  }
926 
927  // Is the number of infeasible constraints reasonable?
928  //
929  // TODO(user): Make this parameters dynamic. We can either try lower value
930  // first and increase it later, or try to dynamically change it during the
931  // search. Another idea is to have instead a "max number of constraints that
932  // can be repaired in one decision" and to take into account the number of
933  // decisions left.
934  if (maintainer_.NumInfeasibleConstraints() > max_num_broken_constraints_) {
935  return false;
936  }
937 
938  // Can we find a constraint that can be repaired in one decision?
939  const ConstraintIndex ct_to_repair = repairer_.ConstraintToRepair();
940  if (ct_to_repair == OneFlipConstraintRepairer::kInvalidConstraint) {
941  return false;
942  }
943 
944  // Add the new decision.
945  //
946  // TODO(user): Store the last explored term index to not start from -1 each
947  // time. This will be very useful when a backtrack occurred due to the SAT
948  // propagator. Note however that this behavior is already enforced when we use
949  // the transposition table, since we will not explore again the branches
950  // already explored.
951  return EnqueueNextRepairingTermIfAny(ct_to_repair,
953 }
954 
955 void LocalSearchAssignmentIterator::Backtrack() {
956  while (!search_nodes_.empty()) {
957  // We finished exploring this node. Store it in the transposition table so
958  // that the same decisions will not be explored again. Note that the SAT
959  // solver may have learned more the second time the exact same decisions are
960  // seen, but we assume that it is not worth exploring again.
961  if (use_transposition_table_) InsertInTranspositionTable();
962 
963  const SearchNode last_node = search_nodes_.back();
964  search_nodes_.pop_back();
965  maintainer_.BacktrackOneLevel();
966  sat_wrapper_->BacktrackOneLevel();
967  if (EnqueueNextRepairingTermIfAny(last_node.constraint,
968  last_node.term_index)) {
969  return;
970  }
971  }
972 }
973 
974 } // namespace bop
975 } // namespace operations_research
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::DebugString
std::string DebugString() const
Definition: bop_ls.cc:378
operations_research::bop::BacktrackableIntegerSet::BacktrackAll
void BacktrackAll()
Definition: bop_ls.cc:160
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::sat::Literal::Variable
BooleanVariable Variable() const
Definition: sat_base.h:80
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::UseCurrentStateAsReference
void UseCurrentStateAsReference()
Definition: bop_ls.cc:267
operations_research::bop::BacktrackableIntegerSet< ConstraintIndex >
operations_research::bop::OneFlipConstraintRepairer::OneFlipConstraintRepairer
OneFlipConstraintRepairer(const sat::LinearBooleanProblem &problem, const AssignmentAndConstraintFeasibilityMaintainer &maintainer, const sat::VariablesAssignment &sat_assignment)
Definition: bop_ls.cc:436
VLOG
#define VLOG(verboselevel)
Definition: base/logging.h:978
operations_research::bop::BopOptimizerBase::SOLUTION_FOUND
@ SOLUTION_FOUND
Definition: bop_base.h:63
operations_research::bop::OneFlipConstraintRepairer::NextRepairingTerm
TermIndex NextRepairingTerm(ConstraintIndex ct_index, TermIndex init_term_index, TermIndex start_term_index) const
Definition: bop_ls.cc:541
operations_research::bop::BopSolution::Size
size_t Size() const
Definition: bop_solution.h:42
operations_research::bop::ProblemState::solution
const BopSolution & solution() const
Definition: bop_base.h:193
operations_research::bop::OneFlipConstraintRepairer::ConstraintTerm
Definition: bop_ls.h:478
operations_research::bop::SatWrapper::FullSatTrail
std::vector< sat::Literal > FullSatTrail() const
Definition: bop_ls.cc:619
absl::StrongVector::size
size_type size() const
Definition: strong_vector.h:147
operations_research::sat::SatSolver::Assignment
const VariablesAssignment & Assignment() const
Definition: sat_solver.h:363
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::BacktrackOneLevel
void BacktrackOneLevel()
Definition: bop_ls.cc:321
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::IsFeasible
bool IsFeasible() const
Definition: bop_ls.h:311
operations_research::bop::NonOrderedSetHasher::IgnoreElement
void IgnoreElement(IntType e)
Definition: bop_ls.h:214
operations_research::bop::BopOptimizerBase::LIMIT_REACHED
@ LIMIT_REACHED
Definition: bop_base.h:65
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::ConstraintIsFeasible
bool ConstraintIsFeasible(ConstraintIndex constraint) const
Definition: bop_ls.h:356
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::ConstraintLowerBound
int64 ConstraintLowerBound(ConstraintIndex constraint) const
Definition: bop_ls.h:339
operations_research::sat::SatSolver::EnqueueDecisionAndBackjumpOnConflict
int EnqueueDecisionAndBackjumpOnConflict(Literal true_literal)
Definition: sat_solver.cc:499
operations_research::sat::SatSolver
Definition: sat_solver.h:58
hash
int64 hash
Definition: matrix_utils.cc:60
value
int64 value
Definition: demon_profiler.cc:43
CHECK_GT
#define CHECK_GT(val1, val2)
Definition: base/logging.h:702
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::PossiblyInfeasibleConstraints
const std::vector< ConstraintIndex > & PossiblyInfeasibleConstraints() const
Definition: bop_ls.h:321
weight
int64 weight
Definition: pack.cc:509
operations_research::bop::SatWrapper::SatWrapper
SatWrapper(sat::SatSolver *sat_solver)
Definition: bop_ls.cc:615
operations_research::bop::OneFlipConstraintRepairer::kInitTerm
static const TermIndex kInitTerm
Definition: bop_ls.h:444
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::ConstraintUpperBound
int64 ConstraintUpperBound(ConstraintIndex constraint) const
Definition: bop_ls.h:344
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::AssignmentAndConstraintFeasibilityMaintainer::PotentialOneFlipRepairs
const std::vector< sat::Literal > & PotentialOneFlipRepairs()
Definition: bop_ls.cc:344
kint64min
static const int64 kint64min
Definition: integral_types.h:60
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::AddBacktrackingLevel
void AddBacktrackingLevel()
Definition: bop_ls.cc:316
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::NumConstraints
size_t NumConstraints() const
Definition: bop_ls.h:327
operations_research::bop::BopOptimizerBase
Definition: bop_base.h:40
operations_research::bop::LocalSearchAssignmentIterator::~LocalSearchAssignmentIterator
~LocalSearchAssignmentIterator()
Definition: bop_ls.cc:694
operations_research::bop::LocalSearchAssignmentIterator::SynchronizeSatWrapper
void SynchronizeSatWrapper()
Definition: bop_ls.cc:719
int64
int64_t int64
Definition: integral_types.h:34
operations_research::bop::BopSolution::Value
bool Value(VariableIndex var) const
Definition: bop_solution.h:43
operations_research::TimeLimit
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:105
index
int index
Definition: pack.cc:508
int32
int int32
Definition: integral_types.h:33
operations_research::sat::Literal::SignedValue
int SignedValue() const
Definition: sat_base.h:87
operations_research::bop::SatWrapper
Definition: bop_ls.h:50
absl::StrongVector::assign
void assign(size_type n, const value_type &val)
Definition: strong_vector.h:131
operations_research::bop::BopSolution
Definition: bop_solution.h:31
operations_research::sat::Trail::Index
int Index() const
Definition: sat_base.h:378
operations_research::bop::SatWrapper::SatAssignment
const sat::VariablesAssignment & SatAssignment() const
Definition: bop_ls.h:65
operations_research::bop::NonOrderedSetHasher::Hash
uint64 Hash(const std::vector< IntType > &set) const
Definition: bop_ls.h:219
operations_research::sat::SatSolver::CurrentDecisionLevel
int CurrentDecisionLevel() const
Definition: sat_solver.h:361
operations_research::bop::BacktrackableIntegerSet::ClearAndResize
void ClearAndResize(IntType n)
Definition: bop_ls.cc:120
DEBUG_MODE
const bool DEBUG_MODE
Definition: macros.h:24
operations_research::bop::NonOrderedSetHasher::Initialize
void Initialize(int size)
Definition: bop_ls.h:205
a
int64 a
Definition: constraint_solver/table.cc:42
operations_research::sat::SatSolver::LiteralTrail
const Trail & LiteralTrail() const
Definition: sat_solver.h:362
kint32max
static const int32 kint32max
Definition: integral_types.h:59
operations_research::bop::BopOptimizerBase::INFEASIBLE
@ INFEASIBLE
Definition: bop_base.h:64
time_limit
SharedTimeLimit * time_limit
Definition: cp_model_solver.cc:2103
operations_research::bop::OneFlipConstraintRepairer::kInvalidConstraint
static const ConstraintIndex kInvalidConstraint
Definition: bop_ls.h:443
operations_research::bop::LearnedInfo
Definition: bop_base.h:245
operations_research::bop::ProblemState
Definition: bop_base.h:111
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::SetReferenceSolution
void SetReferenceSolution(const BopSolution &reference_solution)
Definition: bop_ls.cc:242
CHECK_EQ
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:697
operations_research::bop::OneFlipConstraintRepairer::ConstraintTerm::var
VariableIndex var
Definition: bop_ls.h:480
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::kObjectiveConstraint
static const ConstraintIndex kObjectiveConstraint
Definition: bop_ls.h:271
operations_research::bop::LocalSearchAssignmentIterator::Synchronize
void Synchronize(const ProblemState &problem_state)
Definition: bop_ls.cc:703
operations_research::sat::SatSolver::deterministic_time
double deterministic_time() const
Definition: sat_solver.cc:92
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::Assign
void Assign(const std::vector< sat::Literal > &literals)
Definition: bop_ls.cc:295
operations_research::bop::ExtractLearnedInfoFromSatSolver
void ExtractLearnedInfoFromSatSolver(sat::SatSolver *solver, LearnedInfo *info)
Definition: bop_util.cc:98
ct
const Constraint * ct
Definition: demon_profiler.cc:42
operations_research::bop::SatWrapper::IsModelUnsat
bool IsModelUnsat() const
Definition: bop_ls.h:62
operations_research::bop::SatWrapper::ApplyDecision
int ApplyDecision(sat::Literal decision_literal, std::vector< sat::Literal > *propagated_literals)
Definition: bop_ls.cc:628
operations_research::bop::SatWrapper::BacktrackAll
void BacktrackAll()
Definition: bop_ls.cc:617
bop_util.h
operations_research::bop::LocalSearchAssignmentIterator::deterministic_time
double deterministic_time() const
Definition: bop_ls.cc:818
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer
Definition: bop_ls.h:262
operations_research::bop::LocalSearchOptimizer::~LocalSearchOptimizer
~LocalSearchOptimizer() override
Definition: bop_ls.cc:41
uint64
uint64_t uint64
Definition: integral_types.h:39
operations_research::bop::LocalSearchOptimizer::LocalSearchOptimizer
LocalSearchOptimizer(const std::string &name, int max_num_decisions, sat::SatSolver *sat_propagator)
Definition: bop_ls.cc:32
operations_research::bop::OneFlipConstraintRepairer
Definition: bop_ls.h:430
CHECK_LE
#define CHECK_LE(val1, val2)
Definition: base/logging.h:699
operations_research::bop::BopOptimizerBase::OPTIMAL_SOLUTION_FOUND
@ OPTIMAL_SOLUTION_FOUND
Definition: bop_base.h:62
operations_research::bop::LocalSearchAssignmentIterator::LocalSearchAssignmentIterator
LocalSearchAssignmentIterator(const ProblemState &problem_state, int max_num_decisions, int max_num_broken_constraints, SatWrapper *sat_wrapper)
Definition: bop_ls.cc:673
operations_research::bop::OneFlipConstraintRepairer::GetFlip
sat::Literal GetFlip(ConstraintIndex ct_index, TermIndex term_index) const
Definition: bop_ls.cc:588
absl::StrongVector::clear
void clear()
Definition: strong_vector.h:170
operations_research::bop::OneFlipConstraintRepairer::ConstraintToRepair
ConstraintIndex ConstraintToRepair() const
Definition: bop_ls.cc:488
operations_research::sat::Literal
Definition: sat_base.h:64
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::AssignmentAndConstraintFeasibilityMaintainer
AssignmentAndConstraintFeasibilityMaintainer(const sat::LinearBooleanProblem &problem)
Definition: bop_ls.cc:179
absl::StrongVector
Definition: strong_vector.h:76
operations_research::bop::OneFlipConstraintRepairer::ConstraintTerm::weight
int64 weight
Definition: bop_ls.h:481
operations_research::bop::BacktrackableIntegerSet::ChangeState
void ChangeState(IntType i, bool should_be_inside)
Definition: bop_ls.cc:129
operations_research::bop::BopSolution::IsFeasible
bool IsFeasible() const
Definition: bop_solution.h:69
bop_ls.h
operations_research::bop::BacktrackableIntegerSet::BacktrackOneLevel
void BacktrackOneLevel()
Definition: bop_ls.cc:145
operations_research::bop::BacktrackableIntegerSet::AddBacktrackingLevel
void AddBacktrackingLevel()
Definition: bop_ls.cc:139
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::NumInfeasibleConstraints
int NumInfeasibleConstraints() const
Definition: bop_ls.h:316
operations_research::bop::OneFlipConstraintRepairer::kInvalidTerm
static const TermIndex kInvalidTerm
Definition: bop_ls.h:445
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::Assignment
bool Assignment(VariableIndex var) const
Definition: bop_ls.h:333
operations_research::sat::SatSolver::Backtrack
void Backtrack(int target_level)
Definition: sat_solver.cc:888
operations_research::bop::LocalSearchAssignmentIterator::NextAssignment
bool NextAssignment()
Definition: bop_ls.cc:758
DCHECK_EQ
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:885
operations_research::bop::OneFlipConstraintRepairer::RepairIsValid
bool RepairIsValid(ConstraintIndex ct_index, TermIndex term_index) const
Definition: bop_ls.cc:571
delta
int64 delta
Definition: resource.cc:1684
b
int64 b
Definition: constraint_solver/table.cc:43
boolean_problem.h
operations_research::sat::VariablesAssignment::VariableIsAssigned
bool VariableIsAssigned(BooleanVariable var) const
Definition: sat_base.h:158
operations_research::bop::SatWrapper::deterministic_time
double deterministic_time() const
Definition: bop_ls.cc:665
CHECK_NE
#define CHECK_NE(val1, val2)
Definition: base/logging.h:698
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::BacktrackAll
void BacktrackAll()
Definition: bop_ls.cc:339
operations_research::sat::kObjectiveConstraint
constexpr int kObjectiveConstraint
Definition: presolve_context.h:33
operations_research::bop::SatWrapper::ExtractLearnedInfo
void ExtractLearnedInfo(LearnedInfo *info)
Definition: bop_ls.cc:661
operations_research::bop::BopOptimizerBase::CONTINUE
@ CONTINUE
Definition: bop_base.h:76
literal
Literal literal
Definition: optimization.cc:84
operations_research::sat::VariablesAssignment
Definition: sat_base.h:122
operations_research::bop::LocalSearchAssignmentIterator::DebugString
std::string DebugString() const
Definition: bop_ls.cc:822
operations_research::bop::NonOrderedSetHasher::IsInitialized
bool IsInitialized() const
Definition: bop_ls.h:230
operations_research::bop::AssignmentAndConstraintFeasibilityMaintainer::ConstraintValue
int64 ConstraintValue(ConstraintIndex constraint) const
Definition: bop_ls.h:351
operations_research::bop::BopOptimizerBase::Status
Status
Definition: bop_base.h:61
CHECK
#define CHECK(condition)
Definition: base/logging.h:495
operations_research::sat::SatSolver::IsModelUnsat
bool IsModelUnsat() const
Definition: sat_solver.h:137
parameters
SatParameters parameters
Definition: cp_model_fz_solver.cc:108
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
operations_research::sat::Trail
Definition: sat_base.h:233
operations_research::bop::SatWrapper::BacktrackOneLevel
void BacktrackOneLevel()
Definition: bop_ls.cc:654
kint64max
static const int64 kint64max
Definition: integral_types.h:62