OR-Tools  9.3
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 <memory>
24#include <optional>
25#include <utility>
26
27#include "absl/status/statusor.h"
31#include "ortools/math_opt/cpp/parameters.h" // IWYU pragma: export
32#include "ortools/math_opt/cpp/solve_arguments.h" // IWYU pragma: export
33#include "ortools/math_opt/cpp/solve_result.h" // IWYU pragma: export
34#include "ortools/math_opt/cpp/solver_init_arguments.h" // IWYU pragma: export
35#include "ortools/math_opt/parameters.pb.h" // IWYU pragma: export
36
37namespace operations_research {
38namespace math_opt {
39
40// Solves the input model.
41//
42// A Status error will be returned if there is an unexpected failure in an
43// underlying solver or for some internal math_opt errors. Otherwise, check
44// SolveResult::termination.reason to see if an optimal solution was found.
45//
46// Memory model: the returned SolveResult owns its own memory (for solutions,
47// solve stats, etc.), EXPECT for a pointer back to the model. As a result:
48// * Keep the model alive to access SolveResult,
49// * Avoid unnecessarily copying SolveResult,
50// * The result is generally accessible after mutating the model, but some care
51// is needed if variables or linear constraints are added or deleted.
52//
53// Asserts (using CHECK) that the inputs solve_args.model_parameters and
54// solve_args.callback_registration only contain variables and constraints from
55// the input model.
56//
57// Thread-safety: this method is safe to call concurrently on the same Model.
58//
59// Some solvers may add more restrictions regarding threading. Please see
60// SolverType::kXxx documentation for details.
61absl::StatusOr<SolveResult> Solve(const Model& model, SolverType solver_type,
62 const SolveArguments& solve_args = {},
63 const SolverInitArguments& init_args = {});
64
65// Incremental solve of a model.
66//
67// This is a feature for advance users. Most users should only use the Solve()
68// function above.
69//
70// Here incremental means that the we try to reuse the existing underlying
71// solver internals between each solve. There is no guarantee though that the
72// solver supports all possible model changes. Hence there is not guarantee that
73// performances will be improved when using this class; this is solver
74// dependent. Typically LPs have more to gain from incremental solve than
75// MIPs. In both cases, even if the solver supports the model changes,
76// incremental solve may actually be slower.
77//
78// The New() function instantiates the solver, setup it from the current state
79// of the Model and register on it to listen to changes. Calling Solve() will
80// update the underlying solver with latest model changes and solve this model.
81//
82// Usage:
83// Model model = ...;
84// ASSIGN_OR_RETURN(
85// const std::unique_ptr<IncrementalSolver> incremental_solve,
86// IncrementalSolver::New(&model, SolverType::kXxx));
87//
88// ASSIGN_OR_RETURN(const SolveResult result1, incremental_solve->Solve());
89//
90// model.AddVariable(...);
91// ...
92//
93// ASSIGN_OR_RETURN(const SolveResult result2, incremental_solve->Solve());
94//
95// ...
96//
97// Lifecycle: The IncrementalSolver is only keeping a std::weak_ref on Model's
98// internal data and thus it returns an error if Update() or Solve() are called
99// after the Model has been destroyed. It is fine to destroy the
100// IncrementalSolver after the associated Model though.
101//
102// Thread-safety: The New(), Solve() and Update() methods must not be called
103// while modifying the Model() (adding variables...). The user is expected to
104// use proper synchronization primitives to serialize changes to the model and
105// the use of this object. Note though that it is safe to call methods from
106// different IncrementalSolver instances on the same Model concurrently.
107//
108// There is no problem calling SolveWithoutUpdate() concurrently on different
109// instances of IncrementalSolver or while the model is being modified (unless
110// of course the underlying solver itself is not thread-safe and can only be
111// called from a single-thread).
112//
113// Note that Solve(), Update() and SolveWithoutUpdate() are not reentrant so
114// they should not be called concurrently on the same instance of
115// IncrementalSolver.
116//
117// Some solvers may add more restrictions regarding threading. Please see
118// SolverType::kXxx documentation for details.
120 public:
122 UpdateResult(const bool did_update, std::optional<ModelUpdateProto> update)
123 : did_update(did_update), update(std::move(update)) {}
124
125 // True if the solver has been successfully updated or if no update was
126 // necessary (in which case `update` will be nullopt). False if the solver
127 // had to be recreated.
129
130 // The update that was attempted on the solver. Can be nullopt when no
131 // update was needed (the model was not changed).
132 std::optional<ModelUpdateProto> update;
133 };
134
135 // Creates a new incremental solve for the given model. It may returns an
136 // error if the parameters are invalid (for example if the selected solver is
137 // not linked in the binary).
138 //
139 // The returned IncrementalSolver keeps a copy of `arguments`. Thus the
140 // content of arguments.non_streamable (for example pointers to solver
141 // specific struct) must be valid until the destruction of the
142 // IncrementalSolver. It also registers on the Model to keep track of updates
143 // (see class documentation for details).
144 static absl::StatusOr<std::unique_ptr<IncrementalSolver>> New(
145 Model* model, SolverType solver_type, SolverInitArguments arguments = {});
146
147 // Updates the underlying solver with latest model changes and runs the solve.
148 //
149 // A Status error will be returned if there is an unexpected failure in an
150 // underlying solver or for some internal math_opt errors. Otherwise, check
151 // SolveResult::termination.reason to see if an optimal solution was found.
152 //
153 // Memory model: the returned SolveResult owns its own memory (for solutions,
154 // solve stats, etc.), EXPECT for a pointer back to the model. As a result:
155 // * Keep the model alive to access SolveResult,
156 // * Avoid unnecessarily copying SolveResult,
157 // * The result is generally accessible after mutating this, but some care
158 // is needed if variables or linear constraints are added or deleted.
159 //
160 // Asserts (using CHECK) that the inputs arguments.model_parameters and
161 // arguments.callback_registration only contain variables and constraints from
162 // the input model.
163 //
164 // See callback.h for documentation on arguments.callback and
165 // arguments.callback_registration.
166 absl::StatusOr<SolveResult> Solve(const SolveArguments& arguments = {});
167
168 // Updates the model to solve.
169 //
170 // This is an advanced API, most users should use Solve() above that does the
171 // update and before calling the solver. Calling this function is only useful
172 // for users that want to access to update data or users that need to use
173 // SolveWithoutUpdate() (which should not be common).
174 //
175 // The returned value indicates if the update was possible or if the solver
176 // had to be recreated from scratch (which may happen when the solver does not
177 // support this specific update or any update at all). It also contains the
178 // attempted update data.
179 //
180 // A status error will be returned if the underlying solver has an internal
181 // error.
182 absl::StatusOr<UpdateResult> Update();
183
184 // Same as Solve() but does not update the underlying solver with the latest
185 // changes to the model.
186 //
187 // This is an advanced API, most users should use Solve().
188 absl::StatusOr<SolveResult> SolveWithoutUpdate(
189 const SolveArguments& arguments = {}) const;
190
191 private:
192 IncrementalSolver(SolverType solver_type, SolverInitArguments init_args,
193 const ModelStorage* expected_storage,
194 std::unique_ptr<UpdateTracker> update_tracker,
195 std::unique_ptr<Solver> solver);
196
197 const SolverType solver_type_;
198 const SolverInitArguments init_args_;
199 const ModelStorage* const expected_storage_;
200 const std::unique_ptr<UpdateTracker> update_tracker_;
201 std::unique_ptr<Solver> solver_;
202};
203
204} // namespace math_opt
205} // namespace operations_research
206
207#endif // OR_TOOLS_MATH_OPT_CPP_SOLVE_H_
absl::StatusOr< SolveResult > Solve(const SolveArguments &arguments={})
Definition: solve.cc:131
absl::StatusOr< UpdateResult > Update()
Definition: solve.cc:137
absl::StatusOr< SolveResult > SolveWithoutUpdate(const SolveArguments &arguments={}) const
Definition: solve.cc:159
static absl::StatusOr< std::unique_ptr< IncrementalSolver > > New(Model *model, SolverType solver_type, SolverInitArguments arguments={})
Definition: solve.cc:104
GRBmodel * model
absl::StatusOr< SolveResult > Solve(const Model &model, const SolverType solver_type, const SolveArguments &solve_args, const SolverInitArguments &init_args)
Definition: solve.cc:94
Collection of objects used to extend the Constraint Solver library.
STL namespace.
UpdateResult(const bool did_update, std::optional< ModelUpdateProto > update)
Definition: solve.h:122