Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
bop_lns.cc
Go to the documentation of this file.
1// Copyright 2010-2024 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_lns.h"
15
16#include <algorithm>
17#include <cmath>
18#include <deque>
19#include <memory>
20#include <vector>
21
22#include "absl/cleanup/cleanup.h"
23#include "absl/log/check.h"
24#include "absl/random/bit_gen_ref.h"
25#include "absl/random/distributions.h"
26#include "absl/strings/string_view.h"
30#include "ortools/bop/bop_parameters.pb.h"
38#include "ortools/sat/boolean_problem.pb.h"
42#include "ortools/sat/sat_parameters.pb.h"
44#include "ortools/util/stats.h"
47
48namespace operations_research {
49namespace bop {
50
51using ::operations_research::glop::ColIndex;
52using ::operations_research::glop::DenseRow;
53using ::operations_research::sat::LinearBooleanConstraint;
54using ::operations_research::sat::LinearBooleanProblem;
55
56//------------------------------------------------------------------------------
57// BopCompleteLNSOptimizer
58//------------------------------------------------------------------------------
59
60namespace {
61void UseBopSolutionForSatAssignmentPreference(const BopSolution& solution,
62 sat::SatSolver* solver) {
63 for (int i = 0; i < solution.Size(); ++i) {
64 solver->SetAssignmentPreference(
65 sat::Literal(sat::BooleanVariable(i), solution.Value(VariableIndex(i))),
66 1.0);
67 }
68}
69} // namespace
70
72 absl::string_view name, const BopConstraintTerms& objective_terms)
74 state_update_stamp_(ProblemState::kInitialStampValue),
75 objective_terms_(objective_terms) {}
76
78
79BopOptimizerBase::Status BopCompleteLNSOptimizer::SynchronizeIfNeeded(
80 const ProblemState& problem_state, int num_relaxed_vars) {
81 if (state_update_stamp_ == problem_state.update_stamp()) {
83 }
84 state_update_stamp_ = problem_state.update_stamp();
85
86 // Load the current problem to the solver.
87 sat_solver_ = std::make_unique<sat::SatSolver>();
89 LoadStateProblemToSatSolver(problem_state, sat_solver_.get());
91
92 // Add the constraint that forces the solver to look for a solution
93 // at a distance <= num_relaxed_vars from the current one. Note that not all
94 // the terms appear in this constraint.
95 //
96 // TODO(user): if the current solution didn't change, there is no need to
97 // re-run this optimizer if we already proved UNSAT.
98 std::vector<sat::LiteralWithCoeff> cst;
99 for (BopConstraintTerm term : objective_terms_) {
100 if (problem_state.solution().Value(term.var_id) && term.weight < 0) {
101 cst.push_back(sat::LiteralWithCoeff(
102 sat::Literal(sat::BooleanVariable(term.var_id.value()), false), 1.0));
103 } else if (!problem_state.solution().Value(term.var_id) &&
104 term.weight > 0) {
105 cst.push_back(sat::LiteralWithCoeff(
106 sat::Literal(sat::BooleanVariable(term.var_id.value()), true), 1.0));
107 }
108 }
109 sat_solver_->AddLinearConstraint(
110 /*use_lower_bound=*/false, sat::Coefficient(0),
111 /*use_upper_bound=*/true, sat::Coefficient(num_relaxed_vars), &cst);
112
113 if (sat_solver_->IsModelUnsat()) return BopOptimizerBase::ABORT;
114
115 // It sounds like a good idea to force the solver to find a similar solution
116 // from the current one. On another side, this is already somewhat enforced by
117 // the constraint above, so it will need more investigation.
118 UseBopSolutionForSatAssignmentPreference(problem_state.solution(),
119 sat_solver_.get());
121}
122
123bool BopCompleteLNSOptimizer::ShouldBeRun(
124 const ProblemState& problem_state) const {
125 return problem_state.solution().IsFeasible();
126}
127
128BopOptimizerBase::Status BopCompleteLNSOptimizer::Optimize(
129 const BopParameters& parameters, const ProblemState& problem_state,
130 LearnedInfo* learned_info, TimeLimit* time_limit) {
132 CHECK(learned_info != nullptr);
133 CHECK(time_limit != nullptr);
134 learned_info->Clear();
135
136 const BopOptimizerBase::Status sync_status =
137 SynchronizeIfNeeded(problem_state, parameters.num_relaxed_vars());
138 if (sync_status != BopOptimizerBase::CONTINUE) {
139 return sync_status;
140 }
141
142 CHECK(sat_solver_ != nullptr);
143 const double initial_dt = sat_solver_->deterministic_time();
144 auto advance_dt = ::absl::MakeCleanup([initial_dt, this, &time_limit]() {
145 time_limit->AdvanceDeterministicTime(sat_solver_->deterministic_time() -
146 initial_dt);
147 });
148
149 // Set the parameters for this run.
150 // TODO(user): Because of this, we actually loose the perfect continuity
151 // between runs, and the restart policy is resetted... Fix this.
152 sat::SatParameters sat_params;
153 sat_params.set_max_number_of_conflicts(
154 parameters.max_number_of_conflicts_in_random_lns());
155 sat_params.set_max_time_in_seconds(time_limit->GetTimeLeft());
156 sat_params.set_max_deterministic_time(time_limit->GetDeterministicTimeLeft());
157 sat_params.set_random_seed(parameters.random_seed());
158
159 sat_solver_->SetParameters(sat_params);
160 const sat::SatSolver::Status sat_status = sat_solver_->Solve();
161 if (sat_status == sat::SatSolver::FEASIBLE) {
162 SatAssignmentToBopSolution(sat_solver_->Assignment(),
163 &learned_info->solution);
165 }
166 if (sat_status == sat::SatSolver::LIMIT_REACHED) {
168 }
169
170 // Because of the "LNS" constraint, we can't deduce anything about the problem
171 // in this case.
173}
174
175//------------------------------------------------------------------------------
176// BopAdaptiveLNSOptimizer
177//------------------------------------------------------------------------------
178
179namespace {
180// Returns false if the limit is reached while solving the LP.
181bool UseLinearRelaxationForSatAssignmentPreference(
182 const BopParameters& parameters, const LinearBooleanProblem& problem,
183 sat::SatSolver* sat_solver, TimeLimit* time_limit) {
184 // TODO(user): Re-use the lp_model and lp_solver or build a model with only
185 // needed constraints and variables.
186 glop::LinearProgram lp_model;
188
189 // Set bounds of variables fixed by the sat_solver.
190 const sat::Trail& propagation_trail = sat_solver->LiteralTrail();
191 for (int trail_index = 0; trail_index < propagation_trail.Index();
192 ++trail_index) {
193 const sat::Literal fixed_literal = propagation_trail[trail_index];
194 const glop::Fractional value = fixed_literal.IsPositive() ? 1.0 : 0.0;
195 lp_model.SetVariableBounds(ColIndex(fixed_literal.Variable().value()),
196 value, value);
197 }
198
199 glop::LPSolver lp_solver;
200 NestedTimeLimit nested_time_limit(time_limit, time_limit->GetTimeLeft(),
201 parameters.lp_max_deterministic_time());
202 const glop::ProblemStatus lp_status =
203 lp_solver.SolveWithTimeLimit(lp_model, nested_time_limit.GetTimeLimit());
204
205 if (lp_status != glop::ProblemStatus::OPTIMAL &&
207 lp_status != glop::ProblemStatus::IMPRECISE) {
208 // We have no useful information from the LP, we will abort this LNS.
209 return false;
210 }
211
212 // Set preferences based on the solution of the relaxation.
213 for (ColIndex col(0); col < lp_solver.variable_values().size(); ++col) {
214 const double value = lp_solver.variable_values()[col];
215 sat_solver->SetAssignmentPreference(
216 sat::Literal(sat::BooleanVariable(col.value()), round(value) == 1),
217 1 - fabs(value - round(value)));
218 }
219 return true;
220}
221} // namespace
222
223// Note(user): We prefer to start with a really low difficulty as this works
224// better for large problem, and for small ones, it will be really quickly
225// increased anyway. Maybe a better approach is to start by relaxing something
226// like 10 variables instead of having a fixed percentage.
228 absl::string_view name, bool use_lp_to_guide_sat,
229 NeighborhoodGenerator* neighborhood_generator,
230 sat::SatSolver* sat_propagator)
232 use_lp_to_guide_sat_(use_lp_to_guide_sat),
233 neighborhood_generator_(neighborhood_generator),
234 sat_propagator_(sat_propagator),
235 adaptive_difficulty_(0.001) {
236 CHECK(sat_propagator != nullptr);
237}
238
240
241bool BopAdaptiveLNSOptimizer::ShouldBeRun(
242 const ProblemState& problem_state) const {
243 return problem_state.solution().IsFeasible();
244}
245
246BopOptimizerBase::Status BopAdaptiveLNSOptimizer::Optimize(
247 const BopParameters& parameters, const ProblemState& problem_state,
248 LearnedInfo* learned_info, TimeLimit* time_limit) {
250 CHECK(learned_info != nullptr);
251 CHECK(time_limit != nullptr);
252 learned_info->Clear();
253
254 // Set-up a sat_propagator_ cleanup task to catch all the exit cases.
255 const double initial_dt = sat_propagator_->deterministic_time();
256 auto sat_propagator_cleanup =
257 ::absl::MakeCleanup([initial_dt, this, &learned_info, &time_limit]() {
258 if (!sat_propagator_->IsModelUnsat()) {
259 sat_propagator_->SetAssumptionLevel(0);
260 sat_propagator_->RestoreSolverToAssumptionLevel();
261 ExtractLearnedInfoFromSatSolver(sat_propagator_, learned_info);
262 }
263 time_limit->AdvanceDeterministicTime(
264 sat_propagator_->deterministic_time() - initial_dt);
265 });
266
267 // For the SAT conflicts limit of each LNS, we follow a luby sequence times
268 // the base number of conflicts (num_conflicts_). Note that the numbers of the
269 // Luby sequence are always power of two.
270 //
271 // We dynamically change the size of the neighborhood depending on the
272 // difficulty of the problem. There is one "target" difficulty for each
273 // different numbers in the Luby sequence. Note that the initial value is
274 // reused from the last run.
275 const BopParameters& local_parameters = parameters;
276 int num_tries = 0; // TODO(user): remove? our limit is 1 by default.
277 while (!time_limit->LimitReached() &&
278 num_tries < local_parameters.num_random_lns_tries()) {
279 // Compute the target problem difficulty and generate the neighborhood.
280 adaptive_difficulty_.UpdateLuby();
281 const double difficulty = adaptive_difficulty_.GetParameterValue();
282 neighborhood_generator_->GenerateNeighborhood(problem_state, difficulty,
283 sat_propagator_);
284
285 ++num_tries;
286 VLOG(2) << num_tries << " difficulty:" << difficulty
287 << " luby:" << adaptive_difficulty_.luby_value()
288 << " fixed:" << sat_propagator_->LiteralTrail().Index() << "/"
289 << problem_state.original_problem().num_variables();
290
291 // Special case if the difficulty is too high.
292 if (!sat_propagator_->IsModelUnsat()) {
293 if (sat_propagator_->CurrentDecisionLevel() == 0) {
294 VLOG(2) << "Nothing fixed!";
295 adaptive_difficulty_.DecreaseParameter();
296 continue;
297 }
298 }
299
300 // Since everything is already set-up, we try the sat_propagator_ with
301 // a really low conflict limit. This allow to quickly skip over UNSAT
302 // cases without the costly new problem setup.
303 if (!sat_propagator_->IsModelUnsat()) {
304 sat::SatParameters params;
305 params.set_max_number_of_conflicts(
306 local_parameters.max_number_of_conflicts_for_quick_check());
307 params.set_max_time_in_seconds(time_limit->GetTimeLeft());
308 params.set_max_deterministic_time(time_limit->GetDeterministicTimeLeft());
309 params.set_random_seed(parameters.random_seed());
310 sat_propagator_->SetParameters(params);
311 sat_propagator_->SetAssumptionLevel(
312 sat_propagator_->CurrentDecisionLevel());
313
314 const sat::SatSolver::Status status = sat_propagator_->Solve();
316 adaptive_difficulty_.IncreaseParameter();
317 SatAssignmentToBopSolution(sat_propagator_->Assignment(),
318 &learned_info->solution);
321 // Local problem is infeasible.
322 adaptive_difficulty_.IncreaseParameter();
323 continue;
324 }
325 }
326
327 // Restore to the assumption level.
328 // This is call is important since all the fixed variable in the
329 // propagator_ will be used to construct the local problem below.
330 // Note that calling RestoreSolverToAssumptionLevel() might actually prove
331 // the infeasibility. It is important to check the UNSAT status afterward.
332 if (!sat_propagator_->IsModelUnsat()) {
333 sat_propagator_->RestoreSolverToAssumptionLevel();
334 }
335
336 // Check if the problem is proved UNSAT, by previous the search or the
337 // RestoreSolverToAssumptionLevel() call above.
338 if (sat_propagator_->IsModelUnsat()) {
339 return problem_state.solution().IsFeasible()
342 }
343
344 // Construct and Solve the LNS subproblem.
345 //
346 // Note that we don't use the sat_propagator_ all the way because using a
347 // clean solver on a really small problem is usually a lot faster (even we
348 // the time to create the subproblem) that running a long solve under
349 // assumption (like we did above with a really low conflit limit).
350 const int conflict_limit =
351 adaptive_difficulty_.luby_value() *
352 parameters.max_number_of_conflicts_in_random_lns();
353
354 sat::SatParameters params;
355 params.set_max_number_of_conflicts(conflict_limit);
356 params.set_max_time_in_seconds(time_limit->GetTimeLeft());
357 params.set_max_deterministic_time(time_limit->GetDeterministicTimeLeft());
358 params.set_random_seed(parameters.random_seed());
359
360 sat::SatSolver sat_solver;
361 sat_solver.SetParameters(params);
362
363 // Starts by adding the unit clauses to fix the variables.
364 const LinearBooleanProblem& problem = problem_state.original_problem();
365 sat_solver.SetNumVariables(problem.num_variables());
366 for (int i = 0; i < sat_propagator_->LiteralTrail().Index(); ++i) {
367 CHECK(sat_solver.AddUnitClause(sat_propagator_->LiteralTrail()[i]));
368 }
369
370 // Load the rest of the problem. This will automatically create the small
371 // local subproblem using the already fixed variable.
372 //
373 // TODO(user): modify LoadStateProblemToSatSolver() so that we can call it
374 // instead and don't need to over constraint the objective below. As a
375 // bonus we will also have the learned binary clauses.
376 if (!LoadBooleanProblem(problem, &sat_solver)) {
377 // The local problem is infeasible.
378 adaptive_difficulty_.IncreaseParameter();
379 continue;
380 }
381
382 if (use_lp_to_guide_sat_) {
383 if (!UseLinearRelaxationForSatAssignmentPreference(
384 parameters, problem, &sat_solver, time_limit)) {
386 }
387 } else {
388 UseObjectiveForSatAssignmentPreference(problem, &sat_solver);
389 }
390
392 problem, sat::Coefficient(problem_state.solution().GetCost()) - 1,
393 &sat_solver)) {
394 // The local problem is infeasible.
395 adaptive_difficulty_.IncreaseParameter();
396 continue;
397 }
398
399 // Solve the local problem.
400 const sat::SatSolver::Status status = sat_solver.Solve();
401 time_limit->AdvanceDeterministicTime(sat_solver.deterministic_time());
403 // We found a solution! abort now.
404 SatAssignmentToBopSolution(sat_solver.Assignment(),
405 &learned_info->solution);
407 }
408
409 // Adapt the difficulty.
410 if (sat_solver.num_failures() < 0.5 * conflict_limit) {
411 adaptive_difficulty_.IncreaseParameter();
412 } else if (sat_solver.num_failures() > 0.95 * conflict_limit) {
413 adaptive_difficulty_.DecreaseParameter();
414 }
415 }
416
418}
419
420//------------------------------------------------------------------------------
421// Neighborhood generators.
422//------------------------------------------------------------------------------
423
424namespace {
425
426std::vector<sat::Literal> ObjectiveVariablesAssignedToTheirLowCostValue(
427 const ProblemState& problem_state,
428 const BopConstraintTerms& objective_terms) {
429 std::vector<sat::Literal> result;
430 DCHECK(problem_state.solution().IsFeasible());
431 for (const BopConstraintTerm& term : objective_terms) {
432 if (((problem_state.solution().Value(term.var_id) && term.weight < 0) ||
433 (!problem_state.solution().Value(term.var_id) && term.weight > 0))) {
434 result.push_back(
435 sat::Literal(sat::BooleanVariable(term.var_id.value()),
436 problem_state.solution().Value(term.var_id)));
437 }
438 }
439 return result;
440}
441
442} // namespace
443
444void ObjectiveBasedNeighborhood::GenerateNeighborhood(
445 const ProblemState& problem_state, double difficulty,
446 sat::SatSolver* sat_propagator) {
447 // Generate the set of variable we may fix and randomize their order.
448 std::vector<sat::Literal> candidates =
449 ObjectiveVariablesAssignedToTheirLowCostValue(problem_state,
450 objective_terms_);
451 std::shuffle(candidates.begin(), candidates.end(), random_);
452
453 // We will use the sat_propagator to fix some variables as long as the number
454 // of propagated variables in the solver is under our target.
455 const int num_variables = sat_propagator->NumVariables();
456 const int target = round((1.0 - difficulty) * num_variables);
457
458 sat_propagator->Backtrack(0);
459 for (const sat::Literal literal : candidates) {
460 if (sat_propagator->LiteralTrail().Index() == target) break;
461 if (sat_propagator->LiteralTrail().Index() > target) {
462 // We prefer to error on the large neighborhood side, so we backtrack the
463 // last enqueued literal.
464 sat_propagator->Backtrack(
465 std::max(0, sat_propagator->CurrentDecisionLevel() - 1));
466 break;
467 }
468 sat_propagator->EnqueueDecisionAndBacktrackOnConflict(literal);
469 if (sat_propagator->IsModelUnsat()) return;
470 }
471}
472
473void ConstraintBasedNeighborhood::GenerateNeighborhood(
474 const ProblemState& problem_state, double difficulty,
475 sat::SatSolver* sat_propagator) {
476 // Randomize the set of constraint
477 const LinearBooleanProblem& problem = problem_state.original_problem();
478 const int num_constraints = problem.constraints_size();
479 std::vector<int> ct_ids(num_constraints, 0);
480 for (int ct_id = 0; ct_id < num_constraints; ++ct_id) ct_ids[ct_id] = ct_id;
481 std::shuffle(ct_ids.begin(), ct_ids.end(), random_);
482
483 // Mark that we want to relax all the variables of these constraints as long
484 // as the number of relaxed variable is lower than our difficulty target.
485 const int num_variables = sat_propagator->NumVariables();
486 const int target = round(difficulty * num_variables);
487 int num_relaxed = 0;
488 std::vector<bool> variable_is_relaxed(problem.num_variables(), false);
489 for (int i = 0; i < ct_ids.size(); ++i) {
490 if (num_relaxed >= target) break;
491 const LinearBooleanConstraint& constraint = problem.constraints(ct_ids[i]);
492
493 // We exclude really large constraints since they are probably note helpful
494 // in picking a nice neighborhood.
495 if (constraint.literals_size() > 0.7 * num_variables) continue;
496
497 for (int j = 0; j < constraint.literals_size(); ++j) {
498 const VariableIndex var_id(constraint.literals(j) - 1);
499 if (!variable_is_relaxed[var_id.value()]) {
500 ++num_relaxed;
501 variable_is_relaxed[var_id.value()] = true;
502 }
503 }
504 }
505
506 // Basic version: simply fix all the "to_fix" variable that are not relaxed.
507 //
508 // TODO(user): Not fixing anything that propagates a variable in
509 // variable_is_relaxed may be better. It is actually a lot better in the
510 // RelationGraphBasedNeighborhood. To investigate.
511 sat_propagator->Backtrack(0);
512 const std::vector<sat::Literal> to_fix =
513 ObjectiveVariablesAssignedToTheirLowCostValue(problem_state,
514 objective_terms_);
515 for (const sat::Literal literal : to_fix) {
516 if (variable_is_relaxed[literal.Variable().value()]) continue;
517 sat_propagator->EnqueueDecisionAndBacktrackOnConflict(literal);
518 if (sat_propagator->IsModelUnsat()) return;
519 }
520}
521
523 const LinearBooleanProblem& problem, absl::BitGenRef random)
524 : random_(random) {
525 const int num_variables = problem.num_variables();
526 columns_.resize(num_variables);
527
528 // We will ignore constraints that have more variables than this percentage of
529 // the total number of variables in this neighborhood computation.
530 //
531 // TODO(user): Factor this out with the similar factor in
532 // ConstraintBasedNeighborhood? also maybe a better approach is to order the
533 // constraint, and stop the neighborhood extension without considering all of
534 // them.
535 const double kSizeThreshold = 0.1;
536 for (int i = 0; i < problem.constraints_size(); ++i) {
537 const LinearBooleanConstraint& constraint = problem.constraints(i);
538 if (constraint.literals_size() > kSizeThreshold * num_variables) continue;
539 for (int j = 0; j < constraint.literals_size(); ++j) {
540 const sat::Literal literal(constraint.literals(j));
541 columns_[VariableIndex(literal.Variable().value())].push_back(
542 ConstraintIndex(i));
543 }
544 }
545}
546
547void RelationGraphBasedNeighborhood::GenerateNeighborhood(
548 const ProblemState& problem_state, double difficulty,
549 sat::SatSolver* sat_propagator) {
550 // Simply walk the graph until enough variable are relaxed.
551 const int num_variables = sat_propagator->NumVariables();
552 const int target = round(difficulty * num_variables);
553 int num_relaxed = 1;
554 std::vector<bool> variable_is_relaxed(num_variables, false);
555 std::deque<int> queue;
556
557 // TODO(user): If one plan to try of lot of different LNS, maybe it will be
558 // better to try to bias the distribution of "center" to be as spread as
559 // possible.
560 queue.push_back(absl::Uniform(random_, 0, num_variables));
561 variable_is_relaxed[queue.back()] = true;
562 while (!queue.empty() && num_relaxed < target) {
563 const int var = queue.front();
564 queue.pop_front();
565 for (ConstraintIndex ct_index : columns_[VariableIndex(var)]) {
566 const LinearBooleanConstraint& constraint =
567 problem_state.original_problem().constraints(ct_index.value());
568 for (int i = 0; i < constraint.literals_size(); ++i) {
569 const sat::Literal literal(constraint.literals(i));
570 const int next_var = literal.Variable().value();
571 if (!variable_is_relaxed[next_var]) {
572 ++num_relaxed;
573 variable_is_relaxed[next_var] = true;
574 queue.push_back(next_var);
575 }
576 }
577 }
578 }
579
580 // Loops over all the variables in order and only fix the ones that don't
581 // propagate any relaxed variables.
582 DCHECK(problem_state.solution().IsFeasible());
583 sat_propagator->Backtrack(0);
584 for (sat::BooleanVariable var(0); var < num_variables; ++var) {
585 const sat::Literal literal(
586 var, problem_state.solution().Value(VariableIndex(var.value())));
587 if (variable_is_relaxed[literal.Variable().value()]) continue;
588 int index;
590 if (sat_propagator->CurrentDecisionLevel() > 0) {
591 for (int i = index; i < sat_propagator->LiteralTrail().Index(); ++i) {
592 if (variable_is_relaxed
593 [sat_propagator->LiteralTrail()[i].Variable().value()]) {
594 sat_propagator->Backtrack(sat_propagator->CurrentDecisionLevel() - 1);
595 }
596 }
597 }
598 if (sat_propagator->IsModelUnsat()) return;
599 }
600 VLOG(2) << "target:" << target << " relaxed:" << num_relaxed << " actual:"
601 << num_variables - sat_propagator->LiteralTrail().Index();
602}
603
604} // namespace bop
605} // namespace operations_research
IntegerValue size
BopAdaptiveLNSOptimizer(absl::string_view name, bool use_lp_to_guide_sat, NeighborhoodGenerator *neighborhood_generator, sat::SatSolver *sat_propagator)
Definition bop_lns.cc:231
BopCompleteLNSOptimizer(absl::string_view name, const BopConstraintTerms &objective_terms)
Definition bop_lns.cc:73
@ ABORT
There is no need to call this optimizer again on the same problem state.
Definition bop_base.h:87
bool Value(VariableIndex var) const
const BopSolution & solution() const
Definition bop_base.h:205
RelationGraphBasedNeighborhood(const sat::LinearBooleanProblem &problem, absl::BitGenRef random)
Definition bop_lns.cc:528
Status EnqueueDecisionAndBacktrackOnConflict(Literal true_literal, int *first_propagation_index=nullptr)
void Backtrack(int target_level)
void SetAssumptionLevel(int assumption_level)
const VariablesAssignment & Assignment() const
Definition sat_solver.h:388
const Trail & LiteralTrail() const
Definition sat_solver.h:387
void SetParameters(const SatParameters &parameters)
SatParameters parameters
const std::string name
A name for logging purposes.
int64_t value
IntVar * var
absl::Status status
Definition g_gurobi.cc:44
int literal
int ct_index
time_limit
Definition solve.cc:22
int index
ColIndex col
Definition markowitz.cc:187
double solution
BopOptimizerBase::Status LoadStateProblemToSatSolver(const ProblemState &problem_state, sat::SatSolver *sat_solver)
Definition bop_util.cc:98
util_intops::StrongVector< SparseIndex, BopConstraintTerm > BopConstraintTerms
Definition bop_types.h:89
void SatAssignmentToBopSolution(const sat::VariablesAssignment &assignment, BopSolution *solution)
Definition bop_util.cc:132
void ExtractLearnedInfoFromSatSolver(sat::SatSolver *solver, LearnedInfo *info)
Definition bop_util.cc:109
ProblemStatus
Different statuses for a given problem.
Definition lp_types.h:107
bool LoadBooleanProblem(const LinearBooleanProblem &problem, SatSolver *solver)
Loads a BooleanProblem into a given SatSolver instance.
void ConvertBooleanProblemToLinearProgram(const LinearBooleanProblem &problem, glop::LinearProgram *lp)
Converts a Boolean optimization problem to its lp formulation.
Definition lp_utils.cc:1639
bool AddObjectiveUpperBound(const LinearBooleanProblem &problem, Coefficient upper_bound, SatSolver *solver)
Adds the constraint that the objective is smaller than the given upper bound.
void UseObjectiveForSatAssignmentPreference(const LinearBooleanProblem &problem, SatSolver *solver)
In SWIG mode, we don't want anything besides these top-level includes.
#define SCOPED_TIME_STAT(stats)
Definition stats.h:418
Represents a term in a pseudo-Boolean formula.