OR-Tools  9.2
solve.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// Functions and classes used to solve a Model.
15//
16// The main entry point is the Solve() function.
17//
18// For users that need incremental solving, there is the IncrementalSolver
19// class.
20#ifndef OR_TOOLS_MATH_OPT_CPP_SOLVE_H_
21#define OR_TOOLS_MATH_OPT_CPP_SOLVE_H_
22
23#include <functional>
24#include <iostream>
25#include <memory>
26#include <optional>
27#include <string>
28#include <utility>
29#include <vector>
30
31#include "absl/status/statusor.h"
32#include "absl/strings/string_view.h"
36#include "ortools/math_opt/core/solve_interrupter.h" // IWYU pragma: export
38#include "ortools/math_opt/cpp/callback.h" // IWYU pragma: export
40#include "ortools/math_opt/cpp/model_solve_parameters.h" // IWYU pragma: export
41#include "ortools/math_opt/cpp/parameters.h" // IWYU pragma: export
42#include "ortools/math_opt/cpp/solve_result.h" // IWYU pragma: export
43#include "ortools/math_opt/cpp/streamable_solver_init_arguments.h" // IWYU pragma: export
44#include "ortools/math_opt/parameters.pb.h" // IWYU pragma: export
45
46namespace operations_research {
47namespace math_opt {
48
49// Callback function for messages callback sent by the solver.
50//
51// Each message represents a single output line from the solver, and each
52// message does not contain any '\n' character in it.
53//
54// Thread-safety: a callback may be called concurrently from multiple
55// threads. The users is expected to use proper synchronization primitives to
56// deal with that.
57using MessageCallback = std::function<void(const std::vector<std::string>&)>;
58
59// Returns a message callback function that prints its output to the given
60// output stream, prefixing each line with the given prefix.
61//
62// For each call to the returned message callback, the output_stream is flushed.
63//
64// Usage:
65//
66// SolveArguments args;
67// args.message_callback = PrinterMessageCallback(std::cerr, "solver logs> ");
68MessageCallback PrinterMessageCallback(std::ostream& output_stream = std::cout,
69 absl::string_view prefix = "");
70
71
72// Arguments passed to Solve() and IncrementalSolver::New() to control the
73// instantiation of the solver.
74//
75// For convenience, constructors with streamable or/and non-streamable arguments
76// are provided. The non-streamable arguments are cloned so any change made
77// after passing them to this class are ignored.
78//
79// Usage with streamable arguments:
80//
81// Solve(model, SOLVER_TYPE_GUROBI, /*solver_args=*/{},
82// SolverInitArguments({
83// .gurobi = StreamableGurobiInitArguments{
84// .isv_key = GurobiISVKey{
85// .name = "some name",
86// .application_name = "some app name",
87// .expiration = -1,
88// .key = "random",
89// }
90// }
91// });
92//
93// Usage with non-streamable arguments:
94//
95// NonStreamableGurobiInitArguments gurobi_args;
96// gurobi_args.master_env = master_env.get();
97//
98// Solve(model, SOLVER_TYPE_GUROBI, /*solver_args=*/{},
99// SolverInitArguments(gurobi_args));
100//
103
104 // Initializes this class with a copy of the provided streamable arguments.
106
107 // Initializes this class with a clone of the provided non-streamable
108 // arguments.
109 //
110 // Note that since this constructors calls Clone() to initialize the
111 // non_streamable_solver_init_arguments field, changes made after calling it
112 // to the input non_streamable are ignored.
113 explicit SolverInitArguments(
115
116 // Initializes this class with both the provided a copy streamable arguments
117 // and a clone of the non-streamable ones.
120
121 // Initializes this class as a copy of the provided arguments. The
122 // non_streamable field is cloned if not nullptr.
124
125 // Sets this class as a copy of the provided arguments. The non_streamable
126 // field is cloned if not nullptr.
128
131
133
134 // This should either be the solver specific class or nullptr.
135 //
136 // Solvers will fail (by returning an absl::Status) if called with arguments
137 // for another solver.
138 std::unique_ptr<const NonStreamableSolverInitArguments> non_streamable;
139};
140
141// Arguments passed to Solve() and IncrementalSolver::Solve() to control the
142// solve.
144 // Model independent parameters, e.g. time limit.
146
147 // Model dependent parameters, e.g. solution hint.
149
150 // An optional callback for messages emitted by the solver.
151 //
152 // When set it enables the solver messages and ignores the `enable_output` in
153 // solve parameters; messages are redirected to the callback and not printed
154 // on stdout/stderr/logs anymore.
155 //
156 // See PrinterMessageCallback() for logging to stdout/stderr.
157 //
158 // Usage:
159 //
160 // // To print messages to stdout with a prefix.
161 // ASSIGN_OR_RETURN(
162 // const SolveResult result,
163 // Solve(model, SOLVER_TYPE_GLOP,
164 // { .message_callback = PrinterMessageCallback(std::cout,
165 // "logs| "); });
166 //
167 // // To print messages to the INFO log.
168 // ASSIGN_OR_RETURN(
169 // const SolveResult result,
170 // Solve(model, SOLVER_TYPE_GLOP,
171 // { .message_callback = InfoLoggerMessageCallback("[solver] "); });
172 //
173 // // To print messages to the VLOG(1) log.
174 // ASSIGN_OR_RETURN(
175 // const SolveResult result,
176 // Solve(model, SOLVER_TYPE_GLOP,
177 // { .message_callback = VLoggerMessageCallback(1, "[solver] "); });
178 //
180
181 // Callback registration parameters. Usually `callback` should also be set
182 // when these parameters are modified.
184
185 // The callback. The `callback_registration` parameters have to be set, in
186 // particular `callback_registration.events`.
188
189 // An optional interrupter that the solver can use to interrupt the solve
190 // early.
191 //
192 // Usage:
193 // auto interrupter = std::make_shared<SolveInterrupter>();
194 //
195 // // Use another thread to trigger the interrupter.
196 // RunInOtherThread([interrupter](){
197 // ... wait for something that should interrupt the solve ...
198 // interrupter->Interrupt();
199 // });
200 //
201 // ASSIGN_OR_RETURN(const SolveResult result,
202 // Solve(model, SOLVER_TYPE_GLOP,
203 // { .interrupter = interrupter.get() });
204 //
206};
207
208// Solves the input model.
209//
210// A Status error will be returned if there is an unexpected failure in an
211// underlying solver or for some internal math_opt errors. Otherwise, check
212// SolveResult::termination.reason to see if an optimal solution was found.
213//
214// Memory model: the returned SolveResult owns its own memory (for solutions,
215// solve stats, etc.), EXPECT for a pointer back to the model. As a result:
216// * Keep the model alive to access SolveResult,
217// * Avoid unnecessarily copying SolveResult,
218// * The result is generally accessible after mutating the model, but some care
219// is needed if variables or linear constraints are added or deleted.
220//
221// Asserts (using CHECK) that the inputs solve_args.model_parameters and
222// solve_args.callback_registration only contain variables and constraints from
223// the input model.
224//
225// See callback.h for documentation on solve_args.callback and
226// solve_args.callback_registration.
227//
228// Thread-safety: this method is safe to call concurrently on the same Model.
229//
230// Some solvers may add more restrictions regarding threading. Please see
231// SolverType::kXxx documentation for details.
232absl::StatusOr<SolveResult> Solve(const Model& model, SolverType solver_type,
233 const SolveArguments& solve_args = {},
234 const SolverInitArguments& init_args = {});
235
236// Incremental solve of a model.
237//
238// This is a feature for advance users. Most users should only use the Solve()
239// function above.
240//
241// Here incremental means that the we try to reuse the existing underlying
242// solver internals between each solve. There is no guarantee though that the
243// solver supports all possible model changes. Hence there is not guarantee that
244// performances will be improved when using this class; this is solver
245// dependent. Typically LPs have more to gain from incremental solve than
246// MIPs. In both cases, even if the solver supports the model changes,
247// incremental solve may actually be slower.
248//
249// The New() function instantiates the solver and setup it from the current
250// state of the Model. Calling Solve() will update the underlying solver with
251// latest model changes and solve this model.
252//
253// Usage:
254// Model model = ...;
255// ASSIGN_OR_RETURN(
256// const std::unique_ptr<IncrementalSolver> incremental_solve,
257// IncrementalSolver::New(model, SOLVER_TYPE_XXX));
258//
259// ASSIGN_OR_RETURN(const SolveResult result1, incremental_solve->Solve());
260//
261// model.AddVariable(...);
262// ...
263//
264// ASSIGN_OR_RETURN(const SolveResult result2, incremental_solve->Solve());
265//
266// ...
267//
268// Thread-safety: The New(), Solve() and Update() methods must not be called
269// while modifying the Model() (adding variables...). The user is expected to
270// use proper synchronization primitives to serialize changes to the model and
271// the use of this object. Note though that it is safe to call methods from
272// different IncrementalSolver instances on the same Model concurrently.
273//
274// There is no problem calling SolveWithoutUpdate() concurrently on different
275// instances of IncrementalSolver or while the model is being modified (unless
276// of course the underlying solver itself is not thread-safe and can only be
277// called from a single-thread).
278//
279// Note that Solve(), Update() and SolveWithoutUpdate() are not reentrant so
280// they should not be called concurrently on the same instance of
281// IncrementalSolver.
282//
283// Some solvers may add more restrictions regarding threading. Please see
284// SolverType::kXxx documentation for details.
286 public:
288 UpdateResult(const bool did_update, std::optional<ModelUpdateProto> update)
289 : did_update(did_update), update(std::move(update)) {}
290
291 // True if the solver has been successfully updated or if no update was
292 // necessary (in which case `update` will be nullopt). False if the solver
293 // had to be recreated.
295
296 // The update that was attempted on the solver. Can be nullopt when no
297 // update was needed (the model was not changed).
298 std::optional<ModelUpdateProto> update;
299 };
300
301 // Creates a new incremental solve for the given model. It may returns an
302 // error if the parameters are invalid (for example if the selected solver is
303 // not linked in the binary).
304 //
305 // The returned IncrementalSolver keeps a copy of `arguments`. Thus the
306 // content of arguments.non_streamable (for example pointers to solver
307 // specific struct) must be valid until the destruction of the
308 // IncrementalSolver.
309 static absl::StatusOr<std::unique_ptr<IncrementalSolver>> New(
310 Model& model, SolverType solver_type, SolverInitArguments arguments = {});
311
312 // Updates the underlying solver with latest model changes and runs the solve.
313 //
314 // A Status error will be returned if there is an unexpected failure in an
315 // underlying solver or for some internal math_opt errors. Otherwise, check
316 // SolveResult::termination.reason to see if an optimal solution was found.
317 //
318 // Memory model: the returned SolveResult owns its own memory (for solutions,
319 // solve stats, etc.), EXPECT for a pointer back to the model. As a result:
320 // * Keep the model alive to access SolveResult,
321 // * Avoid unnecessarily copying SolveResult,
322 // * The result is generally accessible after mutating this, but some care
323 // is needed if variables or linear constraints are added or deleted.
324 //
325 // Asserts (using CHECK) that the inputs arguments.model_parameters and
326 // arguments.callback_registration only contain variables and constraints from
327 // the input model.
328 //
329 // See callback.h for documentation on arguments.callback and
330 // arguments.callback_registration.
331 absl::StatusOr<SolveResult> Solve(const SolveArguments& arguments = {});
332
333 // Updates the model to solve.
334 //
335 // This is an advanced API, most users should use Solve() above that does the
336 // update and before calling the solver. Calling this function is only useful
337 // for users that want to access to update data or users that need to use
338 // SolveWithoutUpdate() (which should not be common).
339 //
340 // The returned value indicates if the update was possible or if the solver
341 // had to be recreated from scratch (which may happen when the solver does not
342 // support this specific update or any update at all). It also contains the
343 // attempted update data.
344 //
345 // A status error will be returned if the underlying solver has an internal
346 // error.
347 absl::StatusOr<UpdateResult> Update();
348
349 // Same as Solve() but does not update the underlying solver with the latest
350 // changes to the model.
351 //
352 // This is an advanced API, most users should use Solve().
353 absl::StatusOr<SolveResult> SolveWithoutUpdate(
354 const SolveArguments& arguments = {}) const;
355
356 private:
357 IncrementalSolver(SolverType solver_type, SolverInitArguments init_args,
358 const ModelStorage* expected_storage,
359 std::unique_ptr<UpdateTracker> update_tracker,
360 std::unique_ptr<Solver> solver);
361
362 const SolverType solver_type_;
363 const SolverInitArguments init_args_;
364 const ModelStorage* const expected_storage_;
365 const std::unique_ptr<UpdateTracker> update_tracker_;
366 std::unique_ptr<Solver> solver_;
367};
368
369} // namespace math_opt
370} // namespace operations_research
371
372#endif // OR_TOOLS_MATH_OPT_CPP_SOLVE_H_
absl::StatusOr< SolveResult > Solve(const SolveArguments &arguments={})
Definition: solve.cc:188
absl::StatusOr< UpdateResult > Update()
Definition: solve.cc:194
absl::StatusOr< SolveResult > SolveWithoutUpdate(const SolveArguments &arguments={}) const
Definition: solve.cc:215
static absl::StatusOr< std::unique_ptr< IncrementalSolver > > New(Model &model, SolverType solver_type, SolverInitArguments arguments={})
Definition: solve.cc:165
GRBmodel * model
absl::StatusOr< SolveResult > Solve(const Model &model, const SolverType solver_type, const SolveArguments &solve_args, const SolverInitArguments &init_args)
Definition: solve.cc:155
MessageCallback PrinterMessageCallback(std::ostream &output_stream, const absl::string_view prefix)
Definition: solve.cc:220
std::function< CallbackResult(const CallbackData &)> Callback
Definition: callback.h:89
std::function< void(const std::vector< std::string > &)> MessageCallback
Definition: solve.h:57
Collection of objects used to extend the Constraint Solver library.
STL namespace.
UpdateResult(const bool did_update, std::optional< ModelUpdateProto > update)
Definition: solve.h:288
CallbackRegistration callback_registration
Definition: solve.h:183
SolverInitArguments(SolverInitArguments &&)=default
SolverInitArguments & operator=(const SolverInitArguments &other)
Definition: solve.cc:141
SolverInitArguments & operator=(SolverInitArguments &&)=default
std::unique_ptr< const NonStreamableSolverInitArguments > non_streamable
Definition: solve.h:138
StreamableSolverInitArguments streamable
Definition: solve.h:132