OR-Tools  9.2
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 "absl/base/attributes.h"
20 #include "google/protobuf/text_format.h"
22 #include "ortools/base/file.h"
23 #include "ortools/base/hash.h"
25 #include "ortools/base/logging.h"
29 
30 namespace operations_research {
31 namespace {
32 
33 MPSolver::ResultStatus TranslateProblemStatus(bop::BopSolveStatus status) {
34  switch (status) {
36  return MPSolver::OPTIMAL;
38  return MPSolver::FEASIBLE;
40  return MPSolver::NOT_SOLVED;
42  return MPSolver::INFEASIBLE;
44  return MPSolver::ABNORMAL;
45  }
46  LOG(DFATAL) << "Invalid bop::BopSolveStatus";
47  return MPSolver::ABNORMAL;
48 }
49 
50 } // Anonymous namespace
51 
53  public:
54  explicit BopInterface(MPSolver* const solver);
55  ~BopInterface() override;
56 
57  // ----- Solve -----
58  MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
59 
60  // ----- Model modifications and extraction -----
61  void Reset() override;
62  void SetOptimizationDirection(bool maximize) override;
63  void SetVariableBounds(int index, double lb, double ub) override;
64  void SetVariableInteger(int index, bool integer) override;
65  void SetConstraintBounds(int index, double lb, double ub) override;
66  void AddRowConstraint(MPConstraint* const ct) override;
67  void AddVariable(MPVariable* const var) override;
68  void SetCoefficient(MPConstraint* const constraint,
69  const MPVariable* const variable, double new_value,
70  double old_value) override;
71  void ClearConstraint(MPConstraint* const constraint) override;
72  void SetObjectiveCoefficient(const MPVariable* const variable,
73  double coefficient) override;
74  void SetObjectiveOffset(double value) override;
75  void ClearObjective() override;
76 
77  // ------ Query statistics on the solution and the solve ------
78  int64_t iterations() const override;
79  int64_t nodes() const override;
80  MPSolver::BasisStatus row_status(int constraint_index) const override;
81  MPSolver::BasisStatus column_status(int variable_index) const override;
82 
83  // ----- Misc -----
84  bool IsContinuous() const override;
85  bool IsLP() const override;
86  bool IsMIP() const override;
87 
88  std::string SolverVersion() const override;
89  bool InterruptSolve() override;
90  void* underlying_solver() override;
91 
92  void ExtractNewVariables() override;
93  void ExtractNewConstraints() override;
94  void ExtractObjective() override;
95 
96  void SetParameters(const MPSolverParameters& param) override;
97  void SetRelativeMipGap(double value) override;
98  void SetPrimalTolerance(double value) override;
99  void SetDualTolerance(double value) override;
100  void SetPresolveMode(int value) override;
101  void SetScalingMode(int value) override;
102  void SetLpAlgorithm(int value) override;
104  const std::string& parameters) override;
105 
106  private:
107  void NonIncrementalChange();
108 
109  glop::LinearProgram linear_program_;
110  bop::IntegralSolver bop_solver_;
111  std::vector<MPSolver::BasisStatus> column_status_;
112  std::vector<MPSolver::BasisStatus> row_status_;
113  bop::BopParameters parameters_;
114  std::atomic<bool> interrupt_solver_;
115 };
116 
118  : MPSolverInterface(solver),
119  linear_program_(),
120  bop_solver_(),
121  column_status_(),
122  row_status_(),
123  parameters_(),
124  interrupt_solver_(false) {}
125 
127 
129  // Check whenever the solve has already been stopped by the user.
130  if (interrupt_solver_) {
131  Reset();
132  // linear_solver.cc as DCHECK_EQ that interface_->result_status_ is the same
133  // as the status returned by interface_->Solve().
135  return result_status_;
136  }
137 
138  // Reset extraction as this interface is not incremental yet.
139  Reset();
140  ExtractModel();
141  SetParameters(param);
142 
143  linear_program_.SetMaximizationProblem(maximize_);
144  linear_program_.CleanUp();
145 
146  // Time limit.
147  if (solver_->time_limit()) {
148  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
149  parameters_.set_max_time_in_seconds(
150  static_cast<double>(solver_->time_limit()) / 1000.0);
151  }
152  parameters_.set_log_search_progress(!quiet());
153 
154  glop::DenseRow initial_solution;
155  if (!solver_->solution_hint_.empty()) {
156  const int num_vars = solver_->variables_.size();
157  if (solver_->solution_hint_.size() != num_vars) {
158  LOG(WARNING) << "Bop currently doesn't handle partial solution hints. "
159  << "Filling the missing positions with zeros...";
160  }
161  initial_solution.assign(glop::ColIndex(num_vars), glop::Fractional(0.0));
162  for (const std::pair<const MPVariable*, double>& p :
163  solver_->solution_hint_) {
164  initial_solution[glop::ColIndex(p.first->index())] =
165  glop::Fractional(p.second);
166  }
167  }
168 
170  solver_->solver_specific_parameter_string_);
171  bop_solver_.SetParameters(parameters_);
172  std::unique_ptr<TimeLimit> time_limit =
173  TimeLimit::FromParameters(parameters_);
174  time_limit->RegisterExternalBooleanAsLimit(&interrupt_solver_);
175  const bop::BopSolveStatus status =
176  initial_solution.empty()
177  ? bop_solver_.SolveWithTimeLimit(linear_program_, time_limit.get())
178  : bop_solver_.SolveWithTimeLimit(linear_program_, initial_solution,
179  time_limit.get());
180 
181  // The solution must be marked as synchronized even when no solution exists.
183  result_status_ = TranslateProblemStatus(status);
186  // Get the results.
187  objective_value_ = bop_solver_.objective_value();
188  best_objective_bound_ = bop_solver_.best_bound();
189 
190  // TODO(user): Implement the column status.
191  const size_t num_vars = solver_->variables_.size();
192  column_status_.resize(num_vars, MPSolver::FREE);
193  for (int var_id = 0; var_id < num_vars; ++var_id) {
194  MPVariable* const var = solver_->variables_[var_id];
195  const glop::ColIndex lp_solver_var_id(var->index());
196  const glop::Fractional solution_value =
197  bop_solver_.variable_values()[lp_solver_var_id];
198  var->set_solution_value(static_cast<double>(solution_value));
199  }
200 
201  // TODO(user): Implement the row status.
202  const size_t num_constraints = solver_->constraints_.size();
203  row_status_.resize(num_constraints, MPSolver::FREE);
204  }
205 
206  return result_status_;
207 }
208 
211  linear_program_.Clear();
212  interrupt_solver_ = false;
213 }
214 
216  NonIncrementalChange();
217 }
218 
219 void BopInterface::SetVariableBounds(int index, double lb, double ub) {
220  NonIncrementalChange();
221 }
222 
223 void BopInterface::SetVariableInteger(int index, bool integer) {
224  NonIncrementalChange();
225 }
226 
227 void BopInterface::SetConstraintBounds(int index, double lb, double ub) {
228  NonIncrementalChange();
229 }
230 
232  NonIncrementalChange();
233 }
234 
236  NonIncrementalChange();
237 }
238 
240  const MPVariable* const variable,
241  double new_value, double old_value) {
242  NonIncrementalChange();
243 }
244 
246  NonIncrementalChange();
247 }
248 
250  double coefficient) {
251  NonIncrementalChange();
252 }
253 
254 void BopInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
255 
256 void BopInterface::ClearObjective() { NonIncrementalChange(); }
257 
258 int64_t BopInterface::iterations() const {
259  LOG(DFATAL) << "Number of iterations not available";
261 }
262 
263 int64_t BopInterface::nodes() const {
264  LOG(DFATAL) << "Number of nodes not available";
265  return kUnknownNumberOfNodes;
266 }
267 
268 MPSolver::BasisStatus BopInterface::row_status(int constraint_index) const {
269  return row_status_[constraint_index];
270 }
271 
273  return column_status_[variable_index];
274 }
275 
276 bool BopInterface::IsContinuous() const { return false; }
277 bool BopInterface::IsLP() const { return false; }
278 bool BopInterface::IsMIP() const { return true; }
279 
280 std::string BopInterface::SolverVersion() const {
281  // TODO(user): Decide how to version bop.
282  return "Bop-0.0";
283 }
284 
286  interrupt_solver_ = true;
287  return true;
288 }
289 
290 void* BopInterface::underlying_solver() { return &bop_solver_; }
291 
292 // TODO(user): remove duplication with GlopInterface.
296 
297  const glop::ColIndex num_cols(solver_->variables_.size());
298  for (glop::ColIndex col(last_variable_index_); col < num_cols; ++col) {
299  MPVariable* const var = solver_->variables_[col.value()];
300  const glop::ColIndex new_col = linear_program_.CreateNewVariable();
301  DCHECK_EQ(new_col, col);
302  set_variable_as_extracted(col.value(), true);
303  linear_program_.SetVariableBounds(col, var->lb(), var->ub());
304  if (var->integer()) {
305  linear_program_.SetVariableType(
307  }
308  }
309 }
310 
311 // TODO(user): remove duplication with GlopInterface.
314 
315  const glop::RowIndex num_rows(solver_->constraints_.size());
316  for (glop::RowIndex row(0); row < num_rows; ++row) {
317  MPConstraint* const ct = solver_->constraints_[row.value()];
318  set_constraint_as_extracted(row.value(), true);
319 
320  const double lb = ct->lb();
321  const double ub = ct->ub();
322  const glop::RowIndex new_row = linear_program_.CreateNewConstraint();
323  DCHECK_EQ(new_row, row);
324  linear_program_.SetConstraintBounds(row, lb, ub);
325 
326  for (const auto& entry : ct->coefficients_) {
327  const int var_index = entry.first->index();
328  DCHECK(variable_is_extracted(var_index));
329  const glop::ColIndex col(var_index);
330  const double coeff = entry.second;
331  linear_program_.SetCoefficient(row, col, coeff);
332  }
333  }
334 }
335 
336 // TODO(user): remove duplication with GlopInterface.
338  linear_program_.SetObjectiveOffset(solver_->Objective().offset());
339  for (const auto& entry : solver_->objective_->coefficients_) {
340  const int var_index = entry.first->index();
341  const glop::ColIndex col(var_index);
342  const double coeff = entry.second;
343  linear_program_.SetObjectiveCoefficient(col, coeff);
344  }
345 }
346 
348  parameters_.Clear();
349  SetCommonParameters(param);
350 }
351 
352 // All these have no effect.
358 
360  switch (value) {
362  // TODO(user): add this to BopParameters.
363  break;
365  // TODO(user): add this to BopParameters.
366  break;
367  default:
370  }
371  }
372 }
373 
375  const std::string& parameters) {
376  const bool ok =
377  google::protobuf::TextFormat::MergeFromString(parameters, &parameters_);
378  bop_solver_.SetParameters(parameters_);
379  return ok;
380 }
381 
382 void BopInterface::NonIncrementalChange() {
383  // The current implementation is not incremental.
385 }
386 
387 // Register BOP in the global linear solver factory.
389  return new BopInterface(solver);
390 }
391 
392 } // namespace operations_research
void AddVariable(MPVariable *const var) override
ResultStatus
The status of solving the problem.
void SetDualTolerance(double value) override
void set_variable_as_extracted(int var_index, bool extracted)
ABSL_MUST_USE_RESULT BopSolveStatus SolveWithTimeLimit(const glop::LinearProgram &linear_problem, TimeLimit *time_limit)
void SetObjectiveCoefficient(ColIndex col, Fractional value)
Definition: lp_data.cc:326
void SetRelativeMipGap(double value) override
ModelSharedTimeLimit * time_limit
void set_constraint_as_extracted(int ct_index, bool extracted)
std::string SolverVersion() const override
MPSolver::BasisStatus row_status(int constraint_index) const override
#define VLOG(verboselevel)
Definition: base/logging.h:983
const MPObjective & Objective() const
Returns the objective object.
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final
void SetVariableType(ColIndex col, VariableType type)
Definition: lp_data.cc:236
void SetObjectiveCoefficient(const MPVariable *const variable, double coefficient) override
#define LOG(severity)
Definition: base/logging.h:420
ColIndex col
Definition: markowitz.cc:183
void SetConstraintBounds(int index, double lb, double ub) override
void SetParameters(const MPSolverParameters &param) override
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:309
void SetObjectiveOffset(Fractional objective_offset)
Definition: lp_data.cc:331
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
RowIndex row
Definition: markowitz.cc:182
int64_t coefficient
void assign(IntType size, const T &v)
Definition: lp_types.h:278
int64_t nodes() const override
void SetLpAlgorithm(int value) override
The class for variables of a Mathematical Programming (MP) model.
MPSolverInterface * BuildBopInterface(MPSolver *const solver)
void SetOptimizationDirection(bool maximize) override
void ClearConstraint(MPConstraint *const constraint) override
bool SetSolverSpecificParametersAsString(const std::string &parameters)
Advanced usage: pass solver specific parameters in text format.
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:160
const int WARNING
Definition: log_severity.h:31
bool empty() const
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
int64_t iterations() const override
void SetObjectiveOffset(double value) override
void SetCommonParameters(const MPSolverParameters &param)
static constexpr int64_t kUnknownNumberOfIterations
bool IsContinuous() const override
glop::Fractional objective_value() const
int index
Definition: pack.cc:509
void SetPresolveMode(int value) override
The class for constraints of a Mathematical Programming (MP) model.
feasible, or stopped by limit.
void SetCoefficient(MPConstraint *const constraint, const MPVariable *const variable, double new_value, double old_value) override
#define DCHECK(condition)
Definition: base/logging.h:889
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
static constexpr int64_t kUnknownNumberOfNodes
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:890
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:249
void AddRowConstraint(MPConstraint *const ct) override
void SetVariableBounds(int index, double lb, double ub) override
void SetMaximizationProblem(bool maximize)
Definition: lp_data.cc:343
This mathematical programming (MP) solver class is the main class though which users build and solve ...
Collection of objects used to extend the Constraint Solver library.
void SetParameters(const BopParameters &parameters)
BopInterface(MPSolver *const solver)
abnormal, i.e., error of some kind.
SatParameters parameters
This class stores parameter settings for LP and MIP solvers.
IntVar * var
Definition: expr_array.cc:1874
void SetPrimalTolerance(double value) override
bool SetSolverSpecificParametersAsString(const std::string &parameters) override
void SetVariableInteger(int index, bool integer) override
const glop::DenseRow & variable_values() const
void SetScalingMode(int value) override
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Definition: lp_data.cc:317
double offset() const
Gets the constant term in the objective.
int64_t value
MPSolver::BasisStatus column_status(int variable_index) const override
const Constraint * ct
bool variable_is_extracted(int var_index) const