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