OR-Tools  9.0
bop_interface.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 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 <string>
17 #include <vector>
18 
19 #include "google/protobuf/text_format.h"
21 #include "ortools/base/file.h"
22 #include "ortools/base/hash.h"
24 #include "ortools/base/logging.h"
28 
29 namespace operations_research {
30 namespace {
31 
32 MPSolver::ResultStatus TranslateProblemStatus(bop::BopSolveStatus status) {
33  switch (status) {
35  return MPSolver::OPTIMAL;
37  return MPSolver::FEASIBLE;
39  return MPSolver::NOT_SOLVED;
41  return MPSolver::INFEASIBLE;
43  return MPSolver::ABNORMAL;
44  }
45  LOG(DFATAL) << "Invalid bop::BopSolveStatus";
46  return MPSolver::ABNORMAL;
47 }
48 
49 } // Anonymous namespace
50 
52  public:
53  explicit BopInterface(MPSolver* const solver);
54  ~BopInterface() override;
55 
56  // ----- Solve -----
57  MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
58 
59  // ----- Model modifications and extraction -----
60  void Reset() override;
61  void SetOptimizationDirection(bool maximize) override;
62  void SetVariableBounds(int index, double lb, double ub) override;
63  void SetVariableInteger(int index, bool integer) override;
64  void SetConstraintBounds(int index, double lb, double ub) override;
65  void AddRowConstraint(MPConstraint* const ct) override;
66  void AddVariable(MPVariable* const var) override;
67  void SetCoefficient(MPConstraint* const constraint,
68  const MPVariable* const variable, double new_value,
69  double old_value) override;
70  void ClearConstraint(MPConstraint* const constraint) override;
71  void SetObjectiveCoefficient(const MPVariable* const variable,
72  double coefficient) override;
73  void SetObjectiveOffset(double value) override;
74  void ClearObjective() override;
75 
76  // ------ Query statistics on the solution and the solve ------
77  int64_t iterations() const override;
78  int64_t nodes() const override;
79  MPSolver::BasisStatus row_status(int constraint_index) const override;
80  MPSolver::BasisStatus column_status(int variable_index) const override;
81 
82  // ----- Misc -----
83  bool IsContinuous() const override;
84  bool IsLP() const override;
85  bool IsMIP() const override;
86 
87  std::string SolverVersion() const override;
88  bool InterruptSolve() override;
89  void* underlying_solver() override;
90 
91  void ExtractNewVariables() override;
92  void ExtractNewConstraints() override;
93  void ExtractObjective() override;
94 
95  void SetParameters(const MPSolverParameters& param) override;
96  void SetRelativeMipGap(double value) override;
97  void SetPrimalTolerance(double value) override;
98  void SetDualTolerance(double value) override;
99  void SetPresolveMode(int value) override;
100  void SetScalingMode(int value) override;
101  void SetLpAlgorithm(int value) override;
103  const std::string& parameters) override;
104 
105  private:
106  void NonIncrementalChange();
107 
108  glop::LinearProgram linear_program_;
109  bop::IntegralSolver bop_solver_;
110  std::vector<MPSolver::BasisStatus> column_status_;
111  std::vector<MPSolver::BasisStatus> row_status_;
112  bop::BopParameters parameters_;
113  std::atomic<bool> interrupt_solver_;
114 };
115 
117  : MPSolverInterface(solver),
118  linear_program_(),
119  bop_solver_(),
120  column_status_(),
121  row_status_(),
122  parameters_(),
123  interrupt_solver_(false) {}
124 
126 
128  // Check whenever the solve has already been stopped by the user.
129  if (interrupt_solver_) {
130  Reset();
131  // linear_solver.cc as DCHECK_EQ that interface_->result_status_ is the same
132  // as the status returned by interface_->Solve().
134  return result_status_;
135  }
136 
137  // Reset extraction as this interface is not incremental yet.
138  Reset();
139  ExtractModel();
140  SetParameters(param);
141 
142  linear_program_.SetMaximizationProblem(maximize_);
143  linear_program_.CleanUp();
144 
145  // Time limit.
146  if (solver_->time_limit()) {
147  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
148  parameters_.set_max_time_in_seconds(
149  static_cast<double>(solver_->time_limit()) / 1000.0);
150  }
151  parameters_.set_log_search_progress(!quiet());
152 
153  glop::DenseRow initial_solution;
154  if (!solver_->solution_hint_.empty()) {
155  const int num_vars = solver_->variables_.size();
156  if (solver_->solution_hint_.size() != num_vars) {
157  LOG(WARNING) << "Bop currently doesn't handle partial solution hints. "
158  << "Filling the missing positions with zeros...";
159  }
160  initial_solution.assign(glop::ColIndex(num_vars), glop::Fractional(0.0));
161  for (const std::pair<const MPVariable*, double>& p :
162  solver_->solution_hint_) {
163  initial_solution[glop::ColIndex(p.first->index())] =
164  glop::Fractional(p.second);
165  }
166  }
167 
169  solver_->solver_specific_parameter_string_);
170  bop_solver_.SetParameters(parameters_);
171  std::unique_ptr<TimeLimit> time_limit =
172  TimeLimit::FromParameters(parameters_);
173  time_limit->RegisterExternalBooleanAsLimit(&interrupt_solver_);
174  const bop::BopSolveStatus status =
175  initial_solution.empty()
176  ? bop_solver_.SolveWithTimeLimit(linear_program_, time_limit.get())
177  : bop_solver_.SolveWithTimeLimit(linear_program_, initial_solution,
178  time_limit.get());
179 
180  // The solution must be marked as synchronized even when no solution exists.
182  result_status_ = TranslateProblemStatus(status);
185  // Get the results.
186  objective_value_ = bop_solver_.objective_value();
187  best_objective_bound_ = bop_solver_.best_bound();
188 
189  // TODO(user): Implement the column status.
190  const size_t num_vars = solver_->variables_.size();
191  column_status_.resize(num_vars, MPSolver::FREE);
192  for (int var_id = 0; var_id < num_vars; ++var_id) {
193  MPVariable* const var = solver_->variables_[var_id];
194  const glop::ColIndex lp_solver_var_id(var->index());
195  const glop::Fractional solution_value =
196  bop_solver_.variable_values()[lp_solver_var_id];
197  var->set_solution_value(static_cast<double>(solution_value));
198  }
199 
200  // TODO(user): Implement the row status.
201  const size_t num_constraints = solver_->constraints_.size();
202  row_status_.resize(num_constraints, MPSolver::FREE);
203  }
204 
205  return result_status_;
206 }
207 
210  linear_program_.Clear();
211  interrupt_solver_ = false;
212 }
213 
215  NonIncrementalChange();
216 }
217 
218 void BopInterface::SetVariableBounds(int index, double lb, double ub) {
219  NonIncrementalChange();
220 }
221 
222 void BopInterface::SetVariableInteger(int index, bool integer) {
223  NonIncrementalChange();
224 }
225 
226 void BopInterface::SetConstraintBounds(int index, double lb, double ub) {
227  NonIncrementalChange();
228 }
229 
231  NonIncrementalChange();
232 }
233 
235  NonIncrementalChange();
236 }
237 
239  const MPVariable* const variable,
240  double new_value, double old_value) {
241  NonIncrementalChange();
242 }
243 
245  NonIncrementalChange();
246 }
247 
249  double coefficient) {
250  NonIncrementalChange();
251 }
252 
253 void BopInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
254 
255 void BopInterface::ClearObjective() { NonIncrementalChange(); }
256 
257 int64_t BopInterface::iterations() const {
258  LOG(DFATAL) << "Number of iterations not available";
260 }
261 
262 int64_t BopInterface::nodes() const {
263  LOG(DFATAL) << "Number of nodes not available";
264  return kUnknownNumberOfNodes;
265 }
266 
267 MPSolver::BasisStatus BopInterface::row_status(int constraint_index) const {
268  return row_status_[constraint_index];
269 }
270 
272  return column_status_[variable_index];
273 }
274 
275 bool BopInterface::IsContinuous() const { return false; }
276 bool BopInterface::IsLP() const { return false; }
277 bool BopInterface::IsMIP() const { return true; }
278 
279 std::string BopInterface::SolverVersion() const {
280  // TODO(user): Decide how to version bop.
281  return "Bop-0.0";
282 }
283 
285  interrupt_solver_ = true;
286  return true;
287 }
288 
289 void* BopInterface::underlying_solver() { return &bop_solver_; }
290 
291 // TODO(user): remove duplication with GlopInterface.
295 
296  const glop::ColIndex num_cols(solver_->variables_.size());
297  for (glop::ColIndex col(last_variable_index_); col < num_cols; ++col) {
298  MPVariable* const var = solver_->variables_[col.value()];
299  const glop::ColIndex new_col = linear_program_.CreateNewVariable();
300  DCHECK_EQ(new_col, col);
301  set_variable_as_extracted(col.value(), true);
302  linear_program_.SetVariableBounds(col, var->lb(), var->ub());
303  if (var->integer()) {
304  linear_program_.SetVariableType(
306  }
307  }
308 }
309 
310 // TODO(user): remove duplication with GlopInterface.
313 
314  const glop::RowIndex num_rows(solver_->constraints_.size());
315  for (glop::RowIndex row(0); row < num_rows; ++row) {
316  MPConstraint* const ct = solver_->constraints_[row.value()];
317  set_constraint_as_extracted(row.value(), true);
318 
319  const double lb = ct->lb();
320  const double ub = ct->ub();
321  const glop::RowIndex new_row = linear_program_.CreateNewConstraint();
322  DCHECK_EQ(new_row, row);
323  linear_program_.SetConstraintBounds(row, lb, ub);
324 
325  for (const auto& entry : ct->coefficients_) {
326  const int var_index = entry.first->index();
327  DCHECK(variable_is_extracted(var_index));
328  const glop::ColIndex col(var_index);
329  const double coeff = entry.second;
330  linear_program_.SetCoefficient(row, col, coeff);
331  }
332  }
333 }
334 
335 // TODO(user): remove duplication with GlopInterface.
337  linear_program_.SetObjectiveOffset(solver_->Objective().offset());
338  for (const auto& entry : solver_->objective_->coefficients_) {
339  const int var_index = entry.first->index();
340  const glop::ColIndex col(var_index);
341  const double coeff = entry.second;
342  linear_program_.SetObjectiveCoefficient(col, coeff);
343  }
344 }
345 
347  parameters_.Clear();
348  SetCommonParameters(param);
349 }
350 
351 // All these have no effect.
357 
359  switch (value) {
361  // TODO(user): add this to BopParameters.
362  break;
364  // TODO(user): add this to BopParameters.
365  break;
366  default:
369  }
370  }
371 }
372 
374  const std::string& parameters) {
375  const bool ok =
376  google::protobuf::TextFormat::MergeFromString(parameters, &parameters_);
377  bop_solver_.SetParameters(parameters_);
378  return ok;
379 }
380 
381 void BopInterface::NonIncrementalChange() {
382  // The current implementation is not incremental.
384 }
385 
386 // Register BOP in the global linear solver factory.
388  return new BopInterface(solver);
389 }
390 
391 } // namespace operations_research
#define LOG(severity)
Definition: base/logging.h:423
#define DCHECK(condition)
Definition: base/logging.h:892
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:893
#define VLOG(verboselevel)
Definition: base/logging.h:986
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:249
void SetObjectiveOffset(Fractional objective_offset)
Definition: lp_data.cc:331
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Definition: lp_data.cc:317
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:309
void SetVariableType(ColIndex col, VariableType type)
Definition: lp_data.cc:236
void SetObjectiveCoefficient(ColIndex col, Fractional value)
Definition: lp_data.cc:326
void SetMaximizationProblem(bool maximize)
Definition: lp_data.cc:343
void assign(IntType size, const T &v)
Definition: lp_types.h:275
SatParameters parameters
SharedTimeLimit * time_limit
const Constraint * ct
int64_t value
IntVar * var
Definition: expr_array.cc:1874
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
const int WARNING
Definition: log_severity.h:31
ColIndex col
Definition: markowitz.cc:183
RowIndex row
Definition: markowitz.cc:182
Collection of objects used to extend the Constraint Solver library.
MPSolverInterface * BuildBopInterface(MPSolver *const solver)
int index
Definition: pack.cc:509
int64_t coefficient