From ea71f58ef213945cea968c0e5180065e8cd1a580 Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Fri, 9 Dec 2016 14:15:01 +0100 Subject: [PATCH] minor sync with internal code --- examples/cpp/fap_model_printer.cc | 2 +- examples/cpp/sat_runner.cc | 7 +++++-- src/glop/lp_solver.cc | 33 +++++++++++++++++++++++++++++++ src/glop/lp_solver.h | 17 ++++++++++++++++ src/glop/revised_simplex.cc | 10 ++-------- src/glop/revised_simplex.h | 17 ++++++---------- 6 files changed, 64 insertions(+), 22 deletions(-) diff --git a/examples/cpp/fap_model_printer.cc b/examples/cpp/fap_model_printer.cc index 8774098062..acc070d677 100644 --- a/examples/cpp/fap_model_printer.cc +++ b/examples/cpp/fap_model_printer.cc @@ -40,7 +40,7 @@ void FapModelPrinter::PrintFapVariables() { for (const int value : it.second.domain) { StringAppendF(&domain, "%d ", value); } - StringAppendF(&domain, "}"); + domain.append("}"); std::string hard = " "; if (it.second.hard) { diff --git a/examples/cpp/sat_runner.cc b/examples/cpp/sat_runner.cc index ed9ed876e3..ba3a6fec43 100644 --- a/examples/cpp/sat_runner.cc +++ b/examples/cpp/sat_runner.cc @@ -337,6 +337,9 @@ int Run() { printf("s UNSATISFIABLE\n"); } + // Print status. + printf("c status: %s\n", SatStatusString(result).c_str()); + // Print objective value. if (solution.empty()) { printf("c objective: na\n"); @@ -349,13 +352,13 @@ int Run() { } // Print final statistics. - printf("c status: %s\n", SatStatusString(result).c_str()); + printf("c booleans: %d\n", solver->NumVariables()); printf("c conflicts: %lld\n", solver->num_failures()); printf("c branches: %lld\n", solver->num_branches()); printf("c propagations: %lld\n", solver->num_propagations()); printf("c walltime: %f\n", wall_timer.Get()); printf("c usertime: %f\n", user_timer.Get()); - printf("c deterministic time: %f\n", solver->deterministic_time()); + printf("c deterministic_time: %f\n", solver->deterministic_time()); // The SAT competition requires a particular exit code and since we don't // really use it for any other purpose, we comply. diff --git a/src/glop/lp_solver.cc b/src/glop/lp_solver.cc index 28e791b4a1..ee8053cc1c 100644 --- a/src/glop/lp_solver.cc +++ b/src/glop/lp_solver.cc @@ -194,6 +194,39 @@ void LPSolver::Clear() { revised_simplex_.reset(nullptr); } +void LPSolver::SetInitialBasis( + const VariableStatusRow& variable_statuses, + const ConstraintStatusColumn& constraint_statuses) { + // Create the associated basis state. + BasisState state; + state.statuses = variable_statuses; + for (const ConstraintStatus status : constraint_statuses) { + // Note the change of upper/lower bound between the status of a constraint + // and the status of its associated slack variable. + switch (status) { + case ConstraintStatus::FREE: + state.statuses.push_back(VariableStatus::FREE); + break; + case ConstraintStatus::AT_LOWER_BOUND: + state.statuses.push_back(VariableStatus::AT_UPPER_BOUND); + break; + case ConstraintStatus::AT_UPPER_BOUND: + state.statuses.push_back(VariableStatus::AT_LOWER_BOUND); + break; + case ConstraintStatus::FIXED_VALUE: + state.statuses.push_back(VariableStatus::FIXED_VALUE); + break; + case ConstraintStatus::BASIC: + state.statuses.push_back(VariableStatus::BASIC); + break; + } + } + if (revised_simplex_ == nullptr) { + revised_simplex_.reset(new RevisedSimplex()); + } + revised_simplex_->LoadStateForNextSolve(state); +} + namespace { // Computes the "real" problem objective from the one without offset nor // scaling. diff --git a/src/glop/lp_solver.h b/src/glop/lp_solver.h index e37b5ebeb1..5a715f1a92 100644 --- a/src/glop/lp_solver.h +++ b/src/glop/lp_solver.h @@ -63,6 +63,23 @@ class LPSolver { // result, assuming that no time limit was specified. void Clear(); + // Advanced usage. This should be called before calling Solve(). It will + // configure the solver to try to start from the given point. Note that + // calling Clear() will invalidate this information. + // + // If the set of variables/constraints with a BASIC status does not form a + // basis a warning will be logged and the code will ignore it. Otherwise, the + // non-basic variables will be initialized to their given status and solving + // will start from there (even if the solution is not primal/dual feasible). + // + // Important: There is no facility to transform this information in sync with + // presolve. So you should probably disable presolve when using this since + // otherwise there is a good chance that the matrix will change and that the + // given basis will make no sense. Even worse if it happens to be factorizable + // but doesn't correspond to what was intended. + void SetInitialBasis(const VariableStatusRow& variable_statuses, + const ConstraintStatusColumn& constraint_statuses); + // This loads a given solution and computes related quantities so that the // getters below will refer to it. // diff --git a/src/glop/revised_simplex.cc b/src/glop/revised_simplex.cc index cfb052c31f..e7735fd3cb 100644 --- a/src/glop/revised_simplex.cc +++ b/src/glop/revised_simplex.cc @@ -118,8 +118,6 @@ RevisedSimplex::RevisedSimplex() void RevisedSimplex::ClearStateForNextSolve() { SCOPED_TIME_STAT(&function_stats_); - solution_state_.num_rows = RowIndex(0); - solution_state_.num_cols = ColIndex(0); solution_state_.statuses.clear(); } @@ -834,10 +832,8 @@ void RevisedSimplex::InitializeVariableStatusesForWarmStart( // Start with the given "warm" status from the BasisState if it exists. VariableStatus status = default_status; - if (col < num_cols_) { - if (col < state.num_cols) { - status = state.statuses[col]; - } + if (col < state.statuses.size()) { + status = state.statuses[col]; } // Remove incompatibilities between the warm status and the variable bounds. @@ -1176,8 +1172,6 @@ void RevisedSimplex::DisplayBasicVariableStatistics() { void RevisedSimplex::SaveState() { DCHECK_EQ(num_cols_, variables_info_.GetStatusRow().size()); - solution_state_.num_rows = num_rows_; - solution_state_.num_cols = num_cols_; solution_state_.statuses = variables_info_.GetStatusRow(); solution_state_has_been_set_externally_ = false; } diff --git a/src/glop/revised_simplex.h b/src/glop/revised_simplex.h index 230a822f75..40afff2ee7 100644 --- a/src/glop/revised_simplex.h +++ b/src/glop/revised_simplex.h @@ -120,24 +120,19 @@ namespace operations_research { namespace glop { -// This is the minimal amount of information needed to perform a "warm start". +// Holds the statuses of the all the variables, including slack variables. There +// is no point storing constraint statuses since internally all constraints are +// always fixed to zero. // -// Holds the statuses of the variables and the slack variables. Using this -// information and the original linear program, the basis can be refactorized -// and all the needed quantities derived. +// Note that this is the minimal amount of information needed to perform a "warm +// start". Using this information and the original linear program, the basis can +// be refactorized and all the needed quantities derived. // // TODO(user): Introduce another state class to store a complete state of the // solver. Using this state and the original linear program, the solver can be // restarted with as little time overhead as possible. This is especially useful // for strong branching in a MIP context. struct BasisState { - // The linear program size for which this state was saved. - RowIndex num_rows; - ColIndex num_cols; - - // This vector first contains the num_cols normal variable statuses and then - // the num_rows slack variable statuses. - // // TODO(user): A MIP solver will potentially store a lot of BasicStates so // memory usage is important. It is possible to use only 2 bits for one // VariableStatus enum. To achieve this, the FIXED_VALUE status can be