57#ifndef OR_TOOLS_GSCIP_GSCIP_H_
58#define OR_TOOLS_GSCIP_GSCIP_H_
68#include "absl/base/thread_annotations.h"
69#include "absl/container/flat_hash_map.h"
70#include "absl/container/flat_hash_set.h"
71#include "absl/status/status.h"
72#include "absl/status/statusor.h"
73#include "absl/strings/string_view.h"
74#include "absl/synchronization/mutex.h"
75#include "absl/types/span.h"
77#include "ortools/gscip/gscip.pb.h"
82#include "scip/scip_prob.h"
83#include "scip/type_cons.h"
84#include "scip/type_scip.h"
85#include "scip/type_var.h"
89using GScipSolution = absl::flat_hash_map<SCIP_VAR*, double>;
94 GScipOutput gscip_output;
98 std::vector<GScipSolution> solutions;
100 std::vector<double> objective_values;
105 absl::flat_hash_map<SCIP_VAR*, double> primal_ray;
110struct GScipLinearRange {
111 double lower_bound = -std::numeric_limits<double>::infinity();
112 std::vector<SCIP_VAR*> variables;
114 double upper_bound = std::numeric_limits<double>::infinity();
120enum class GScipVarType { kContinuous, kBinary, kInteger, kImpliedInteger };
122struct GScipIndicatorConstraint;
123struct GScipLogicalConstraintData;
125struct GScipQuadraticRange;
127struct GScipVariableOptions;
130struct GScipConstraintOptions;
133using GScipBranchingPriority = absl::flat_hash_map<SCIP_VAR*, int>;
134enum class GScipHintResult;
150 Interrupter() =
default;
151 Interrupter(
const Interrupter&) =
delete;
152 Interrupter& operator=(
const Interrupter&) =
delete;
160 void Interrupt() { interrupted_ =
true; }
167 bool is_interrupted()
const {
return interrupted_.load(); }
170 std::atomic<bool> interrupted_{
false};
175 static absl::StatusOr<std::unique_ptr<GScip>> Create(
176 const std::string& problem_name);
178 static std::string ScipVersion();
193 absl::StatusOr<GScipResult>
Solve(
194 const GScipParameters& params = GScipParameters(),
195 absl::string_view legacy_params =
"",
196 GScipMessageHandler message_handler =
nullptr,
197 const Interrupter* interrupter =
nullptr);
204 absl::Status SetMaximize(
bool is_maximize);
205 absl::Status SetObjectiveOffset(
double offset);
214 absl::StatusOr<SCIP_VAR*> AddVariable(
215 double lb,
double ub,
double obj_coef, GScipVarType var_type,
216 const std::string& var_name =
"",
226 absl::StatusOr<SCIP_CONS*> AddLinearConstraint(
227 const GScipLinearRange&
range,
const std::string&
name =
"",
234 bool ObjectiveIsMaximize();
235 double ObjectiveOffset();
237 double Lb(SCIP_VAR*
var);
238 double Ub(SCIP_VAR*
var);
239 double ObjCoef(SCIP_VAR*
var);
241 GScipVarType VarType(SCIP_VAR*
var);
242 absl::string_view Name(SCIP_VAR*
var);
243 const absl::flat_hash_set<SCIP_VAR*>& variables() {
return variables_; }
246 absl::string_view Name(SCIP_CONS* constraint);
247 bool IsConstraintLinear(SCIP_CONS* constraint);
248 const absl::flat_hash_set<SCIP_CONS*>& constraints() {
return constraints_; }
251 absl::Span<const double> LinearConstraintCoefficients(SCIP_CONS* constraint);
252 absl::Span<SCIP_VAR* const> LinearConstraintVariables(SCIP_CONS* constraint);
253 double LinearConstraintLb(SCIP_CONS* constraint);
254 double LinearConstraintUb(SCIP_CONS* constraint);
262 absl::Status SetLb(SCIP_VAR*
var,
double lb);
266 absl::Status SetUb(SCIP_VAR*
var,
double ub);
267 absl::Status SetObjCoef(SCIP_VAR*
var,
double obj_coef);
268 absl::Status SetVarType(SCIP_VAR*
var, GScipVarType var_type);
274 absl::Status DeleteVariable(SCIP_VAR*
var);
280 absl::Status CanSafeBulkDelete(
const absl::flat_hash_set<SCIP_VAR*>& vars);
288 absl::Status SafeBulkDelete(
const absl::flat_hash_set<SCIP_VAR*>& vars);
291 absl::Status SetLinearConstraintLb(SCIP_CONS* constraint,
double lb);
292 absl::Status SetLinearConstraintUb(SCIP_CONS* constraint,
double ub);
293 absl::Status SetLinearConstraintCoef(SCIP_CONS* constraint, SCIP_VAR*
var,
295 absl::Status AddLinearConstraintCoef(SCIP_CONS* constraint, SCIP_VAR*
var,
300 absl::Status DeleteConstraint(SCIP_CONS* constraint);
314 absl::StatusOr<SCIP_CONS*> AddIndicatorConstraint(
315 const GScipIndicatorConstraint& indicator_constraint,
316 const std::string&
name =
"",
322 absl::StatusOr<SCIP_CONS*> AddQuadraticConstraint(
323 const GScipQuadraticRange&
range,
const std::string&
name =
"",
330 absl::StatusOr<SCIP_CONS*> AddAndConstraint(
331 const GScipLogicalConstraintData& logical_data,
332 const std::string&
name =
"",
339 absl::StatusOr<SCIP_CONS*> AddOrConstraint(
340 const GScipLogicalConstraintData& logical_data,
341 const std::string&
name =
"",
350 absl::StatusOr<SCIP_CONS*> AddSOS1Constraint(
351 const GScipSOSData& sos_data,
const std::string&
name =
"",
360 absl::StatusOr<SCIP_CONS*> AddSOS2Constraint(
361 const GScipSOSData& sos_data,
const std::string&
name =
"",
369 absl::string_view ConstraintType(SCIP_CONS* constraint);
375 absl::StatusOr<GScipHintResult> SuggestHint(
376 const GScipSolution& partial_solution);
384 absl::Status SetBranchingPriority(SCIP_VAR*
var,
int priority);
392 static constexpr double kDefaultScipInf = 1e20;
395 SCIP* scip() {
return scip_; }
397 absl::StatusOr<bool> DefaultBoolParamValue(
const std::string& parameter_name);
398 absl::StatusOr<int> DefaultIntParamValue(
const std::string& parameter_name);
399 absl::StatusOr<int64_t> DefaultLongParamValue(
400 const std::string& parameter_name);
401 absl::StatusOr<double> DefaultRealParamValue(
402 const std::string& parameter_name);
403 absl::StatusOr<char> DefaultCharParamValue(
const std::string& parameter_name);
404 absl::StatusOr<std::string> DefaultStringParamValue(
405 const std::string& parameter_name);
418 void InterruptSolveFromCallbackOnCallbackError(absl::Status error_status);
422 template <
typename ConsHandler,
typename ConsData>
423 inline absl::StatusOr<SCIP_CONS*> AddConstraintForHandler(
424 ConsHandler* handler, ConsData* data,
const std::string&
name =
"",
430 absl::StatusOr<double> ScipInfClamp(
double d);
435 double ScipInfUnclamp(
double d);
458 class InterruptEventHandler :
public GScipEventHandler {
460 InterruptEventHandler();
462 SCIP_RETCODE Init(GScip* gscip)
override;
463 SCIP_RETCODE Execute(GScipEventHandlerContext)
override;
467 SCIP_RETCODE TryCallInterruptIfNeeded(GScip* gscip);
470 void set_interrupter(
const Interrupter* interrupter);
476 const Interrupter* interrupter_ =
nullptr;
479 explicit GScip(SCIP* scip);
481 absl::Status CleanUp();
483 absl::Status SetParams(
const GScipParameters& params,
484 absl::string_view legacy_params);
485 absl::Status FreeTransform();
488 absl::Status CheckScipFinite(
double d);
490 absl::Status MaybeKeepConstraintAlive(SCIP_CONS* constraint,
491 const GScipConstraintOptions& options);
494 InterruptEventHandler interrupt_event_handler_;
495 absl::flat_hash_set<SCIP_VAR*> variables_;
496 absl::flat_hash_set<SCIP_CONS*> constraints_;
497 absl::Mutex callback_status_mutex_;
498 absl::Status callback_status_ ABSL_GUARDED_BY(callback_status_mutex_);
505struct GScipQuadraticRange {
507 double lower_bound = -std::numeric_limits<double>::infinity();
511 std::vector<SCIP_Var*> linear_variables;
512 std::vector<double> linear_coefficients;
524 std::vector<SCIP_Var*> quadratic_variables1;
525 std::vector<SCIP_Var*> quadratic_variables2;
526 std::vector<double> quadratic_coefficients;
529 double upper_bound = std::numeric_limits<double>::infinity();
545 std::vector<SCIP_VAR*> variables;
554 std::vector<double> weights;
559struct GScipIndicatorConstraint {
561 SCIP_VAR* indicator_variable =
nullptr;
562 bool negate_indicator =
false;
564 std::vector<SCIP_Var*> variables;
568 double upper_bound = std::numeric_limits<double>::infinity();
575struct GScipLogicalConstraintData {
576 SCIP_VAR* resultant =
nullptr;
577 std::vector<SCIP_VAR*> operators;
580enum class GScipHintResult {
591struct GScipVariableOptions {
602 bool removable =
false;
616 bool keep_alive =
true;
620struct GScipConstraintOptions {
631 bool separate =
true;
639 bool propagate =
true;
645 bool modifiable =
false;
648 bool dynamic =
false;
651 bool removable =
false;
655 bool sticking_at_node =
false;
669 bool keep_alive =
true;
676template <
typename ConsHandler,
typename ConsData>
677absl::StatusOr<SCIP_CONS*> GScip::AddConstraintForHandler(
678 ConsHandler* handler, ConsData* data,
const std::string&
name,
679 const GScipConstraintOptions& options) {
680 SCIP_CONS* constraint =
nullptr;
682 scip_, &constraint,
name.data(), handler, data, options.initial,
683 options.separate, options.enforce, options.check, options.propagate,
684 options.local, options.modifiable, options.dynamic, options.removable,
685 options.sticking_at_node));
686 if (constraint ==
nullptr) {
687 return absl::InternalError(
"SCIP failed to create constraint");
#define RETURN_IF_ERROR(expr)
const std::string name
A name for logging purposes.
absl::Span< const double > coefficients
absl::StatusOr< SolveResult > Solve(const Model &model, const SolverType solver_type, const SolveArguments &solve_args, const SolverInitArguments &init_args)
In SWIG mode, we don't want anything besides these top-level includes.
const GScipConstraintOptions & DefaultGScipConstraintOptions()
const GScipVariableOptions & DefaultGScipVariableOptions()
#define RETURN_IF_SCIP_ERROR(x)
const std::optional< Range > & range