OR-Tools  9.6
gscip_solver_callback.cc
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 
15 
16 #include <memory>
17 #include <optional>
18 #include <utility>
19 
20 #include "absl/container/flat_hash_set.h"
21 #include "absl/memory/memory.h"
22 #include "absl/status/status.h"
23 #include "absl/status/statusor.h"
24 #include "absl/synchronization/mutex.h"
25 #include "absl/time/time.h"
26 #include "ortools/base/logging.h"
28 #include "ortools/math_opt/callback.pb.h"
31 #include "scip/scip.h"
32 #include "scip/type_scip.h"
33 
34 namespace operations_research {
35 namespace math_opt {
36 
37 std::unique_ptr<GScipSolverCallbackHandler>
39  const CallbackRegistrationProto& callback_registration,
40  const SolverInterface::Callback callback, const absl::Time solve_start,
41  SCIP* const scip) {
42  // TODO(b/180617976): Don't ignore unknown callbacks.
43  return nullptr;
44 }
45 
47  SolverInterface::Callback callback, absl::Time solve_start,
48  SCIP* const scip)
49  : callback_(std::move(ABSL_DIE_IF_NULL(callback))),
50  solve_start_(std::move(solve_start)),
51  scip_(ABSL_DIE_IF_NULL(scip)) {}
52 
54  const absl::MutexLock lock(&callback_mutex_);
55  return status_;
56 }
57 
58 std::optional<CallbackResultProto> GScipSolverCallbackHandler::CallUserCallback(
59  const CallbackDataProto& callback_data) {
60  // We hold the lock during the call of the user callback to ensure only one
61  // call execute at a time. Having multiple calls at once may be an issue when
62  // the user asks for termination since it may ask for it in one call while
63  // another thread is about to make its call for another callback.
64  //
65  // We don't expect any valid actions taken by the user is a callback to lead
66  // to another callback.
67  absl::MutexLock lock(&callback_mutex_);
68  if (!status_.ok()) {
69  return std::nullopt;
70  }
71 
72  absl::StatusOr<CallbackResultProto> result_or = callback_(callback_data);
73  status_ = result_or.status();
74  if (!result_or.ok() || result_or->terminate()) {
75  // TODO(b/182919884): Make sure it is correct to use SCIPinterruptSolve()
76  // here and maybe migrate to the same architecture as the one used to
77  // interrupt the solve from foreign threads..
78  const auto interrupt_status = SCIP_TO_STATUS(SCIPinterruptSolve(scip_));
79  if (!interrupt_status.ok()) {
80  if (status_.ok()) {
81  status_ = interrupt_status;
82  } else {
83  LOG(ERROR) << "Failed to interrupt the solve on error: "
84  << interrupt_status;
85  }
86  }
87  return std::nullopt;
88  }
89 
90  return *std::move(result_or);
91 }
92 
93 } // namespace math_opt
94 } // namespace operations_research
static std::unique_ptr< GScipSolverCallbackHandler > RegisterIfNeeded(const CallbackRegistrationProto &callback_registration, SolverInterface::Callback callback, absl::Time solve_start, SCIP *scip)
GScipSolverCallbackHandler(const GScipSolverCallbackHandler &)=delete
std::function< absl::StatusOr< CallbackResultProto >(const CallbackDataProto &)> Callback
MPCallback * callback
Collection of objects used to extend the Constraint Solver library.
#define SCIP_TO_STATUS(x)