OR-Tools  9.0
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"
121 #include "ortools/math_opt/cpp/callback.h" // IWYU pragma: export
122 #include "ortools/math_opt/cpp/linear_constraint.h" // IWYU pragma: export
123 #include "ortools/math_opt/cpp/model_solve_parameters.h" // IWYU pragma: export
124 #include "ortools/math_opt/cpp/objective.h" // IWYU pragma: export
125 #include "ortools/math_opt/cpp/result.h" // IWYU pragma: export
126 #include "ortools/math_opt/cpp/variable_and_expressions.h" // IWYU pragma: export
128 #include "ortools/math_opt/model.pb.h" // IWYU pragma: export
129 #include "ortools/math_opt/parameters.pb.h" // IWYU pragma: export
130 #include "ortools/math_opt/result.pb.h" // IWYU pragma: export
131 #include "ortools/math_opt/solver.h"
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  // Adds a linear constraint to the model with bounds [-inf, +inf].
199  inline LinearConstraint AddLinearConstraint(absl::string_view name = "");
200 
201  // Adds a linear constraint with bounds [lower_bound, upper_bound].
203  double upper_bound,
204  absl::string_view name = "");
205 
206  // Adds a linear constraint from the given bounded linear expression.
207  //
208  // Usage:
209  // MathOpt model = ...;
210  // const Variable x = ...;
211  // const Variable y = ...;
212  // model.AddLinearConstraint(3 <= 2 * x + y + 1 <= 5, "c");
213  // // The new constraint formula is:
214  // // 3 - 1 <= 2 * x + y <= 5 - 1
215  // // Which is:
216  // // 2 <= 2 * x + y <= 4
217  // // since the offset has been removed from bounds.
218  //
219  // model.AddLinearConstraint(2 * x + y == x + 5 * z + 3);
220  // model.AddLinearConstraint(x >= 5);
222  const BoundedLinearExpression& bounded_expr, absl::string_view name = "");
223 
224  // Removes a linear constraint from the model.
225  //
226  // It is an error to use any reference to this linear constraint after this
227  // operation. Runs in O(#variables in the linear constraint).
228  inline void DeleteLinearConstraint(LinearConstraint constraint);
229 
230  // The number of linear constraints in the model.
231  //
232  // Equal to the number of linear constraints created minus the number of
233  // linear constraints deleted.
234  inline int num_linear_constraints() const;
235 
236  // The returned id of the next call to AddLinearConstraint.
237  //
238  // Equal to the number of linear constraints created.
239  inline int next_linear_constraint_id() const;
240 
241  // Returns true if this id has been created and not yet deleted.
242  inline bool has_linear_constraint(int id) const;
243 
244  // Returns all the existing (created and not deleted) linear constraints in
245  // the model in an arbitrary order.
246  std::vector<LinearConstraint> LinearConstraints();
247 
248  // Returns all the existing (created and not deleted) linear constraints in
249  // the model sorted by id.
250  std::vector<LinearConstraint> SortedLinearConstraints();
251 
252  inline Objective objective();
253 
254  // Solves the current optimization problem.
255  //
256  // A Status error will be returned if there is an unexpected failure in an
257  // underlying solver or for some internal MathOpt errors. Otherwise, check
258  // Result::termination_reason to see if an optimal solution was found.
259  //
260  // Memory model: the returned Result owns its own memory (for solutions, solve
261  // stats, etc.), EXPECT for a pointer back to this->model_. As a result:
262  // * Keep this alive to access Result
263  // * Avoid unnecessarily copying Result,
264  // * The result is generally accessible after mutating this, but some care
265  // is needed if Variables or LinearConstraints are added or deleted.
266  //
267  // Asserts (using CHECK) that the inputs model_parameters and
268  // callback_registration only contain variables and constraints from this
269  // model.
270  //
271  // See callback.h for documentation on callback and callback_registration.
272  absl::StatusOr<Result> Solve(
273  const SolveParametersProto& solver_parameters,
274  const ModelSolveParameters& model_parameters = {},
275  const CallbackRegistration& callback_registration = {},
276  Callback callback = nullptr);
277 
278  ModelProto ExportModel() const;
279 
280  // TODO(user): expose a way to efficiently iterate through the nonzeros of
281  // the linear constraint matrix.
282  private:
283  // Asserts (with CHECK) that the input pointer is either nullptr or that it
284  // points to the same model as model_.
285  void CheckModel(IndexedModel* model);
286  const SolverType solver_type_;
287  const SolverInitializerProto solver_initializer_;
288  const std::unique_ptr<IndexedModel> model_;
289  std::unique_ptr<Solver> solver_;
290 };
291 
293 // Inline function implementations
295 
296 MathOpt::MathOpt(const SolverType solver_type, const absl::string_view name,
297  SolverInitializerProto solver_initializer)
298  : solver_type_(solver_type),
299  solver_initializer_(std::move(solver_initializer)),
300  model_(absl::make_unique<IndexedModel>(name)) {}
301 
302 const std::string& MathOpt::name() const { return model_->name(); }
303 
304 Variable MathOpt::AddVariable(const absl::string_view name) {
305  return Variable(model_.get(), model_->AddVariable(name));
306 }
308  const double upper_bound, const bool is_integer,
309  const absl::string_view name) {
310  return Variable(model_.get(), model_->AddVariable(lower_bound, upper_bound,
311  is_integer, name));
312 }
313 
314 Variable MathOpt::AddBinaryVariable(const absl::string_view name) {
315  return AddVariable(0.0, 1.0, true, name);
316 }
317 
319  const double upper_bound,
320  const absl::string_view name) {
321  return AddVariable(lower_bound, upper_bound, false, name);
322 }
323 
325  const double upper_bound,
326  const absl::string_view name) {
327  return AddVariable(lower_bound, upper_bound, true, name);
328 }
329 
330 void MathOpt::DeleteVariable(const Variable variable) {
331  CHECK_EQ(model_.get(), variable.model());
332  model_->DeleteVariable(variable.typed_id());
333 }
334 
335 int MathOpt::num_variables() const { return model_->num_variables(); }
336 
338  return model_->next_variable_id().value();
339 }
340 
341 bool MathOpt::has_variable(const int id) const {
342  return model_->has_variable(VariableId(id));
343 }
344 
346  return LinearConstraint(model_.get(), model_->AddLinearConstraint(name));
347 }
349  const double upper_bound,
350  const absl::string_view name) {
351  return LinearConstraint(model_.get(), model_->AddLinearConstraint(
353 }
354 
356  CHECK_EQ(model_.get(), constraint.model());
357  model_->DeleteLinearConstraint(constraint.typed_id());
358 }
359 
361  return model_->num_linear_constraints();
362 }
363 
365  return model_->next_linear_constraint_id().value();
366 }
367 
368 bool MathOpt::has_linear_constraint(const int id) const {
369  return model_->has_linear_constraint(LinearConstraintId(id));
370 }
371 
372 Objective MathOpt::objective() { return Objective(model_.get()); }
373 
374 } // namespace math_opt
375 } // namespace operations_research
376 
377 #endif // OR_TOOLS_MATH_OPT_CPP_MATH_OPT_H_
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:705
void DeleteVariable(Variable variable)
Definition: math_opt.h:330
std::function< CallbackResult(CallbackData)> Callback
Definition: math_opt.h:139
Variable AddBinaryVariable(absl::string_view name="")
Definition: math_opt.h:314
const std::string & name() const
Definition: math_opt.h:302
Variable AddIntegerVariable(double lower_bound, double upper_bound, absl::string_view name="")
Definition: math_opt.h:324
MathOpt & operator=(const MathOpt &)=delete
LinearConstraint AddLinearConstraint(absl::string_view name="")
Definition: math_opt.h:345
std::vector< Variable > Variables()
Definition: math_opt.cc:95
void DeleteLinearConstraint(LinearConstraint constraint)
Definition: math_opt.h:355
Variable AddContinuousVariable(double lower_bound, double upper_bound, absl::string_view name="")
Definition: math_opt.h:318
absl::StatusOr< Result > Solve(const SolveParametersProto &solver_parameters, const ModelSolveParameters &model_parameters={}, const CallbackRegistration &callback_registration={}, Callback callback=nullptr)
Definition: math_opt.cc:37
std::vector< LinearConstraint > LinearConstraints()
Definition: math_opt.cc:113
bool has_linear_constraint(int id) const
Definition: math_opt.h:368
std::vector< LinearConstraint > SortedLinearConstraints()
Definition: math_opt.cc:122
std::vector< Variable > SortedVariables()
Definition: math_opt.cc:104
Variable AddVariable(double lower_bound, double upper_bound, bool is_integer, absl::string_view name="")
Definition: math_opt.h:307
const std::string name
double upper_bound
double lower_bound
GRBmodel * model
MPCallback * callback
Definition: cleanup.h:22
Collection of objects used to extend the Constraint Solver library.