OR-Tools  9.3
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"
26#include "ortools/bop/bop_parameters.pb.h"
29
30namespace operations_research {
31namespace {
32
34 switch (status) {
36 return MPSolver::OPTIMAL;
38 return MPSolver::FEASIBLE;
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_);
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
219void BopInterface::SetVariableBounds(int index, double lb, double ub) {
220 NonIncrementalChange();
221}
222
224 NonIncrementalChange();
225}
226
227void 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
254void BopInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
255
256void BopInterface::ClearObjective() { NonIncrementalChange(); }
257
259 LOG(DFATAL) << "Number of iterations not available";
261}
262
263int64_t BopInterface::nodes() const {
264 LOG(DFATAL) << "Number of nodes not available";
266}
267
269 return row_status_[constraint_index];
270}
271
273 return column_status_[variable_index];
274}
275
276bool BopInterface::IsContinuous() const { return false; }
277bool BopInterface::IsLP() const { return false; }
278bool BopInterface::IsMIP() const { return true; }
279
280std::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
290void* 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
382void 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
#define LOG(severity)
Definition: base/logging.h:420
#define DCHECK(condition)
Definition: base/logging.h:890
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:891
#define VLOG(verboselevel)
Definition: base/logging.h:984
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:160
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
absl::Status status
Definition: g_gurobi.cc:35
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
int index
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)
int64_t coefficient
const double coeff