OR-Tools  9.1
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"
28
29namespace operations_research {
30namespace {
31
32MPSolver::ResultStatus TranslateProblemStatus(bop::BopSolveStatus status) {
33 switch (status) {
35 return MPSolver::OPTIMAL;
37 return MPSolver::FEASIBLE;
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
218void BopInterface::SetVariableBounds(int index, double lb, double ub) {
219 NonIncrementalChange();
220}
221
223 NonIncrementalChange();
224}
225
226void 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
253void BopInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
254
255void BopInterface::ClearObjective() { NonIncrementalChange(); }
256
258 LOG(DFATAL) << "Number of iterations not available";
260}
261
262int64_t BopInterface::nodes() const {
263 LOG(DFATAL) << "Number of nodes not available";
265}
266
268 return row_status_[constraint_index];
269}
270
272 return column_status_[variable_index];
273}
274
275bool BopInterface::IsContinuous() const { return false; }
276bool BopInterface::IsLP() const { return false; }
277bool BopInterface::IsMIP() const { return true; }
278
279std::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
289void* 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
381void 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:416
#define DCHECK(condition)
Definition: base/logging.h:885
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:886
#define VLOG(verboselevel)
Definition: base/logging.h:979
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 ...
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.
const MPObjective & Objective() const
Returns the objective object.
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
PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final
ABSL_MUST_USE_RESULT BopSolveStatus SolveWithTimeLimit(const glop::LinearProgram &linear_problem, TimeLimit *time_limit)
glop::Fractional objective_value() const
const glop::DenseRow & variable_values() 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:278
SatParameters parameters
ModelSharedTimeLimit * 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