20#include "absl/functional/any_invocable.h"
21#include "absl/log/check.h"
22#include "absl/memory/memory.h"
23#include "absl/status/status.h"
24#include "absl/status/statusor.h"
25#include "absl/synchronization/mutex.h"
43absl::StatusOr<SolveResult> CallSolve(BaseSolver& solver,
45 const SolveArguments& arguments,
46 SolveInterrupter& local_canceller) {
47 RETURN_IF_ERROR(arguments.CheckModelStorageAndCallback(expected_storage));
51 absl::Status cb_status;
52 if (arguments.callback !=
nullptr) {
53 cb = [&](
const CallbackDataProto& callback_data_proto) {
54 const CallbackData data(expected_storage, callback_data_proto);
55 const CallbackResult result = arguments.callback(data);
56 if (
const absl::Status status =
57 result.CheckModelStorage(expected_storage);
61 util::StatusBuilder builder(status);
62 builder <<
"invalid CallbackResult returned by user callback";
65 const absl::MutexLock lock(&mutex);
66 cb_status.Update(builder);
70 local_canceller.Interrupt();
74 CallbackResultProto result_proto;
75 result_proto.set_terminate(
true);
78 return result.Proto();
83 arguments.model_parameters.Proto());
84 const absl::StatusOr<SolveResultProto> solve_result_proto = solver.Solve(
85 {.parameters = arguments.parameters.Proto(),
86 .model_parameters = std::move(model_parameters),
87 .message_callback = arguments.message_callback,
88 .callback_registration = arguments.callback_registration.Proto(),
89 .user_cb = std::move(cb),
90 .interrupter = arguments.interrupter});
96 const absl::MutexLock lock(&mutex);
100 if (!solve_result_proto.ok()) {
101 return solve_result_proto.status();
104 return SolveResult::FromProto(expected_storage, solve_result_proto.value());
107absl::StatusOr<ComputeInfeasibleSubsystemResult> CallComputeInfeasibleSubsystem(
109 const ComputeInfeasibleSubsystemArguments& arguments,
110 SolveInterrupter& local_canceller) {
112 const ComputeInfeasibleSubsystemResultProto compute_result_proto,
113 solver.ComputeInfeasibleSubsystem(
114 {.parameters = arguments.parameters.Proto(),
115 .message_callback = arguments.message_callback,
116 .interrupter = arguments.interrupter}));
119 compute_result_proto);
130 user_canceller, [&]() { local_canceller.
Interrupt(); });
132 const std::unique_ptr<BaseSolver> solver,
135 return CallSolve(*solver, model.
storage(), solve_args, local_canceller);
145 user_canceller, [&]() { local_canceller.
Interrupt(); });
147 const std::unique_ptr<BaseSolver> subprocess_solver,
150 return CallComputeInfeasibleSubsystem(*subprocess_solver, model.
storage(),
151 compute_args, local_canceller);
154absl::StatusOr<std::unique_ptr<IncrementalSolverImpl>>
158 const bool remove_names) {
159 if (model ==
nullptr) {
160 return absl::InvalidArgumentError(
"input model can't be null");
162 auto local_canceller = std::make_shared<SolveInterrupter>();
163 auto user_canceller_cb =
164 std::make_unique<const ScopedSolveInterrupterCallback>(
166 [local_canceller]() { local_canceller->Interrupt(); });
169 update_tracker->ExportModel(remove_names));
171 std::unique_ptr<BaseSolver> solver,
173 local_canceller.get()));
174 return absl::WrapUnique<IncrementalSolverImpl>(
new IncrementalSolverImpl(
175 std::move(solver_factory),
solver_type, remove_names,
176 std::move(local_canceller), std::move(user_canceller_cb),
177 model->
storage(), std::move(update_tracker), std::move(solver)));
180IncrementalSolverImpl::IncrementalSolverImpl(
182 const bool remove_names, std::shared_ptr<SolveInterrupter> local_canceller,
183 std::unique_ptr<const ScopedSolveInterrupterCallback> user_canceller_cb,
185 std::unique_ptr<UpdateTracker> update_tracker,
186 std::unique_ptr<BaseSolver> solver)
187 : solver_factory_(
std::move(solver_factory)),
188 solver_type_(solver_type),
189 remove_names_(remove_names),
190 local_canceller_(
std::move(local_canceller)),
191 user_canceller_cb_(
std::move(user_canceller_cb)),
192 expected_storage_(expected_storage),
193 update_tracker_(
std::move(update_tracker)),
194 solver_(
std::move(solver)) {}
203absl::StatusOr<ComputeInfeasibleSubsystemResult>
214 update_tracker_->ExportModelUpdate(remove_names_));
215 if (!model_update.has_value()) {
220 solver_->Update(*std::move(model_update)),
221 _ <<
"update failed");
229 update_tracker_->ExportModel(remove_names_));
232 solver_factory_(
EnumToProto(solver_type_), std::move(model_proto),
233 local_canceller_.get()),
234 _ <<
"solver re-creation failed");
242 return CallSolve(*solver_, expected_storage_, arguments, *local_canceller_);
245absl::StatusOr<ComputeInfeasibleSubsystemResult>
249 return CallComputeInfeasibleSubsystem(*solver_, expected_storage_, arguments,
#define ASSIGN_OR_RETURN(lhs, rexpr)
#define RETURN_IF_ERROR(expr)
std::function< CallbackResultProto(const CallbackDataProto &)> Callback
Callback function type for MIP/LP callbacks.
absl::StatusOr< SolveResult > SolveWithoutUpdate() const
absl::StatusOr< ComputeInfeasibleSubsystemResult > ComputeInfeasibleSubsystemWithoutUpdate() const
absl::StatusOr< SolveResult > Solve()
absl::StatusOr< ComputeInfeasibleSubsystemResult > ComputeInfeasibleSubsystem()
ModelProto ExportModel(bool remove_names=false) const
std::unique_ptr< UpdateTracker > NewUpdateTracker()
ModelStorageCPtr storage() const
absl::StatusOr< UpdateResult > Update() override
SolverType solver_type() const override
Returns the underlying solver used.
static absl::StatusOr< std::unique_ptr< IncrementalSolverImpl > > New(BaseSolverFactory solver_factory, Model *model, SolverType solver_type, const SolveInterrupter *user_canceller, bool remove_names)
absl::StatusOr< ComputeInfeasibleSubsystemResult > ComputeInfeasibleSubsystemImpl(const BaseSolverFactory solver_factory, const Model &model, const SolverType solver_type, const ComputeInfeasibleSubsystemArguments &compute_args, const SolveInterrupter *const user_canceller, const bool remove_names)
absl::AnyInvocable< absl::StatusOr< std::unique_ptr< BaseSolver > >( SolverTypeProto solver_type, ModelProto model, SolveInterrupter *local_canceller) const > BaseSolverFactory
absl::StatusOr< SolveResult > SolveImpl(const BaseSolverFactory solver_factory, const Model &model, const SolverType solver_type, const SolveArguments &solve_args, const SolveInterrupter *const user_canceller, const bool remove_names)
absl::Nonnull< const ModelStorage * > ModelStorageCPtr
SolverType
The solvers supported by MathOpt.
Enum< E >::Proto EnumToProto(std::optional< E > value)
Arguments passed to ComputeInfeasibleSubsystem() to control the solver.
static absl::StatusOr< ComputeInfeasibleSubsystemResult > FromProto(ModelStorageCPtr model, const ComputeInfeasibleSubsystemResultProto &result_proto)
Result of the Update() on an incremental solver.
#define OR_ASSIGN_OR_RETURN3(lhs, rexpr, error_expression)