OR-Tools  9.6
bop_interface.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #include <atomic>
15 #include <cstdint>
16 #include <memory>
17 #include <string>
18 #include <utility>
19 #include <vector>
20 
21 #include "absl/base/attributes.h"
22 #include "google/protobuf/text_format.h"
24 #include "ortools/base/file.h"
25 #include "ortools/base/hash.h"
26 #include "ortools/base/helpers.h"
28 #include "ortools/base/logging.h"
29 #include "ortools/bop/bop_parameters.pb.h"
32 
33 namespace operations_research {
34 namespace {
35 
36 MPSolver::ResultStatus TranslateProblemStatus(bop::BopSolveStatus status) {
37  switch (status) {
39  return MPSolver::OPTIMAL;
41  return MPSolver::FEASIBLE;
43  return MPSolver::NOT_SOLVED;
45  return MPSolver::INFEASIBLE;
47  return MPSolver::ABNORMAL;
48  }
49  LOG(DFATAL) << "Invalid bop::BopSolveStatus";
50  return MPSolver::ABNORMAL;
51 }
52 
53 } // Anonymous namespace
54 
56  public:
57  explicit BopInterface(MPSolver* const solver);
58  ~BopInterface() override;
59 
60  // ----- Solve -----
61  MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
62 
63  // ----- Model modifications and extraction -----
64  void Reset() override;
65  void SetOptimizationDirection(bool maximize) override;
66  void SetVariableBounds(int index, double lb, double ub) override;
67  void SetVariableInteger(int index, bool integer) override;
68  void SetConstraintBounds(int index, double lb, double ub) override;
69  void AddRowConstraint(MPConstraint* const ct) override;
70  void AddVariable(MPVariable* const var) override;
71  void SetCoefficient(MPConstraint* const constraint,
72  const MPVariable* const variable, double new_value,
73  double old_value) override;
74  void ClearConstraint(MPConstraint* const constraint) override;
75  void SetObjectiveCoefficient(const MPVariable* const variable,
76  double coefficient) override;
77  void SetObjectiveOffset(double value) override;
78  void ClearObjective() override;
79 
80  // ------ Query statistics on the solution and the solve ------
81  int64_t iterations() const override;
82  int64_t nodes() const override;
83  MPSolver::BasisStatus row_status(int constraint_index) const override;
84  MPSolver::BasisStatus column_status(int variable_index) const override;
85 
86  // ----- Misc -----
87  bool IsContinuous() const override;
88  bool IsLP() const override;
89  bool IsMIP() const override;
90 
91  std::string SolverVersion() const override;
92  bool InterruptSolve() override;
93  void* underlying_solver() override;
94 
95  void ExtractNewVariables() override;
96  void ExtractNewConstraints() override;
97  void ExtractObjective() override;
98 
99  void SetParameters(const MPSolverParameters& param) override;
100  void SetRelativeMipGap(double value) override;
101  void SetPrimalTolerance(double value) override;
102  void SetDualTolerance(double value) override;
103  void SetPresolveMode(int value) override;
104  void SetScalingMode(int value) override;
105  void SetLpAlgorithm(int value) override;
107  const std::string& parameters) override;
108 
109  private:
110  void NonIncrementalChange();
111 
112  glop::LinearProgram linear_program_;
113  bop::IntegralSolver bop_solver_;
114  std::vector<MPSolver::BasisStatus> column_status_;
115  std::vector<MPSolver::BasisStatus> row_status_;
116  bop::BopParameters parameters_;
117  std::atomic<bool> interrupt_solver_;
118 };
119 
121  : MPSolverInterface(solver),
122  linear_program_(),
123  bop_solver_(),
124  column_status_(),
125  row_status_(),
126  parameters_(),
127  interrupt_solver_(false) {}
128 
130 
132  // Check whenever the solve has already been stopped by the user.
133  if (interrupt_solver_) {
134  Reset();
135  // linear_solver.cc as DCHECK_EQ that interface_->result_status_ is the same
136  // as the status returned by interface_->Solve().
138  return result_status_;
139  }
140 
141  // Reset extraction as this interface is not incremental yet.
142  Reset();
143  ExtractModel();
144  SetParameters(param);
145 
146  linear_program_.SetMaximizationProblem(maximize_);
147  linear_program_.CleanUp();
148 
149  // Time limit.
150  if (solver_->time_limit()) {
151  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
152  parameters_.set_max_time_in_seconds(
153  static_cast<double>(solver_->time_limit()) / 1000.0);
154  }
155  parameters_.set_log_search_progress(!quiet());
156 
157  glop::DenseRow initial_solution;
158  if (!solver_->solution_hint_.empty()) {
159  const int num_vars = solver_->variables_.size();
160  if (solver_->solution_hint_.size() != num_vars) {
161  LOG(WARNING) << "Bop currently doesn't handle partial solution hints. "
162  << "Filling the missing positions with zeros...";
163  }
164  initial_solution.assign(glop::ColIndex(num_vars), glop::Fractional(0.0));
165  for (const std::pair<const MPVariable*, double>& p :
166  solver_->solution_hint_) {
167  initial_solution[glop::ColIndex(p.first->index())] =
168  glop::Fractional(p.second);
169  }
170  }
171 
173  solver_->solver_specific_parameter_string_);
174  bop_solver_.SetParameters(parameters_);
175  std::unique_ptr<TimeLimit> time_limit =
176  TimeLimit::FromParameters(parameters_);
177  time_limit->RegisterExternalBooleanAsLimit(&interrupt_solver_);
179  initial_solution.empty()
180  ? bop_solver_.SolveWithTimeLimit(linear_program_, time_limit.get())
181  : bop_solver_.SolveWithTimeLimit(linear_program_, initial_solution,
182  time_limit.get());
183 
184  // The solution must be marked as synchronized even when no solution exists.
186  result_status_ = TranslateProblemStatus(status);
189  // Get the results.
190  objective_value_ = bop_solver_.objective_value();
191  best_objective_bound_ = bop_solver_.best_bound();
192 
193  // TODO(user): Implement the column status.
194  const size_t num_vars = solver_->variables_.size();
195  column_status_.resize(num_vars, MPSolver::FREE);
196  for (int var_id = 0; var_id < num_vars; ++var_id) {
197  MPVariable* const var = solver_->variables_[var_id];
198  const glop::ColIndex lp_solver_var_id(var->index());
199  const glop::Fractional solution_value =
200  bop_solver_.variable_values()[lp_solver_var_id];
201  var->set_solution_value(static_cast<double>(solution_value));
202  }
203 
204  // TODO(user): Implement the row status.
205  const size_t num_constraints = solver_->constraints_.size();
206  row_status_.resize(num_constraints, MPSolver::FREE);
207  }
208 
209  return result_status_;
210 }
211 
214  linear_program_.Clear();
215  interrupt_solver_ = false;
216 }
217 
219  NonIncrementalChange();
220 }
221 
222 void BopInterface::SetVariableBounds(int index, double lb, double ub) {
223  NonIncrementalChange();
224 }
225 
226 void BopInterface::SetVariableInteger(int index, bool integer) {
227  NonIncrementalChange();
228 }
229 
230 void BopInterface::SetConstraintBounds(int index, double lb, double ub) {
231  NonIncrementalChange();
232 }
233 
235  NonIncrementalChange();
236 }
237 
239  NonIncrementalChange();
240 }
241 
243  const MPVariable* const variable,
244  double new_value, double old_value) {
245  NonIncrementalChange();
246 }
247 
249  NonIncrementalChange();
250 }
251 
253  double coefficient) {
254  NonIncrementalChange();
255 }
256 
257 void BopInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
258 
259 void BopInterface::ClearObjective() { NonIncrementalChange(); }
260 
261 int64_t BopInterface::iterations() const {
262  LOG(DFATAL) << "Number of iterations not available";
264 }
265 
266 int64_t BopInterface::nodes() const {
267  LOG(DFATAL) << "Number of nodes not available";
268  return kUnknownNumberOfNodes;
269 }
270 
271 MPSolver::BasisStatus BopInterface::row_status(int constraint_index) const {
272  return row_status_[constraint_index];
273 }
274 
276  return column_status_[variable_index];
277 }
278 
279 bool BopInterface::IsContinuous() const { return false; }
280 bool BopInterface::IsLP() const { return false; }
281 bool BopInterface::IsMIP() const { return true; }
282 
283 std::string BopInterface::SolverVersion() const {
284  // TODO(user): Decide how to version bop.
285  return "Bop-0.0";
286 }
287 
289  interrupt_solver_ = true;
290  return true;
291 }
292 
293 void* BopInterface::underlying_solver() { return &bop_solver_; }
294 
295 // TODO(user): remove duplication with GlopInterface.
297  DCHECK_EQ(0, last_variable_index_);
298  DCHECK_EQ(0, last_constraint_index_);
299 
300  const glop::ColIndex num_cols(solver_->variables_.size());
301  for (glop::ColIndex col(last_variable_index_); col < num_cols; ++col) {
302  MPVariable* const var = solver_->variables_[col.value()];
303  const glop::ColIndex new_col = linear_program_.CreateNewVariable();
304  DCHECK_EQ(new_col, col);
305  set_variable_as_extracted(col.value(), true);
306  linear_program_.SetVariableBounds(col, var->lb(), var->ub());
307  if (var->integer()) {
308  linear_program_.SetVariableType(
310  }
311  }
312 }
313 
314 // TODO(user): remove duplication with GlopInterface.
316  DCHECK_EQ(0, last_constraint_index_);
317 
318  const glop::RowIndex num_rows(solver_->constraints_.size());
319  for (glop::RowIndex row(0); row < num_rows; ++row) {
320  MPConstraint* const ct = solver_->constraints_[row.value()];
321  set_constraint_as_extracted(row.value(), true);
322 
323  const double lb = ct->lb();
324  const double ub = ct->ub();
325  const glop::RowIndex new_row = linear_program_.CreateNewConstraint();
326  DCHECK_EQ(new_row, row);
327  linear_program_.SetConstraintBounds(row, lb, ub);
328 
329  for (const auto& entry : ct->coefficients_) {
330  const int var_index = entry.first->index();
331  DCHECK(variable_is_extracted(var_index));
332  const glop::ColIndex col(var_index);
333  const double coeff = entry.second;
334  linear_program_.SetCoefficient(row, col, coeff);
335  }
336  }
337 }
338 
339 // TODO(user): remove duplication with GlopInterface.
341  linear_program_.SetObjectiveOffset(solver_->Objective().offset());
342  for (const auto& entry : solver_->objective_->coefficients_) {
343  const int var_index = entry.first->index();
344  const glop::ColIndex col(var_index);
345  const double coeff = entry.second;
346  linear_program_.SetObjectiveCoefficient(col, coeff);
347  }
348 }
349 
351  parameters_.Clear();
352  SetCommonParameters(param);
353 }
354 
355 // All these have no effect.
361 
363  switch (value) {
365  // TODO(user): add this to BopParameters.
366  break;
368  // TODO(user): add this to BopParameters.
369  break;
370  default:
373  }
374  }
375 }
376 
378  const std::string& parameters) {
379  const bool ok =
380  google::protobuf::TextFormat::MergeFromString(parameters, &parameters_);
381  bop_solver_.SetParameters(parameters_);
382  return ok;
383 }
384 
385 void BopInterface::NonIncrementalChange() {
386  // The current implementation is not incremental.
388 }
389 
390 // Register BOP in the global linear solver factory.
392  return new BopInterface(solver);
393 }
394 
395 } // namespace operations_research
bool empty() const
void SetScalingMode(int value) override
void SetDualTolerance(double value) override
void AddRowConstraint(MPConstraint *const ct) override
void SetLpAlgorithm(int value) override
bool IsContinuous() const override
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
void SetPrimalTolerance(double value) override
void ClearConstraint(MPConstraint *const constraint) override
bool SetSolverSpecificParametersAsString(const std::string &parameters) override
void SetObjectiveCoefficient(const MPVariable *const variable, double coefficient) override
void SetCoefficient(MPConstraint *const constraint, const MPVariable *const variable, double new_value, double old_value) override
MPSolver::BasisStatus row_status(int constraint_index) const override
void SetObjectiveOffset(double value) override
void SetVariableInteger(int index, bool integer) override
void SetParameters(const MPSolverParameters &param) override
BopInterface(MPSolver *const solver)
std::string SolverVersion() const override
void SetRelativeMipGap(double value) override
void SetConstraintBounds(int index, double lb, double ub) override
void SetPresolveMode(int value) override
void SetVariableBounds(int index, double lb, double ub) override
void AddVariable(MPVariable *const var) override
int64_t nodes() const override
int64_t iterations() const override
void SetOptimizationDirection(bool maximize) override
MPSolver::BasisStatus column_status(int variable_index) const override
The class for constraints of a Mathematical Programming (MP) model.
double offset() const
Gets the constant term in the objective.
This mathematical programming (MP) solver class is the main class though which users build and solve ...
const MPObjective & Objective() const
Returns the objective object.
ResultStatus
The status of solving the problem.
@ FEASIBLE
feasible, or stopped by limit.
@ NOT_SOLVED
not been solved yet.
@ INFEASIBLE
proven infeasible.
@ ABNORMAL
abnormal, i.e., error of some kind.
bool SetSolverSpecificParametersAsString(const std::string &parameters)
Advanced usage: pass solver specific parameters in text format.
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
void set_constraint_as_extracted(int ct_index, bool extracted)
static constexpr int64_t kUnknownNumberOfNodes
bool variable_is_extracted(int var_index) const
static constexpr int64_t kUnknownNumberOfIterations
void set_variable_as_extracted(int var_index, bool extracted)
void SetCommonParameters(const MPSolverParameters &param)
This class stores parameter settings for LP and MIP solvers.
@ PRESOLVE
Advanced usage: presolve mode.
The class for variables of a Mathematical Programming (MP) model.
static std::unique_ptr< TimeLimit > FromParameters(const Parameters &parameters)
Creates a time limit object initialized from an object that provides methods max_time_in_seconds() an...
Definition: time_limit.h:159
ABSL_MUST_USE_RESULT BopSolveStatus SolveWithTimeLimit(const glop::LinearProgram &linear_problem, TimeLimit *time_limit)
const glop::DenseRow & variable_values() const
glop::Fractional objective_value() const
void SetParameters(const BopParameters &parameters)
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:250
void SetObjectiveOffset(Fractional objective_offset)
Definition: lp_data.cc:332
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Definition: lp_data.cc:318
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:310
void SetVariableType(ColIndex col, VariableType type)
Definition: lp_data.cc:237
void SetObjectiveCoefficient(ColIndex col, Fractional value)
Definition: lp_data.cc:327
void SetMaximizationProblem(bool maximize)
Definition: lp_data.cc:344
void assign(IntType size, const T &v)
Definition: lp_types.h:312
SatParameters parameters
ModelSharedTimeLimit * time_limit
const Constraint * ct
int64_t value
IntVar * var
Definition: expr_array.cc:1874
absl::Status status
Definition: g_gurobi.cc:41
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
int index
ColIndex col
Definition: markowitz.cc:186
RowIndex row
Definition: markowitz.cc:185
Collection of objects used to extend the Constraint Solver library.
MPSolverInterface * BuildBopInterface(MPSolver *const solver)
int64_t coefficient
#define VLOG(verboselevel)
Definition: vlog.h:39