Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
bop_interface.cc
Go to the documentation of this file.
1// Copyright 2010-2024 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#if defined(USE_BOP)
15
16#include <atomic>
17#include <cstdint>
18#include <memory>
19#include <string>
20#include <utility>
21#include <vector>
22
23#include "absl/base/attributes.h"
24#include "google/protobuf/text_format.h"
26#include "ortools/base/file.h"
27#include "ortools/base/hash.h"
30#include "ortools/bop/bop_parameters.pb.h"
33
34namespace operations_research {
35namespace {
36
38 switch (status) {
40 return MPSolver::OPTIMAL;
42 return MPSolver::FEASIBLE;
48 return MPSolver::ABNORMAL;
49 }
50 LOG(DFATAL) << "Invalid bop::BopSolveStatus";
51 return MPSolver::ABNORMAL;
52}
53
54} // Anonymous namespace
55
57 public:
58 explicit BopInterface(MPSolver* solver);
59 ~BopInterface() override;
60
61 // ----- Solve -----
62 MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
63
64 // ----- Model modifications and extraction -----
65 void Reset() override;
66 void SetOptimizationDirection(bool maximize) override;
67 void SetVariableBounds(int index, double lb, double ub) override;
68 void SetVariableInteger(int index, bool integer) override;
69 void SetConstraintBounds(int index, double lb, double ub) override;
70 void AddRowConstraint(MPConstraint* ct) override;
71 void AddVariable(MPVariable* var) override;
72 void SetCoefficient(MPConstraint* constraint, const MPVariable* variable,
73 double new_value, double old_value) override;
74 void ClearConstraint(MPConstraint* constraint) override;
75 void SetObjectiveCoefficient(const MPVariable* 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;
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
222void BopInterface::SetVariableBounds(int index, double lb, double ub) {
223 NonIncrementalChange();
224}
225
227 NonIncrementalChange();
228}
229
230void 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
257void BopInterface::SetObjectiveOffset(double value) { NonIncrementalChange(); }
258
259void BopInterface::ClearObjective() { NonIncrementalChange(); }
260
262 LOG(DFATAL) << "Number of iterations not available";
264}
265
266int64_t BopInterface::nodes() const {
267 LOG(DFATAL) << "Number of nodes not available";
269}
270
274
276 return column_status_[variable_index];
277}
278
279bool BopInterface::IsContinuous() const { return false; }
280bool BopInterface::IsLP() const { return false; }
281bool BopInterface::IsMIP() const { return true; }
282
283std::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
293void* 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();
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
385void 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
396#endif // #if defined(USE_BOP)
bool IsMIP() const override
Returns true if the problem is discrete and linear.
void SetParameters(const MPSolverParameters &param) override
Sets all parameters in the underlying solver.
void SetRelativeMipGap(double value) override
Sets each parameter in the underlying solver.
void SetScalingMode(int value) override
Sets the scaling mode.
bool IsLP() const override
Returns true if the problem is continuous and linear.
MPSolver::BasisStatus row_status(int constraint_index) const override
Returns the basis status of a row.
void AddVariable(MPVariable *var) override
Add a variable.
void Reset() override
--— Model modifications and extraction --—
void * underlying_solver() override
Returns the underlying solver.
int64_t nodes() const override
void SetVariableInteger(int index, bool integer) override
Modifies integrality of an extracted variable.
void SetObjectiveCoefficient(const MPVariable *variable, double coefficient) override
Changes a coefficient in the linear objective.
std::string SolverVersion() const override
Returns a string describing the underlying solver and its version.
void ClearObjective() override
Clears the objective from all its terms.
int64_t iterations() const override
---— Query statistics on the solution and the solve ---—
void SetLpAlgorithm(int value) override
void SetCoefficient(MPConstraint *constraint, const MPVariable *variable, double new_value, double old_value) override
Changes a coefficient in a constraint.
void SetVariableBounds(int index, double lb, double ub) override
Modifies bounds of an extracted variable.
bool SetSolverSpecificParametersAsString(const std::string &parameters) override
void SetOptimizationDirection(bool maximize) override
Sets the optimization direction (min/max).
void SetConstraintBounds(int index, double lb, double ub) override
Modify bounds of an extracted variable.
void SetDualTolerance(double value) override
bool IsContinuous() const override
--— Misc --—
void SetPresolveMode(int value) override
void ClearConstraint(MPConstraint *constraint) override
Clears a constraint from all its terms.
MPSolver::BasisStatus column_status(int variable_index) const override
Returns the basis status of a constraint.
void SetObjectiveOffset(double value) override
Changes the constant term in the linear objective.
void AddRowConstraint(MPConstraint *ct) override
Adds a linear constraint.
void SetPrimalTolerance(double value) override
All these have no effect.
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
--— Solve --—
double offset() const
Gets the constant term in the objective.
void set_variable_as_extracted(int var_index, bool extracted)
static constexpr int64_t kUnknownNumberOfIterations
void set_constraint_as_extracted(int ct_index, bool extracted)
void ResetExtractionInformation()
Resets the extraction information.
int last_variable_index_
Index in MPSolver::constraints_ of last variable extracted.
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
Sets a supported integer parameter to an unsupported value.
int last_constraint_index_
Index in MPSolver::variables_ of last constraint extracted.
bool variable_is_extracted(int var_index) const
bool quiet() const
Returns the boolean indicating the verbosity of the solver output.
static constexpr int64_t kUnknownNumberOfNodes
void ExtractModel()
Extracts model stored in MPSolver.
double objective_value_
The value of the objective function.
double best_objective_bound_
The value of the best objective bound. Used only for MIP solvers.
bool maximize_
Optimization direction.
void SetCommonParameters(const MPSolverParameters &param)
Sets parameters common to LP and MIP in the underlying solver.
SynchronizationStatus sync_status_
Indicates whether the model and the solution are synchronized.
@ PRESOLVE
Advanced usage: presolve mode.
@ FEASIBLE
feasible, or stopped by limit.
@ NOT_SOLVED
not been solved yet.
@ INFEASIBLE
proven infeasible.
@ ABNORMAL
abnormal, i.e., error of some kind.
const MPObjective & Objective() const
bool SetSolverSpecificParametersAsString(const std::string &parameters)
The class for variables of a Mathematical Programming (MP) model.
static std::unique_ptr< TimeLimit > FromParameters(const Parameters &parameters)
Definition time_limit.h:140
const glop::DenseRow & variable_values() const
glop::Fractional best_bound() const
Returns the best bound found so far.
ABSL_MUST_USE_RESULT BopSolveStatus SolveWithTimeLimit(const glop::LinearProgram &linear_problem, TimeLimit *time_limit)
glop::Fractional objective_value() const
Returns the objective value of the solution with its offset.
void SetParameters(const BopParameters &parameters)
void Clear()
Clears, i.e. reset the object to its initial value.
Definition lp_data.cc:143
@ INTEGER
The variable must only take integer values.
void SetObjectiveOffset(Fractional objective_offset)
Definition lp_data.cc:340
void SetObjectiveCoefficient(ColIndex col, Fractional value)
Definition lp_data.cc:335
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
Definition lp_data.cc:258
void SetVariableType(ColIndex col, VariableType type)
Set the type of the variable.
Definition lp_data.cc:245
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition lp_data.cc:318
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Defines the coefficient for col / row.
Definition lp_data.cc:326
void SetMaximizationProblem(bool maximize)
Definition lp_data.cc:352
void assign(IntType size, const T &v)
Definition lp_types.h:319
const ParentType & get() const
SatParameters parameters
const Constraint * ct
int64_t value
IntVar * var
absl::Status status
Definition g_gurobi.cc:44
int constraint_index
time_limit
Definition solve.cc:22
int index
ColIndex col
Definition markowitz.cc:187
RowIndex row
Definition markowitz.cc:186
BopSolveStatus
Status of the solve of Bop.
Definition bop_types.h:34
@ NO_SOLUTION_FOUND
The solver didn't find any solution.
@ OPTIMAL_SOLUTION_FOUND
The solver found the proven optimal solution.
@ INFEASIBLE_PROBLEM
The problem is infeasible.
@ INVALID_PROBLEM
The problem is invalid.
In SWIG mode, we don't want anything besides these top-level includes.
MPSolverInterface * BuildBopInterface(MPSolver *const solver)
Register BOP in the global linear solver factory.
int64_t coefficient
int var_index
Definition search.cc:3268