OR-Tools  9.1
math_opt.h
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 // A C++ API for building optimization problems.
15 //
16 // Warning: Variable, LinearConstraint, and Objective are value types, see
17 // "Memory Model" below.
18 //
19 // A simple example:
20 //
21 // Model the problem:
22 // max 2.0 * x + y
23 // s.t. x + y <= 1.5
24 // x in {0.0, 1.0}
25 // y in [0.0, 2.5]
26 //
27 // using ::operations_research::math_opt::LinearConstraint;
28 // using ::operations_research::math_opt::Objective;
29 // using ::operations_research::math_opt::MathOpt;
30 // using ::operations_research::math_opt::Result;
31 // using ::operations_research::math_opt::SolveParameters;
32 // using ::operations_research::math_opt::SolveResultProto;
33 // using ::operations_research::math_opt::Variable;
34 //
35 // Version 1:
36 //
37 // MathOpt optimizer(operations_research::math_opt::SOLVER_TYPE_GSCIP,
38 // "my_model");
39 // const Variable x = optimizer.AddBinaryVariable("x");
40 // const Variable y = optimizer.AddContinuousVariable(0.0, 2.5, "y");
41 // const LinearConstraint c = optimizer.AddLinearConstraint(
42 // -std::numeric_limits<double>::infinity(), 1.5, "c");
43 // c.set_coefficient(x, 1.0);
44 // c.set_coefficient(y, 1.0);
45 // const Objective obj = optimizer.objective();
46 // obj.set_linear_coefficient(x, 2.0);
47 // obj.set_linear_coefficient(y, 1.0);
48 // obj.set_maximize();
49 // const Result result = optimizer.Solve(SolveParametersProto()).value();
50 // for (const auto& warning : result.warnings) {
51 // std::cerr << "Solver warning: " << warning << std::endl;
52 // }
53 // CHECK_EQ(result.termination_reason, SolveResultProto::OPTIMAL)
54 // << result.termination_detail;
55 // // The following code will print:
56 // // objective value: 2.5
57 // // value for variable x: 1
58 // std::cout << "objective value: " << result.objective_value()
59 // << "\nvalue for variable x: " << result.variable_values().at(x)
60 // << std::endl;
61 //
62 // Version 2 (with linear expressions):
63 //
64 // MathOpt optimizer(operations_research::math_opt::SOLVER_TYPE_GSCIP,
65 // "my_model");
66 // const Variable x = optimizer.AddBinaryVariable("x");
67 // const Variable y = optimizer.AddContinuousVariable(0.0, 2.5, "y");
68 // // We can directly use linear combinations of variables ...
69 // optimizer.AddLinearConstraint(x + y <= 1.5, "c");
70 // // ... or build them incrementally.
71 // LinearExpression objective_expression;
72 // objective_expression += 2*x;
73 // objective_expression += y;
74 // optimizer.objective().Maximize(objective_expression);
75 // const Result result = optimizer.Solve(SolveParametersProto()).value();
76 // for (const auto& warning : result.warnings) {
77 // std::cerr << "Solver warning: " << warning << std::endl;
78 // }
79 // CHECK_EQ(result.termination_reason, SolveResultProto::OPTIMAL)
80 // << result.termination_detail;
81 // // The following code will print:
82 // // objective value: 2.5
83 // // value for variable x: 1
84 // std::cout << "objective value: " << result.objective_value()
85 // << "\nvalue for variable x: " << result.variable_values().at(x)
86 // << std::endl;
87 //
88 // Memory model:
89 //
90 // Variable, LinearConstraint, and Objective are all value types that
91 // represent references to the underlying MathOpt object. They don't hold any of
92 // the actual model data, they can be copied, and they should be passed by
93 // value. They can be regenerated arbitrarily from MathOpt. MathOpt holds all
94 // the data.
95 //
96 // Performance:
97 //
98 // This class is a thin wrapper around IndexedModel (for incrementally building
99 // the model and reading it back, and producing the Model proto) and Solver (for
100 // consuming the Model proto to solve the optimization problem). Operations for
101 // building/reading/modifying the problem typically run in O(read/write size)
102 // and rely on hashing, see the indexed model documentation for details. At
103 // solve time (if you are solving locally) beware that there will be (at least)
104 // three copies of the model in memory, IndexedModel, the Model proto, and the
105 // underlying solver's copy(/ies). Note that the Model proto is reclaimed before
106 // the underlying solver begins solving.
107 
108 #ifndef OR_TOOLS_MATH_OPT_CPP_MATH_OPT_H_
109 #define OR_TOOLS_MATH_OPT_CPP_MATH_OPT_H_
110 
111 #include <functional>
112 #include <memory>
113 #include <string>
114 #include <utility>
115 #include <vector>
116 
117 #include "ortools/base/logging.h"
118 #include "absl/memory/memory.h"
119 #include "absl/status/statusor.h"
120 #include "absl/strings/string_view.h"
123 #include "ortools/math_opt/cpp/callback.h" // IWYU pragma: export
124 #include "ortools/math_opt/cpp/linear_constraint.h" // IWYU pragma: export
125 #include "ortools/math_opt/cpp/model_solve_parameters.h" // IWYU pragma: export
126 #include "ortools/math_opt/cpp/objective.h" // IWYU pragma: export
127 #include "ortools/math_opt/cpp/result.h" // IWYU pragma: export
128 #include "ortools/math_opt/cpp/variable_and_expressions.h" // IWYU pragma: export
129 #include "ortools/math_opt/model.pb.h" // IWYU pragma: export
130 #include "ortools/math_opt/parameters.pb.h" // IWYU pragma: export
131 #include "ortools/math_opt/result.pb.h" // IWYU pragma: export
132 
133 namespace operations_research {
134 namespace math_opt {
135 
136 // Models and solves mathematical optimization problems.
137 class MathOpt {
138  public:
139  using Callback = std::function<CallbackResult(CallbackData)>;
140 
141  MathOpt(const MathOpt&) = delete;
142  MathOpt& operator=(const MathOpt&) = delete;
143 
144  // Creates an empty minimization problem.
145  inline explicit MathOpt(
146  SolverType solver_type, absl::string_view name = "",
147  SolverInitializerProto solver_initializer = SolverInitializerProto());
148 
149  inline const std::string& name() const;
150 
151  // Adds a variable to the model and returns a reference to it.
152  inline Variable AddVariable(double lower_bound, double upper_bound,
153  bool is_integer, absl::string_view name = "");
154 
155  // Adds a continuous unbounded variable to the model.
156  inline Variable AddVariable(absl::string_view name = "");
157 
158  // Adds an variable to the model with domain {0, 1}.
159  inline Variable AddBinaryVariable(absl::string_view name = "");
160 
161  // Adds a variable to the model with domain [lower_bound, upper_bound].
163  absl::string_view name = "");
164 
165  // Adds a variable to the model that can take integer values between
166  // lower_bound and upper_bound (inclusive).
167  inline Variable AddIntegerVariable(double lower_bound, double upper_bound,
168  absl::string_view name = "");
169 
170  // Removes a variable from the model.
171  //
172  // It is an error to use any reference to this variable after this operation.
173  // Runs in O(#constraints containing the variable).
174  inline void DeleteVariable(Variable variable);
175 
176  // The number of variables in the model.
177  //
178  // Equal to the number of variables created minus the number of variables
179  // deleted.
180  inline int num_variables() const;
181 
182  // The returned id of the next call to AddVariable.
183  //
184  // Equal to the number of variables created.
185  inline int next_variable_id() const;
186 
187  // Returns true if this id has been created and not yet deleted.
188  inline bool has_variable(int id) const;
189 
190  // Returns all the existing (created and not deleted) variables in the model
191  // in an arbitrary order.
192  std::vector<Variable> Variables();
193 
194  // Returns all the existing (created and not deleted) variables in the model,
195  // sorted by id.
196  std::vector<Variable> SortedVariables();
197 
198  std::vector<LinearConstraint> ColumnNonzeros(Variable variable);
199 
200  // Adds a linear constraint to the model with bounds [-inf, +inf].
201  inline LinearConstraint AddLinearConstraint(absl::string_view name = "");
202 
203  // Adds a linear constraint with bounds [lower_bound, upper_bound].
205  double upper_bound,
206  absl::string_view name = "");
207 
208  // Adds a linear constraint from the given bounded linear expression.
209  //
210  // Usage:
211  // MathOpt model = ...;
212  // const Variable x = ...;
213  // const Variable y = ...;
214  // model.AddLinearConstraint(3 <= 2 * x + y + 1 <= 5, "c");
215  // // The new constraint formula is:
216  // // 3 - 1 <= 2 * x + y <= 5 - 1
217  // // Which is:
218  // // 2 <= 2 * x + y <= 4
219  // // since the offset has been removed from bounds.
220  //
221  // model.AddLinearConstraint(2 * x + y == x + 5 * z + 3);
222  // model.AddLinearConstraint(x >= 5);
224  const BoundedLinearExpression& bounded_expr, absl::string_view name = "");
225 
226  // Removes a linear constraint from the model.
227  //
228  // It is an error to use any reference to this linear constraint after this
229  // operation. Runs in O(#variables in the linear constraint).
230  inline void DeleteLinearConstraint(LinearConstraint constraint);
231 
232  // The number of linear constraints in the model.
233  //
234  // Equal to the number of linear constraints created minus the number of
235  // linear constraints deleted.
236  inline int num_linear_constraints() const;
237 
238  // The returned id of the next call to AddLinearConstraint.
239  //
240  // Equal to the number of linear constraints created.
241  inline int next_linear_constraint_id() const;
242 
243  // Returns true if this id has been created and not yet deleted.
244  inline bool has_linear_constraint(int id) const;
245 
246  // Returns all the existing (created and not deleted) linear constraints in
247  // the model in an arbitrary order.
248  std::vector<LinearConstraint> LinearConstraints();
249 
250  // Returns all the existing (created and not deleted) linear constraints in
251  // the model sorted by id.
252  std::vector<LinearConstraint> SortedLinearConstraints();
253 
254  inline Objective objective();
255 
256  // Solves the current optimization problem.
257  //
258  // A Status error will be returned if there is an unexpected failure in an
259  // underlying solver or for some internal MathOpt errors. Otherwise, check
260  // Result::termination_reason to see if an optimal solution was found.
261  //
262  // Memory model: the returned Result owns its own memory (for solutions, solve
263  // stats, etc.), EXPECT for a pointer back to this->model_. As a result:
264  // * Keep this alive to access Result
265  // * Avoid unnecessarily copying Result,
266  // * The result is generally accessible after mutating this, but some care
267  // is needed if Variables or LinearConstraints are added or deleted.
268  //
269  // Asserts (using CHECK) that the inputs model_parameters and
270  // callback_registration only contain variables and constraints from this
271  // model.
272  //
273  // See callback.h for documentation on callback and callback_registration.
274  absl::StatusOr<Result> Solve(
275  const SolveParametersProto& solver_parameters,
276  const ModelSolveParameters& model_parameters = {},
277  const CallbackRegistration& callback_registration = {},
278  Callback callback = nullptr);
279 
280  ModelProto ExportModel() const;
281 
282  // TODO(user): expose a way to efficiently iterate through the nonzeros of
283  // the linear constraint matrix.
284  private:
285  // Asserts (with CHECK) that the input pointer is either nullptr or that it
286  // points to the same model as model_.
287  void CheckModel(IndexedModel* model);
288  const SolverType solver_type_;
289  const SolverInitializerProto solver_initializer_;
290  const std::unique_ptr<IndexedModel> model_;
291  std::unique_ptr<Solver> solver_;
292  std::unique_ptr<IndexedModel::UpdateTracker> update_tracker_;
293 };
294 
296 // Inline function implementations
298 
299 MathOpt::MathOpt(const SolverType solver_type, const absl::string_view name,
300  SolverInitializerProto solver_initializer)
301  : solver_type_(solver_type),
302  solver_initializer_(std::move(solver_initializer)),
303  model_(absl::make_unique<IndexedModel>(name)) {}
304 
305 const std::string& MathOpt::name() const { return model_->name(); }
306 
307 Variable MathOpt::AddVariable(const absl::string_view name) {
308  return Variable(model_.get(), model_->AddVariable(name));
309 }
311  const double upper_bound, const bool is_integer,
312  const absl::string_view name) {
313  return Variable(model_.get(), model_->AddVariable(lower_bound, upper_bound,
314  is_integer, name));
315 }
316 
317 Variable MathOpt::AddBinaryVariable(const absl::string_view name) {
318  return AddVariable(0.0, 1.0, true, name);
319 }
320 
322  const double upper_bound,
323  const absl::string_view name) {
324  return AddVariable(lower_bound, upper_bound, false, name);
325 }
326 
328  const double upper_bound,
329  const absl::string_view name) {
330  return AddVariable(lower_bound, upper_bound, true, name);
331 }
332 
333 void MathOpt::DeleteVariable(const Variable variable) {
334  CHECK_EQ(model_.get(), variable.model());
335  model_->DeleteVariable(variable.typed_id());
336 }
337 
338 int MathOpt::num_variables() const { return model_->num_variables(); }
339 
341  return model_->next_variable_id().value();
342 }
343 
344 bool MathOpt::has_variable(const int id) const {
345  return model_->has_variable(VariableId(id));
346 }
347 
349  return LinearConstraint(model_.get(), model_->AddLinearConstraint(name));
350 }
352  const double upper_bound,
353  const absl::string_view name) {
354  return LinearConstraint(model_.get(), model_->AddLinearConstraint(
356 }
357 
359  CHECK_EQ(model_.get(), constraint.model());
360  model_->DeleteLinearConstraint(constraint.typed_id());
361 }
362 
364  return model_->num_linear_constraints();
365 }
366 
368  return model_->next_linear_constraint_id().value();
369 }
370 
371 bool MathOpt::has_linear_constraint(const int id) const {
372  return model_->has_linear_constraint(LinearConstraintId(id));
373 }
374 
375 Objective MathOpt::objective() { return Objective(model_.get()); }
376 
377 } // namespace math_opt
378 } // namespace operations_research
379 
380 #endif // OR_TOOLS_MATH_OPT_CPP_MATH_OPT_H_
Variable AddVariable(double lower_bound, double upper_bound, bool is_integer, absl::string_view name="")
Definition: math_opt.h:310
std::vector< LinearConstraint > ColumnNonzeros(Variable variable)
Definition: math_opt.cc:130
void DeleteVariable(Variable variable)
Definition: math_opt.h:333
std::vector< Variable > SortedVariables()
Definition: math_opt.cc:121
LinearConstraint AddLinearConstraint(absl::string_view name="")
Definition: math_opt.h:348
const std::string name
MathOpt & operator=(const MathOpt &)=delete
MPCallback * callback
GRBmodel * model
std::function< CallbackResult(CallbackData)> Callback
Definition: math_opt.h:139
Definition: cleanup.h:22
double upper_bound
Variable AddIntegerVariable(double lower_bound, double upper_bound, absl::string_view name="")
Definition: math_opt.h:327
bool has_linear_constraint(int id) const
Definition: math_opt.h:371
double lower_bound
std::vector< Variable > Variables()
Definition: math_opt.cc:112
Variable AddContinuousVariable(double lower_bound, double upper_bound, absl::string_view name="")
Definition: math_opt.h:321
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:698
void DeleteLinearConstraint(LinearConstraint constraint)
Definition: math_opt.h:358
Variable AddBinaryVariable(absl::string_view name="")
Definition: math_opt.h:317
std::vector< LinearConstraint > SortedLinearConstraints()
Definition: math_opt.cc:148
Collection of objects used to extend the Constraint Solver library.
absl::StatusOr< Result > Solve(const SolveParametersProto &solver_parameters, const ModelSolveParameters &model_parameters={}, const CallbackRegistration &callback_registration={}, Callback callback=nullptr)
Definition: math_opt.cc:37
const std::string & name() const
Definition: math_opt.h:305
std::vector< LinearConstraint > LinearConstraints()
Definition: math_opt.cc:139