24 #include "absl/memory/memory.h"
25 #include "absl/strings/str_format.h"
26 #include "google/protobuf/text_format.h"
43 using ::operations_research::glop::ColIndex;
45 using ::operations_research::glop::GlopParameters;
46 using ::operations_research::glop::RowIndex;
52 return solution.IsFeasible() ? (solution.GetCost() <=
lower_bound
58 bool AllIntegralValues(
const DenseRow& values,
double tolerance) {
62 if (
value >= tolerance &&
value + tolerance < 1.0) {
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())]));
94 if (state_update_stamp_ == problem_state.
update_stamp()) {
101 sat_solver_ = std::make_unique<sat::SatSolver>();
105 .exploit_symmetry_in_sat_first_solution()) {
106 std::vector<std::unique_ptr<SparsePermutation>> generators;
109 std::unique_ptr<sat::SymmetryPropagator> propagator(
111 for (
int i = 0; i < generators.size(); ++i) {
112 propagator->AddSymmetry(std::move(generators[i]));
114 sat_solver_->AddPropagator(propagator.get());
115 sat_solver_->TakePropagatorOwnership(std::move(propagator));
129 sat_solver_->SetAssignmentPreference(
130 sat::Literal(sat::BooleanVariable(
col.value()), round(
value) == 1),
140 sat_solver_->SetAssignmentPreference(
141 sat::Literal(sat::BooleanVariable(i),
152 if (abort_)
return false;
166 CHECK(learned_info !=
nullptr);
168 learned_info->
Clear();
171 SynchronizeIfNeeded(problem_state);
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());
183 sat_params.set_max_number_of_conflicts(
185 sat_solver_->SetParameters(sat_params);
187 const double initial_deterministic_time = sat_solver_->deterministic_time();
189 time_limit->AdvanceDeterministicTime(sat_solver_->deterministic_time() -
190 initial_deterministic_time);
221 sat_propagator_(sat_propagator) {}
234 CHECK(learned_info !=
nullptr);
236 learned_info->
Clear();
239 const sat::SatParameters saved_params = sat_propagator_->
parameters();
240 const std::vector<std::pair<sat::Literal, double>> saved_prefs =
243 const int kMaxNumConflicts = 10;
247 int64_t remaining_num_conflicts =
248 parameters.max_number_of_conflicts_in_random_solution_generation();
249 int64_t old_num_failures = 0;
253 bool objective_need_to_be_overconstrained =
256 bool solution_found =
false;
257 while (remaining_num_conflicts > 0 && !
time_limit->LimitReached()) {
261 sat::SatParameters sat_params = saved_params;
263 sat_params.set_max_number_of_conflicts(kMaxNumConflicts);
267 if (objective_need_to_be_overconstrained) {
277 objective_need_to_be_overconstrained =
false;
281 const int preference = absl::Uniform(random_, 0, 4);
282 if (preference == 0) {
285 }
else if (preference == 1 && !problem_state.
lp_values().
empty()) {
298 objective_need_to_be_overconstrained =
true;
299 solution_found =
true;
314 remaining_num_conflicts -=
347 const std::string&
name)
351 lp_model_loaded_(false),
357 num_fixed_variables_(-1),
358 problem_already_solved_(false),
359 scaled_solution_cost_(glop::
kInfinity) {}
365 if (state_update_stamp_ == problem_state.
update_stamp()) {
373 parameters_.max_lp_solve_for_feasibility_problems() >= 0 &&
374 num_full_solves_ >= parameters_.max_lp_solve_for_feasibility_problems()) {
380 int num_fixed_variables = 0;
381 for (
const bool is_fixed : problem_state.
is_fixed()) {
383 ++num_fixed_variables;
386 problem_already_solved_ =
387 problem_already_solved_ && num_fixed_variables_ >= num_fixed_variables;
391 num_fixed_variables_ = num_fixed_variables;
392 if (!lp_model_loaded_) {
396 lp_model_loaded_ =
true;
407 if (parameters_.use_learned_binary_clauses_in_lp()) {
408 for (
const sat::BinaryClause& clause :
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());
422 (clause.a.IsPositive() ? name_a :
"not(" + name_a +
")") +
" or " +
423 (clause.b.IsPositive() ? name_b :
"not(" + name_b +
")"));
432 scaled_solution_cost_ =
447 parameters_.max_lp_solve_for_feasibility_problems() != 0;
453 CHECK(learned_info !=
nullptr);
455 learned_info->
Clear();
458 SynchronizeIfNeeded(problem_state);
471 problem_already_solved_ =
true;
488 if (parameters_.use_lp_strong_branching()) {
490 ComputeLowerBoundUsingStrongBranching(learned_info,
time_limit);
493 <<
" using strong branching.";
496 const int tolerance_sign = scaling_ < 0 ? 1 : -1;
497 const double unscaled_cost =
500 lp_solver_.
GetParameters().solution_feasibility_tolerance()) /
503 learned_info->
lower_bound =
static_cast<int64_t
>(ceil(unscaled_cost));
505 if (AllIntegralValues(
507 lp_solver_.
GetParameters().primal_feasibility_tolerance())) {
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);
531 parameters_.lp_max_deterministic_time());
533 lp_model_, nested_time_limit.GetTimeLimit());
537 double LinearRelaxation::ComputeLowerBoundUsingStrongBranching(
538 LearnedInfo* learned_info, TimeLimit*
time_limit) {
540 const double tolerance =
543 for (glop::ColIndex
col(0);
col < initial_lp_values.size(); ++
col) {
567 (initial_lp_values[
col] < tolerance ||
568 initial_lp_values[
col] + tolerance > 1)) {
572 double objective_true = best_lp_objective;
573 double objective_false = best_lp_objective;
597 std::max(objective_true, objective_false))
598 : std::
max(best_lp_objective,
599 std::
min(objective_true, objective_false));
603 if (CostIsWorseThanSolution(objective_true, tolerance)) {
607 learned_info->fixed_literals.push_back(
608 sat::Literal(sat::BooleanVariable(
col.value()),
false));
609 }
else if (CostIsWorseThanSolution(objective_false, tolerance)) {
613 learned_info->fixed_literals.push_back(
614 sat::Literal(sat::BooleanVariable(
col.value()),
true));
620 return best_lp_objective;
623 bool LinearRelaxation::CostIsWorseThanSolution(
double scaled_cost,
624 double tolerance)
const {
Provides a way to nest time limits for algorithms where a certain part of the computation is bounded ...
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
bool ShouldBeRun(const ProblemState &problem_state) const override
Status Optimize(const BopParameters ¶meters, const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override
~BopRandomFirstSolutionGenerator() override
BopRandomFirstSolutionGenerator(const std::string &name, const BopParameters ¶meters, sat::SatSolver *sat_propagator, absl::BitGenRef random)
double GetScaledCost() const
bool ShouldBeRun(const ProblemState &problem_state) const override
GuidedSatFirstSolutionGenerator(const std::string &name, Policy policy)
~GuidedSatFirstSolutionGenerator() override
Status Optimize(const BopParameters ¶meters, const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override
bool ShouldBeRun(const ProblemState &problem_state) const override
Status Optimize(const BopParameters ¶meters, const ProblemState &problem_state, LearnedInfo *learned_info, TimeLimit *time_limit) override
LinearRelaxation(const BopParameters ¶meters, const std::string &name)
~LinearRelaxation() override
const BopParameters & GetParameters() const
const sat::LinearBooleanProblem & original_problem() const
const std::vector< bool > assignment_preference() const
int64_t lower_bound() const
const glop::DenseRow & lp_values() const
const std::vector< sat::BinaryClause > & NewlyAddedBinaryClauses() const
bool IsVariableFixed(VariableIndex var) const
bool GetVariableFixedValue(VariableIndex var) const
int64_t update_stamp() const
const BopSolution & solution() const
int64_t upper_bound() const
const absl::StrongVector< VariableIndex, bool > & is_fixed() const
const GlopParameters & GetParameters() const
const DenseRow & variable_values() const
Fractional GetObjectiveValue() const
ABSL_MUST_USE_RESULT ProblemStatus SolveWithTimeLimit(const LinearProgram &lp, TimeLimit *time_limit)
void SetParameters(const GlopParameters ¶meters)
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
std::string GetVariableName(ColIndex col) const
void SetConstraintName(RowIndex row, absl::string_view name)
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
const DenseRow & variable_lower_bounds() const
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
bool IsMaximizationProblem() const
const DenseRow & variable_upper_bounds() const
RowIndex CreateNewConstraint()
std::vector< std::pair< Literal, double > > AllPreferences() const
const SatParameters & parameters() const
void ResetDecisionHeuristicAndSetAllPreferences(const std::vector< std::pair< Literal, double >> &prefs)
void ResetDecisionHeuristic()
Status SolveWithTimeLimit(TimeLimit *time_limit)
int AssumptionLevel() const
void SetAssignmentPreference(Literal literal, double weight)
const VariablesAssignment & Assignment() const
void SetParameters(const SatParameters ¶meters)
void Backtrack(int target_level)
bool RestoreSolverToAssumptionLevel()
int64_t num_failures() const
bool IsModelUnsat() const
ModelSharedTimeLimit * time_limit
BopOptimizerBase::Status LoadStateProblemToSatSolver(const ProblemState &problem_state, sat::SatSolver *sat_solver)
void SatAssignmentToBopSolution(const sat::VariablesAssignment &assignment, BopSolution *solution)
void ExtractLearnedInfoFromSatSolver(sat::SatSolver *solver, LearnedInfo *info)
StrictITIVector< ColIndex, Fractional > DenseRow
std::string GetProblemStatusString(ProblemStatus problem_status)
constexpr double kInfinity
std::tuple< int64_t, int64_t, const double > Coefficient
void RandomizeDecisionHeuristic(absl::BitGenRef random, SatParameters *parameters)
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.
constexpr double kInfinity
#define VLOG(verboselevel)