OR-Tools  9.6
solver_interface.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 #ifndef OR_TOOLS_MATH_OPT_CORE_SOLVER_INTERFACE_H_
15 #define OR_TOOLS_MATH_OPT_CORE_SOLVER_INTERFACE_H_
16 
17 #include <functional>
18 #include <memory>
19 #include <string>
20 #include <vector>
21 
22 #include "absl/base/attributes.h"
23 #include "absl/container/flat_hash_map.h"
24 #include "absl/status/status.h"
25 #include "absl/status/statusor.h"
26 #include "absl/strings/string_view.h"
27 #include "absl/synchronization/mutex.h"
28 #include "ortools/math_opt/callback.pb.h"
31 #include "ortools/math_opt/model.pb.h"
32 #include "ortools/math_opt/model_parameters.pb.h"
33 #include "ortools/math_opt/model_update.pb.h"
34 #include "ortools/math_opt/parameters.pb.h"
35 #include "ortools/math_opt/result.pb.h"
36 
37 namespace operations_research {
38 namespace math_opt {
39 namespace internal {
40 
41 // The message of the InvalidArgumentError returned by solvers that are passed a
42 // non null message callback when they don't support it.
43 inline constexpr absl::string_view kMessageCallbackNotSupported =
44  "This solver does not support message callbacks.";
45 
46 } // namespace internal
47 
48 // Interface implemented by actual solvers.
49 //
50 // This interface is not meant to be used directly. The actual API is the one of
51 // the Solver class. The Solver class validates the models before calling this
52 // interface. It makes sure no concurrent calls happen on Solve(), CanUpdate()
53 // and Update(). It makes sure no other function is called after Solve(),
54 // Update() or a callback have failed.
55 //
56 // Implementations of this interface should not have public constructors but
57 // instead have a static `New` function with the signature of Factory function
58 // as defined below. They should register this factory using the macro
59 // MATH_OPT_REGISTER_SOLVER().
61  public:
62  // Initialization arguments.
63  struct InitArgs {
64  // All parameters that can be stored in a proto and exchange with other
65  // processes.
66  SolverInitializerProto streamable;
67 
68  // All parameters that can't be exchanged with another process. The caller
69  // keeps ownership of non_streamable.
71  };
72 
73  // A callback function (if non null) for messages emitted by the solver.
74  //
75  // See Solver::MessageCallback documentation for details.
76  using MessageCallback = std::function<void(const std::vector<std::string>&)>;
77 
78  // A callback function (if non null) is a function that validates its input
79  // and its output, and if fails, return a status. The invariant is that the
80  // solver implementation can rely on receiving valid data. The implementation
81  // of this interface must provide valid input (which will be validated) and
82  // in error, it will return a status (without actually calling the callback
83  // function). This is enforced in the solver.cc layer.
84  using Callback = std::function<absl::StatusOr<CallbackResultProto>(
85  const CallbackDataProto&)>;
86 
87  // A factory builds a solver based on the input model and parameters.
88  //
89  // Implementation should have a static `New()` function with this signature
90  // and no public constructors.
91  //
92  // The implementation should assume the input ModelProto is valid and is free
93  // to CHECK-fail if this is not the case. It should also assume that the input
94  // init_args.streamable and init_args.non_streamable are also either not set
95  // of set to the arguments of the correct solver.
96  using Factory =
97  std::function<absl::StatusOr<std::unique_ptr<SolverInterface>>(
98  const ModelProto& model, const InitArgs& init_args)>;
99 
100  SolverInterface() = default;
103  virtual ~SolverInterface() = default;
104 
105  // Solves the current model (included all updates).
106  //
107  // All input arguments are ensured (by solver.cc) to be valid. Furthermore,
108  // since all parameters are references or functions (which could be a lambda
109  // expression), the implementation should not keep a reference or copy of
110  // them, as they may become invalid reference after the invocation if this
111  // function.
112  //
113  // Parameters `message_cb`, `cb` and `interrupter` are optional. They are
114  // nullptr when not set.
115  //
116  // When parameter `message_cb` is not null and the underlying solver does not
117  // supports message callbacks, it must return an InvalidArgumentError with the
118  // message internal::kMessageCallbackNotSupported.
119  //
120  // Solvers should return a InvalidArgumentError when called with events on
121  // callback_registration that are not supported by the solver for the type of
122  // model being solved (for example MIP events if the model is an LP, or events
123  // that are not emitted by the solver). Solvers should use
124  // CheckRegisteredCallbackEvents() to implement that.
125  virtual absl::StatusOr<SolveResultProto> Solve(
126  const SolveParametersProto& parameters,
127  const ModelSolveParametersProto& model_parameters,
128  MessageCallback message_cb,
129  const CallbackRegistrationProto& callback_registration, Callback cb,
130  SolveInterrupter* interrupter) = 0;
131 
132  // Updates the model to solve and returns true, or returns false if this
133  // update is not supported.
134  //
135  // The implementation should assume the input ModelUpdate is valid and is free
136  // to assert if this is not the case.
137  virtual absl::StatusOr<bool> Update(const ModelUpdateProto& model_update) = 0;
138 };
139 
141  public:
144 
145  static AllSolversRegistry* Instance();
146 
147  // Maps the given factory to the given solver type. Calling this twice will
148  // result in an error, using static initialization is recommended, e.g. see
149  // MATH_OPT_REGISTER_SOLVER defined below.
150  //
151  // Required: factory must be threadsafe.
152  void Register(SolverTypeProto solver_type, SolverInterface::Factory factory);
153 
154  // Invokes the factory associated to the solver type with the provided
155  // arguments.
156  absl::StatusOr<std::unique_ptr<SolverInterface>> Create(
157  SolverTypeProto solver_type, const ModelProto& model,
158  const SolverInterface::InitArgs& init_args) const;
159 
160  // Whether a solver type is supported.
161  bool IsRegistered(SolverTypeProto solver_type) const;
162 
163  // List all supported solver types.
164  std::vector<SolverTypeProto> RegisteredSolvers() const;
165 
166  // Returns a human-readable list of supported solver types.
167  std::string RegisteredSolversToString() const;
168 
169  private:
170  AllSolversRegistry() = default;
171 
172  mutable absl::Mutex mutex_;
173  absl::flat_hash_map<SolverTypeProto, SolverInterface::Factory>
174  registered_solvers_;
175 };
176 
177 // Use to ensure that a solver is registered exactly one time. Invoke in each cc
178 // file implementing a SolverInterface. Example use:
179 //
180 // MATH_OPT_REGISTER_SOLVER(SOLVER_TYPE_GSCIP, GScipSolver::New)
181 //
182 // Can only be used once per cc file.
183 //
184 // Arguments:
185 // solver_type: A SolverTypeProto proto enum.
186 // solver_factory: A SolverInterface::Factory for solver_type.
187 #define MATH_OPT_REGISTER_SOLVER(solver_type, solver_factory) \
188  namespace { \
189  const void* const kRegisterSolver ABSL_ATTRIBUTE_UNUSED = [] { \
190  AllSolversRegistry::Instance()->Register(solver_type, solver_factory); \
191  return nullptr; \
192  }(); \
193  } // namespace
194 
195 } // namespace math_opt
196 } // namespace operations_research
197 
198 #endif // OR_TOOLS_MATH_OPT_CORE_SOLVER_INTERFACE_H_
void Register(SolverTypeProto solver_type, SolverInterface::Factory factory)
absl::StatusOr< std::unique_ptr< SolverInterface > > Create(SolverTypeProto solver_type, const ModelProto &model, const SolverInterface::InitArgs &init_args) const
AllSolversRegistry(const AllSolversRegistry &)=delete
bool IsRegistered(SolverTypeProto solver_type) const
std::vector< SolverTypeProto > RegisteredSolvers() const
AllSolversRegistry & operator=(const AllSolversRegistry &)=delete
SolverInterface & operator=(const SolverInterface &)=delete
virtual absl::StatusOr< SolveResultProto > Solve(const SolveParametersProto &parameters, const ModelSolveParametersProto &model_parameters, MessageCallback message_cb, const CallbackRegistrationProto &callback_registration, Callback cb, SolveInterrupter *interrupter)=0
std::function< void(const std::vector< std::string > &)> MessageCallback
std::function< absl::StatusOr< std::unique_ptr< SolverInterface > >(const ModelProto &model, const InitArgs &init_args)> Factory
std::function< absl::StatusOr< CallbackResultProto >(const CallbackDataProto &)> Callback
virtual absl::StatusOr< bool > Update(const ModelUpdateProto &model_update)=0
SolverInterface(const SolverInterface &)=delete
SatParameters parameters
GRBmodel * model
constexpr absl::string_view kMessageCallbackNotSupported
Collection of objects used to extend the Constraint Solver library.
const NonStreamableSolverInitArguments * non_streamable