Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
gscip.h
Go to the documentation of this file.
1// Copyright 2010-2025 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// Simplified bindings for the SCIP solver. This is not designed to be used
15// directly by users, the API is not friendly to a modeler. For most common
16// cases, use MathOpt instead.
17//
18// Notable differences between gSCIP and SCIP:
19// * Unless callbacks are used, gSCIP only exposes the SCIP stage PROBLEM to
20// the user through public APIs.
21// * Instead of the stateful SCIP parameters API, parameters are passed in at
22// Solve() time and cleared at the end of solve. Parameters that effect
23// problem creation are thus not supported.
24// * gSCIP uses std::numeric_limits<double>::infinity(), rather than SCIPs
25// infinity (a default value of 1e20). Doubles with absolute value >= 1e20
26// but < inf result in an error. Changing the underlying SCIP's infinity is
27// not supported.
28// * absl::Status and absl::StatusOr are used to propagate SCIP errors (and on
29// a best effort basis, also filter out bad input to gSCIP functions). In
30// constraint handlers, we also use absl::Status and absl::StatusOr for
31// error propagation and not SCIP_RETCODE.
32// * Interruption: SCIP interruption (via SCIPinterruptSolve()) is not
33// threadsafe and can only be safely used from a callback (and only in some
34// stages). For GScip, users can optionally provide a GScip::Interrupter as
35// part of the Solve() API. (Behind the scenes we call SCIPinterruptSolve()
36// on the correct thread for the user. Users who know what they are doing
37// can invoke SCIPinterruptSolve() directly, but using a GScip::Interrupter
38// is recommended.
39//
40// A note on error propagation and reliability:
41// Many methods on SCIP return an error code. Errors can be triggered by
42// both invalid input and bugs in SCIP. We propagate these errors back to the
43// user through gSCIP through Status and StatusOr. If you are solving a single
44// MIP and you have previously successfully solved similar MIPs, it is unlikely
45// gSCIP would return any status errors. Depending on your application, CHECK
46// failing on these errors may be appropriate (e.g. a benchmark that is run by
47// hand). If you are solving a very large number of MIPs (e.g. in a flume job),
48// your instances are numerically challenging, or the model/data are drawn from
49// an unreliable source, or you are running a server that cannot crash, you may
50// want to try and process these errors instead. Note that on bad instances,
51// SCIP may still crash, so highly reliable systems should run SCIP in a
52// separate process.
53//
54// NOTE(user): much of the API uses const std::string& instead of
55// absl::string_view because the underlying SCIP API needs a null terminated
56// char*.
57#ifndef ORTOOLS_MATH_OPT_SOLVERS_GSCIP_GSCIP_H_
58#define ORTOOLS_MATH_OPT_SOLVERS_GSCIP_GSCIP_H_
59
60#include <atomic>
61#include <cstdint>
62#include <functional>
63#include <limits>
64#include <memory>
65#include <string>
66#include <vector>
67
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"
80#include "ortools/math_opt/solvers/gscip/gscip_message_handler.h" // IWYU pragma: export
81#include "scip/scip.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"
86
87namespace operations_research {
88
89using GScipSolution = absl::flat_hash_map<SCIP_VAR*, double>;
90
91// The result of GScip::Solve(). Contains the solve status, statistics, and the
92// solutions found.
95 // The number of solutions returned is at most GScipParameters::num_solutions.
96 // They are ordered from best objective value to worst. When
97 // gscip_output.status() is optimal, solutions will have at least one element.
98 std::vector<GScipSolution> solutions;
99 // Of the same size as solutions.
100 std::vector<double> objective_values;
101 // Advanced use below
102
103 // If the problem was unbounded, a primal ray in the unbounded direction of
104 // the LP relaxation should be produced.
105 absl::flat_hash_map<SCIP_VAR*, double> primal_ray;
106};
107
108// Models the constraint lb <= a*x <= ub. Members variables and coefficients
109// must have the same size.
111 double lower_bound = -std::numeric_limits<double>::infinity();
112 std::vector<SCIP_VAR*> variables;
113 std::vector<double> coefficients;
114 double upper_bound = std::numeric_limits<double>::infinity();
115};
116
117// A variable is implied integer if the integrality constraint is not required
118// for the model to be valid, but the variable takes an integer value in any
119// optimal solution to the problem.
121
122struct GScipIndicatorConstraint;
123struct GScipLogicalConstraintData;
124// Some advanced features, defined at the end of the header file.
125struct GScipQuadraticRange;
126struct GScipSOSData;
127struct GScipVariableOptions;
128
129const GScipVariableOptions& DefaultGScipVariableOptions();
130struct GScipConstraintOptions;
131
132const GScipConstraintOptions& DefaultGScipConstraintOptions();
133using GScipBranchingPriority = absl::flat_hash_map<SCIP_VAR*, int>;
134enum class GScipHintResult;
135
136// A thin wrapper around the SCIP solver that provides C++ bindings that are
137// idiomatic for Google. Unless callbacks are used, the SCIP stage is always
138// PROBLEM. If any GScip function returns an absl::Status error, then the GScip
139// object should be considered to be in an error state.
140class GScip {
141 public:
142 // Used to notify GScip that a call to Solve() should terminate early.
143 //
144 // Begins in the uninterrupted state, and irreversibly moves to the
145 // interrupted state after a call to `interrupt()`.
146 //
147 // This class is threadsafe.
149 public:
150 Interrupter() = default;
151 Interrupter(const Interrupter&) = delete;
153
154 // Triggers the interrupter. Informs calls to GScip::Solve() which took
155 // this Interrupter as an argument to stop as soon as possible. Note that
156 // this function does not block and GScip::Solve() does not stop
157 // immediately. Calling this function more than once has no further effect.
158 //
159 // This function is threadsafe and nonblocking.
160 void Interrupt() { interrupted_ = true; }
161
162 // Returns true if we are in the interrupted state (i.e. `interrupt() was
163 // called).
164 //
165 // This function is threadsafe, non-blocking, and fast (time to read an
166 // atomic).
167 bool is_interrupted() const { return interrupted_.load(); }
168
169 private:
170 std::atomic<bool> interrupted_{false};
171 };
172
173 // Create a new GScip (the constructor is private). The default objective
174 // direction is minimization.
175 static absl::StatusOr<std::unique_ptr<GScip>> Create(
176 const std::string& problem_name);
177 ~GScip();
178 static std::string ScipVersion();
179
180 // After Solve() the parameters are reset and SCIP stage is restored to
181 // PROBLEM.
182 //
183 // The returned StatusOr will contain an error only if an:
184 // * An underlying function from SCIP fails.
185 // * There is an I/O error with managing SCIP output.
186 // * A user-defined callback function fails.
187 // The above cases are not mutually exclusive. If the problem is infeasible,
188 // this will be reflected in the value of GScipResult::gscip_output::status.
189 //
190 // No reference is held to message_handler or interrupter after Solve()
191 // returns.
192 absl::StatusOr<GScipResult> Solve(
193 const GScipParameters& params = GScipParameters(),
194 GScipMessageHandler message_handler = nullptr,
195 const Interrupter* interrupter = nullptr);
196
197 // ///////////////////////////////////////////////////////////////////////////
198 // Basic Model Construction
199 // ///////////////////////////////////////////////////////////////////////////
200
201 // Use true for maximization, false for minimization.
202 absl::Status SetMaximize(bool is_maximize);
203 absl::Status SetObjectiveOffset(double offset);
204
205 // The returned SCIP_VAR is owned by GScip. With default options, the
206 // returned variable will have the same lifetime as GScip (if instead,
207 // GScipVariableOptions::keep_alive is false, SCIP may free the variable at
208 // any time, see GScipVariableOptions::keep_alive for details).
209 //
210 // Note that SCIP will internally convert a variable of type `kInteger` with
211 // bounds of [0, 1] to a variable of type `kBinary`.
212 absl::StatusOr<SCIP_VAR*> AddVariable(
213 double lb, double ub, double obj_coef, GScipVarType var_type,
214 const std::string& var_name = "",
215 const GScipVariableOptions& options = DefaultGScipVariableOptions());
216
217 // The returned SCIP_CONS is owned by GScip. With default options, the
218 // returned variable will have the same lifetime as GScip (if instead,
219 // GScipConstraintOptions::keep_alive is false, SCIP may free the constraint
220 // at any time, see GScipConstraintOptions::keep_alive for details).
221 //
222 // Can be called while creating the model or in a callback (e.g. in a
223 // GScipConstraintHandler).
224 absl::StatusOr<SCIP_CONS*> AddLinearConstraint(
225 const GScipLinearRange& range, const std::string& name = "",
226 const GScipConstraintOptions& options = DefaultGScipConstraintOptions());
227
228 // ///////////////////////////////////////////////////////////////////////////
229 // Model Queries
230 // ///////////////////////////////////////////////////////////////////////////
231
232 bool ObjectiveIsMaximize();
233 double ObjectiveOffset();
234
235 double Lb(SCIP_VAR* var);
236 double Ub(SCIP_VAR* var);
237 double ObjCoef(SCIP_VAR* var);
238 // NOTE: The returned type may differ from the type passed to `AddVariable()`.
239 GScipVarType VarType(SCIP_VAR* var);
240 absl::string_view Name(SCIP_VAR* var);
241 const absl::flat_hash_set<SCIP_VAR*>& variables() { return variables_; }
242
243 // These methods works on all constraint types.
244 absl::string_view Name(SCIP_CONS* constraint);
245 bool IsConstraintLinear(SCIP_CONS* constraint);
246 const absl::flat_hash_set<SCIP_CONS*>& constraints() { return constraints_; }
247
248 // These methods will CHECK fail if constraint is not a linear constraint.
249 absl::Span<const double> LinearConstraintCoefficients(SCIP_CONS* constraint);
250 absl::Span<SCIP_VAR* const> LinearConstraintVariables(SCIP_CONS* constraint);
251 double LinearConstraintLb(SCIP_CONS* constraint);
252 double LinearConstraintUb(SCIP_CONS* constraint);
253
254 // ///////////////////////////////////////////////////////////////////////////
255 // Model Updates (needed for incrementalism)
256 // ///////////////////////////////////////////////////////////////////////////
257 // TODO(b/246342145): A crash may occur if you attempt to set a lb <= -1.0 on
258 // a binary variable. SCIP can also silently change the vartype of a variable
259 // after construction, so you should check it via `VarType()`.
260 absl::Status SetLb(SCIP_VAR* var, double lb);
261 // TODO(b/246342145): A crash may occur if you attempt to set an ub >= 2.0 on
262 // a binary variable. SCIP can also silently change the vartype of a variable
263 // after construction, so you should check it via `VarType()`.
264 absl::Status SetUb(SCIP_VAR* var, double ub);
265 absl::Status SetObjCoef(SCIP_VAR* var, double obj_coef);
266 absl::Status SetVarType(SCIP_VAR* var, GScipVarType var_type);
267
268 // Warning: you need to ensure that no constraint has a reference to this
269 // variable before deleting it, or undefined behavior will occur. For linear
270 // constraints, you can set the coefficient of this variable to zero to remove
271 // the variable from the constraint.
272 absl::Status DeleteVariable(SCIP_VAR* var);
273
274 // Checks if SafeBulkDelete will succeed for vars, and returns a description
275 // the problematic variables/constraints on a failure (the returned status
276 // will not contain a propagated SCIP error). Will not modify the underlying
277 // SCIP, it is safe to continue using this if an error is returned.
278 absl::Status CanSafeBulkDelete(const absl::flat_hash_set<SCIP_VAR*>& vars);
279
280 // Attempts to remove vars from all constraints and then remove vars from
281 // the model. As of August 7, 2020, will fail if the model contains any
282 // constraints that are not linear.
283 //
284 // Will call CanSafeBulkDelete above, but can also return an error Status
285 // propagated from SCIP. Do not assume SCIP is in a valid state if this fails.
286 absl::Status SafeBulkDelete(const absl::flat_hash_set<SCIP_VAR*>& vars);
287
288 // These methods will CHECK fail if constraint is not a linear constraint.
289 absl::Status SetLinearConstraintLb(SCIP_CONS* constraint, double lb);
290 absl::Status SetLinearConstraintUb(SCIP_CONS* constraint, double ub);
291 absl::Status SetLinearConstraintCoef(SCIP_CONS* constraint, SCIP_VAR* var,
292 double value);
293 absl::Status AddLinearConstraintCoef(SCIP_CONS* constraint, SCIP_VAR* var,
294 double value);
295
296 // Works on all constraint types. Unlike DeleteVariable, no special action is
297 // required before deleting a constraint.
298 absl::Status DeleteConstraint(SCIP_CONS* constraint);
299
300 // ///////////////////////////////////////////////////////////////////////////
301 // Nonlinear constraint types.
302 // For now, only basic support (adding to the model) is provided. Reading and
303 // updating support may be added in the future.
304 // ///////////////////////////////////////////////////////////////////////////
305
306 // Adds a constraint of the form:
307 // if z then a * x <= b
308 // where z is a binary variable, x is a vector of decision variables, a is
309 // vector of constants, and b is a constant. z can be negated.
310 //
311 // NOTE(user): options.modifiable is ignored.
312 absl::StatusOr<SCIP_CONS*> AddIndicatorConstraint(
313 const GScipIndicatorConstraint& indicator_constraint,
314 const std::string& name = "",
316
317 // Adds a constraint of form lb <= x * Q * x + a * x <= ub.
318 //
319 // NOTE(user): options.modifiable and options.sticking_at_node are ignored.
320 absl::StatusOr<SCIP_CONS*> AddQuadraticConstraint(
321 const GScipQuadraticRange& range, const std::string& name = "",
323
324 // Adds the constraint:
325 // logical_data.resultant = AND_i logical_data.operators[i],
326 // where logical_data.resultant and logical_data.operators[i] are all binary
327 // variables.
328 absl::StatusOr<SCIP_CONS*> AddAndConstraint(
329 const GScipLogicalConstraintData& logical_data,
330 const std::string& name = "",
332
333 // Adds the constraint:
334 // logical_data.resultant = OR_i logical_data.operators[i],
335 // where logical_data.resultant and logical_data.operators[i] must be binary
336 // variables.
337 absl::StatusOr<SCIP_CONS*> AddOrConstraint(
338 const GScipLogicalConstraintData& logical_data,
339 const std::string& name = "",
341
342 // Adds the constraint that at most one of the variables in sos_data can be
343 // nonzero. The variables can be integer or continuous. See GScipSOSData for
344 // details.
345 //
346 // NOTE(user): options.modifiable is ignored (these constraints are not
347 // modifiable).
348 absl::StatusOr<SCIP_CONS*> AddSOS1Constraint(
349 const GScipSOSData& sos_data, const std::string& name = "",
351
352 // Adds the constraint that at most two of the variables in sos_data can be
353 // nonzero, and they must be adjacent under the ordering for sos_data. See
354 // GScipSOSData for details.
355 //
356 // NOTE(user): options.modifiable is ignored (these constraints are not
357 // modifiable).
358 absl::StatusOr<SCIP_CONS*> AddSOS2Constraint(
359 const GScipSOSData& sos_data, const std::string& name = "",
361
362 // ///////////////////////////////////////////////////////////////////////////
363 // Advanced use
364 // ///////////////////////////////////////////////////////////////////////////
365
366 // Returns the name of the constraint handler for this constraint.
367 absl::string_view ConstraintType(SCIP_CONS* constraint);
368
369 // The proposed solution can be partial (only specify some of the variables)
370 // or complete. Complete solutions will be checked for feasibility and
371 // objective quality, and might be unused for these reasons. Partial solutions
372 // will always be accepted.
373 absl::StatusOr<GScipHintResult> SuggestHint(
374 const GScipSolution& partial_solution);
375
376 // All variables have a default branching priority of zero. Variables are
377 // partitioned by their branching priority, and a fractional variable from the
378 // highest partition will always be branched on.
379 //
380 // TODO(user): Add support for BranchingFactor as well, this is typically
381 // more useful.
382 absl::Status SetBranchingPriority(SCIP_VAR* var, int priority);
383
384 // Doubles with absolute value of at least this value are invalid and result
385 // in errors. Floating point actual infinities are replaced by this value in
386 // SCIP calls. SCIP considers values at least this large to be infinite. When
387 // querying gSCIP, if an absolute value exceeds ScipInf, it is replaced by
388 // std::numeric_limits<double>::infinity().
389 double ScipInf();
390 static constexpr double kDefaultScipInf = 1e20;
391
392 // These should typically not be needed.
393 SCIP* scip() { return scip_; }
394
395 absl::StatusOr<bool> DefaultBoolParamValue(const std::string& parameter_name);
396 absl::StatusOr<int> DefaultIntParamValue(const std::string& parameter_name);
397 absl::StatusOr<int64_t> DefaultLongParamValue(
398 const std::string& parameter_name);
399 absl::StatusOr<double> DefaultRealParamValue(
400 const std::string& parameter_name);
401 absl::StatusOr<char> DefaultCharParamValue(const std::string& parameter_name);
402 absl::StatusOr<std::string> DefaultStringParamValue(
403 const std::string& parameter_name);
404
405 // Returns true if GScip is in an error state. Currently only checks if a
406 // callback has failed, but in the future it may check for other failures.
407 bool InErrorState();
408
409 // Internal use. Used by constraint handlers to propagate user-returned Status
410 // errors to GSCIP. Interrupts a solve and passes an error status that
411 // GScip::Solve() must return after SCIP finishes interrupting the solve. Does
412 // not do anything if previously called with a (non-OK) status (i.e. the first
413 // status error is returned by SCIP).
414 //
415 // CHECK fails if status is OK.
416 void InterruptSolveFromCallbackOnCallbackError(absl::Status error_status);
417
418 // Internal use only. Users should instead call
419 // GScipConstraintHandler::AddCallbackConstraint().
420 template <typename ConsHandler, typename ConsData>
421 inline absl::StatusOr<SCIP_CONS*> AddConstraintForHandler(
422 ConsHandler* handler, ConsData* data, const std::string& name = "",
424
425 // Internal use only.
426 //
427 // Replaces +/- inf by +/- ScipInf(), fails when |d| is in [ScipInf(), inf).
428 absl::StatusOr<double> ScipInfClamp(double d);
429
430 // Internal use only.
431 //
432 // Returns +/- inf if |d| >= ScipInf(), otherwise returns d.
433 double ScipInfUnclamp(double d);
434
435 private:
436 // Event handler that it used to call SCIPinterruptSolve() is a safe manner.
437 //
438 // At the start of SCIPsolve(), SCIP resets `SCIP_Stat::userinterrupt` to
439 // false. It does the same in SCIPpresolve(), which is called at the beginning
440 // of SCIPsolve() but also at the beginning of each restart. The
441 // `userinterrupt` can also be reset when the transformed problem is freed
442 // when the parameter "misc/resetstat" is used. On top of that, it is not
443 // possible to call SCIPinterruptSolve() in SCIP_STAGE_INITSOLVE stage; which
444 // occurs in the middle of the solve and at restarts.
445 //
446 // If this was no enough, SCIPinterruptSolve() calls SCIPcheckStage() which is
447 // not thread-safe.
448 //
449 // As a consequence, there is no safe way to call SCIPinterruptSolve() from
450 // another thread. Here we take a safer approach: we call it only from the
451 // Exec() of an event handler. This solves all thread safety issues and, if we
452 // have been careful, also ensures we don't call it in the wrong stage. This
453 // also solves the issue the multiple resets of the `userinterrupt` flag since
454 // each time we are called after the interrupter has been triggered, we simply
455 // call SCIPinterruptSolve() until SCIP finally listens.
456 class InterruptEventHandler : public GScipEventHandler {
457 public:
458 InterruptEventHandler();
459
460 SCIP_RETCODE Init(GScip* gscip) override;
461 SCIP_RETCODE Execute(GScipEventHandlerContext) override;
462
463 // Calls SCIPinterruptSolve() if the interrupter is set and triggered and
464 // SCIP is in a valid stage for that.
465 SCIP_RETCODE TryCallInterruptIfNeeded(GScip* gscip);
466
467 // Sets the interrupter, or clears it when `interrupter == nullptr`.
468 void set_interrupter(const Interrupter* interrupter);
469
470 private:
471 // This is set at the start of each call to GScip::Solve() and cleared
472 // before the function returns. It may be null when the user does not
473 // provide an interrupter; in that case we don't register any event.
474 const Interrupter* interrupter_ = nullptr;
475 };
476
477 explicit GScip(SCIP* scip);
478 // Releases SCIP memory.
479 absl::Status CleanUp();
480
481 absl::Status SetParams(const GScipParameters& params);
482 absl::Status FreeTransform();
483
484 // Returns an error if |d| >= ScipInf().
485 absl::Status CheckScipFinite(double d);
486
487 absl::Status MaybeKeepConstraintAlive(SCIP_CONS* constraint,
488 const GScipConstraintOptions& options);
489
490 SCIP* scip_;
491 InterruptEventHandler interrupt_event_handler_;
492 absl::flat_hash_set<SCIP_VAR*> variables_;
493 absl::flat_hash_set<SCIP_CONS*> constraints_;
494 absl::Mutex callback_status_mutex_;
495 absl::Status callback_status_ ABSL_GUARDED_BY(callback_status_mutex_);
496};
497
498// Advanced features below
499
500// Models the constraint
501// lb <= x * Q * x + a * x <= ub
502struct GScipQuadraticRange {
503 // Models lb above.
504 double lower_bound = -std::numeric_limits<double>::infinity();
505
506 // Models a * x above. linear_variables and linear_coefficients must have the
507 // same size.
508 std::vector<SCIP_Var*> linear_variables;
509 std::vector<double> linear_coefficients;
510
511 // These three vectors must have the same size. Models x * Q * x as
512 // sum_i quadratic_coefficients[i] * quadratic_variables1[i]
513 // * quadratic_variables2[i]
514 //
515 // Duplicate quadratic terms (e.g. i=3 encodes 4*x1*x3 and i=4 encodes
516 // 8*x3*x1) are added (as if you added a single entry 12*x1*x3).
517 //
518 // TODO(user): investigate, the documentation seems to suggest that when
519 // linear_variables[i] == quadratic_variables1[i] == quadratic_variables2[i]
520 // there is some advantage.
521 std::vector<SCIP_Var*> quadratic_variables1;
522 std::vector<SCIP_Var*> quadratic_variables2;
523 std::vector<double> quadratic_coefficients;
524
525 // Models ub above.
526 double upper_bound = std::numeric_limits<double>::infinity();
527};
528
529// Models special ordered set constraints (SOS1 and SOS2 constraints). Each
530// contains a list of variables that are implicitly ordered by the provided
531// weights, which must be distinct.
532// SOS1: At most one of the variables can be nonzero.
533// SOS2: At most two of the variables can be nonzero, and they must be
534// consecutive.
535//
536// The weights are optional, and if not provided, the ordering in "variables" is
537// used.
538struct GScipSOSData {
539 // The list of variables where all but one or two must be zero. Can be integer
540 // or continuous variables, typically their domain will contain zero. Cannot
541 // be empty in a valid SOS constraint.
542 std::vector<SCIP_VAR*> variables;
543
544 // Optional, can be empty. Otherwise, must have size equal to variables, and
545 // values must be distinct. Determines an "ordering" over the variables
546 // (smallest weight to largest). Additionally, the numeric values of
547 // the weights are used to make branching decisions in a solver specific way,
548 // for details, see:
549 // * https://scip.zib.de/doc/html/cons__sos1_8c.php
550 // * https://scip.zib.de/doc/html/cons__sos2_8c.php.
551 std::vector<double> weights;
553
554// Models the constraint z = 1 => a * x <= b
555// If negate_indicator, then instead: z = 0 => a * x <= b
557 // The z variable above. The vartype must be kBinary.
558 SCIP_VAR* indicator_variable = nullptr;
559 bool negate_indicator = false;
560 // The x variable above.
561 std::vector<SCIP_Var*> variables;
562 // a above. Must have the same size as x.
563 std::vector<double> coefficients;
564 // b above.
565 double upper_bound = std::numeric_limits<double>::infinity();
567
568// Data for constraint of the form resultant = f(operators), e.g.:
569// resultant = AND_i operators[i]
570// For existing constraints (e.g. AND, OR) resultant and operators[i] should all
571// be binary variables, this my change. See use in GScip for details.
573 SCIP_VAR* resultant = nullptr;
574 std::vector<SCIP_VAR*> operators;
576
577enum class GScipHintResult {
578 // Hint was not feasible.
580 // Hint was not good enough to keep.
581 kRejected,
582 // Hint was kept. Partial solutions are not checked for feasibility, they
583 // are always accepted.
585};
586
587// Advanced use. Options to use when creating a variable.
589 // ///////////////////////////////////////////////////////////////////////////
590 // SCIP options. Descriptions are from the SCIP documentation, e.g.
591 // SCIPcreateVar:
592 // https://scip.zib.de/doc/html/group__PublicVariableMethods.php#ga7a37fe4dc702dadecc4186b9624e93fc
593 // ///////////////////////////////////////////////////////////////////////////
595 // Should var's column be present in the initial root LP?
596 bool initial = true;
597
598 // Is var's column removable from the LP (due to aging or cleanup)?
599 bool removable = false;
600
601 // ///////////////////////////////////////////////////////////////////////////
602 // gSCIP options.
603 // ///////////////////////////////////////////////////////////////////////////
604
605 // If keep_alive=true, the returned variable will not to be freed until after
606 // ~GScip() is called. Otherwise, the returned variable could be freed
607 // internally by SCIP at any point, and it is not safe to hold a reference to
608 // the returned variable.
609 //
610 // The primary reason to set keep_alive=false is if you are adding many
611 // variables in a callback (in branch and price), and you expect that most of
612 // them will be deleted.
613 bool keep_alive = true;
614};
615
616// Advanced use. Options to use when creating a constraint.
618 // ///////////////////////////////////////////////////////////////////////////
619 // SCIP options. Descriptions are from the SCIP documentation, e.g.
620 // SCIPcreateConsLinear:
621 // https://scip.zib.de/doc/html/group__CONSHDLRS.php#gaea3b4db21fe214be5db047e08b46b50e
622 // ///////////////////////////////////////////////////////////////////////////
623
624 // Should the LP relaxation of constraint be in the initial LP? False for lazy
625 // constraints (true in callbacks).
626 bool initial = true;
627 // Should the constraint be separated during LP processing?
628 bool separate = true;
629 // Should the constraint be enforced during node processing? True for model
630 // constraints, false for redundant constraints.
631 bool enforce = true;
632 // Should the constraint be checked for feasibility? True for model
633 // constraints, false for redundant constraints.
634 bool check = true;
635 // Should the constraint be propagated during node processing?
636 bool propagate = true;
637 // Is constraint only valid locally? Must be true for branching constraints.
638 bool local = false;
639 // Is constraint modifiable (subject to column generation)? In column
640 // generation applications, set to true if pricing adds coefficients to this
641 // constraint.
642 bool modifiable = false;
643 // Is constraint subject to aging? Set to true for own cuts which are
644 // separated as constraints
645 bool dynamic = false;
646 // Should the relaxation be removed from the LP due to aging or cleanup? Set
647 // to true for 'lazy constraints' and 'user cuts'.
648 bool removable = false;
649 // Should the constraint always be kept at the node where it was added, even
650 // if it may be moved to a more global node? Usually set to false. Set to true
651 // for constraints that represent node data.
652 bool sticking_at_node = false;
653
654 // ///////////////////////////////////////////////////////////////////////////
655 // gSCIP options.
656 // ///////////////////////////////////////////////////////////////////////////
657
658 // If keep_alive=true, the returned constraint will not to be freed until
659 // after ~GScip() is called. Otherwise, the returned constraint could be freed
660 // internally by SCIP at any point, and it is not safe to hold a reference to
661 // the returned constraint.
662 //
663 // The primary reason to set keep_alive=false is if you are adding many
664 // constraints in a callback, and you expect that most of them will be
665 // deleted.
666 bool keep_alive = true;
667};
670// Template function implementations
672
673template <typename ConsHandler, typename ConsData>
674absl::StatusOr<SCIP_CONS*> GScip::AddConstraintForHandler(
675 ConsHandler* handler, ConsData* data, const std::string& name,
676 const GScipConstraintOptions& options) {
677 SCIP_CONS* constraint = nullptr;
678 RETURN_IF_SCIP_ERROR(SCIPcreateCons(
679 scip_, &constraint, name.data(), handler, data, options.initial,
680 options.separate, options.enforce, options.check, options.propagate,
681 options.local, options.modifiable, options.dynamic, options.removable,
682 options.sticking_at_node));
683 if (constraint == nullptr) {
684 return absl::InternalError("SCIP failed to create constraint");
685 }
686 RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint));
687 RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options));
688 return constraint;
689}
690
691} // namespace operations_research
692
693#endif // ORTOOLS_MATH_OPT_SOLVERS_GSCIP_GSCIP_H_
#define RETURN_IF_ERROR(expr)
Interrupter(const Interrupter &)=delete
Interrupter & operator=(const Interrupter &)=delete
double Lb(SCIP_VAR *var)
Definition gscip.cc:811
absl::Status DeleteConstraint(SCIP_CONS *constraint)
Definition gscip.cc:871
static constexpr double kDefaultScipInf
Definition gscip.h:400
absl::StatusOr< SCIP_CONS * > AddConstraintForHandler(ConsHandler *handler, ConsData *data, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition gscip.h:694
double LinearConstraintLb(SCIP_CONS *constraint)
Definition gscip.cc:847
double LinearConstraintUb(SCIP_CONS *constraint)
Definition gscip.cc:851
absl::Span< SCIP_VAR *const > LinearConstraintVariables(SCIP_CONS *constraint)
Definition gscip.cc:841
absl::Status SafeBulkDelete(const absl::flat_hash_set< SCIP_VAR * > &vars)
Definition gscip.cc:788
const absl::flat_hash_set< SCIP_CONS * > & constraints()
Definition gscip.h:250
absl::Status SetVarType(SCIP_VAR *var, GScipVarType var_type)
Definition gscip.cc:757
absl::StatusOr< char > DefaultCharParamValue(const std::string &parameter_name)
Definition gscip.cc:1150
double Ub(SCIP_VAR *var)
Definition gscip.cc:815
absl::Status DeleteVariable(SCIP_VAR *var)
Definition gscip.cc:764
absl::StatusOr< SCIP_CONS * > AddQuadraticConstraint(const GScipQuadraticRange &range, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition gscip.cc:500
absl::Status SetObjCoef(SCIP_VAR *var, double obj_coef)
Definition gscip.cc:751
absl::StatusOr< GScipResult > Solve(const GScipParameters &params=GScipParameters(), GScipMessageHandler message_handler=nullptr, const Interrupter *interrupter=nullptr)
Definition gscip.cc:933
bool IsConstraintLinear(SCIP_CONS *constraint)
Definition gscip.cc:831
void InterruptSolveFromCallbackOnCallbackError(absl::Status error_status)
Definition gscip.cc:390
double ScipInfUnclamp(double d)
Definition gscip.cc:1183
absl::StatusOr< double > DefaultRealParamValue(const std::string &parameter_name)
Definition gscip.cc:1142
absl::Status AddLinearConstraintCoef(SCIP_CONS *constraint, SCIP_VAR *var, double value)
Definition gscip.cc:888
absl::StatusOr< SCIP_CONS * > AddAndConstraint(const GScipLogicalConstraintData &logical_data, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition gscip.cc:589
absl::StatusOr< double > ScipInfClamp(double d)
Definition gscip.cc:1166
absl::Status CanSafeBulkDelete(const absl::flat_hash_set< SCIP_VAR * > &vars)
Definition gscip.cc:774
absl::StatusOr< int > DefaultIntParamValue(const std::string &parameter_name)
Definition gscip.cc:1126
double ObjCoef(SCIP_VAR *var)
Definition gscip.cc:819
absl::StatusOr< SCIP_VAR * > AddVariable(double lb, double ub, double obj_coef, GScipVarType var_type, const std::string &var_name="", const GScipVariableOptions &options=DefaultGScipVariableOptions())
Definition gscip.cc:430
absl::StatusOr< SCIP_CONS * > AddSOS2Constraint(const GScipSOSData &sos_data, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition gscip.cc:688
absl::StatusOr< SCIP_CONS * > AddSOS1Constraint(const GScipSOSData &sos_data, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition gscip.cc:661
const absl::flat_hash_set< SCIP_VAR * > & variables()
Definition gscip.h:245
absl::string_view ConstraintType(SCIP_CONS *constraint)
Definition gscip.cc:827
absl::Status SetObjectiveOffset(double offset)
Definition gscip.cc:720
absl::StatusOr< SCIP_CONS * > AddLinearConstraint(const GScipLinearRange &range, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition gscip.cc:466
absl::Span< const double > LinearConstraintCoefficients(SCIP_CONS *constraint)
Definition gscip.cc:835
absl::Status SetLb(SCIP_VAR *var, double lb)
Definition gscip.cc:739
absl::StatusOr< SCIP_CONS * > AddOrConstraint(const GScipLogicalConstraintData &logical_data, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition gscip.cc:614
absl::Status SetBranchingPriority(SCIP_VAR *var, int priority)
Definition gscip.cc:734
absl::string_view Name(SCIP_VAR *var)
Definition gscip.cc:825
absl::StatusOr< SCIP_CONS * > AddIndicatorConstraint(const GScipIndicatorConstraint &indicator_constraint, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition gscip.cc:548
absl::StatusOr< bool > DefaultBoolParamValue(const std::string &parameter_name)
Definition gscip.cc:1118
absl::Status SetLinearConstraintUb(SCIP_CONS *constraint, double ub)
Definition gscip.cc:865
absl::StatusOr< GScipHintResult > SuggestHint(const GScipSolution &partial_solution)
Definition gscip.cc:896
absl::Status SetMaximize(bool is_maximize)
Definition gscip.cc:714
absl::Status SetUb(SCIP_VAR *var, double ub)
Definition gscip.cc:745
absl::Status SetLinearConstraintLb(SCIP_CONS *constraint, double lb)
Definition gscip.cc:859
GScipVarType VarType(SCIP_VAR *var)
Definition gscip.cc:821
absl::StatusOr< std::string > DefaultStringParamValue(const std::string &parameter_name)
Definition gscip.cc:1158
absl::StatusOr< int64_t > DefaultLongParamValue(const std::string &parameter_name)
Definition gscip.cc:1134
static absl::StatusOr< std::unique_ptr< GScip > > Create(const std::string &problem_name)
Definition gscip.cc:362
absl::Status SetLinearConstraintCoef(SCIP_CONS *constraint, SCIP_VAR *var, double value)
Definition gscip.cc:878
static std::string ScipVersion()
Definition gscip.cc:384
OR-Tools root namespace.
const GScipConstraintOptions & DefaultGScipConstraintOptions()
Definition gscip.cc:299
absl::flat_hash_map< SCIP_VAR *, int > GScipBranchingPriority
Definition gscip.h:133
absl::flat_hash_map< SCIP_VAR *, double > GScipSolution
Definition gscip.h:89
std::function< void(GScipMessageType type, absl::string_view message)> GScipMessageHandler
const GScipVariableOptions & DefaultGScipVariableOptions()
Definition gscip.cc:294
#define RETURN_IF_SCIP_ERROR(x)
std::vector< SCIP_VAR * > variables
Definition gscip.h:112
std::vector< double > coefficients
Definition gscip.h:113
std::vector< SCIP_VAR * > operators
Definition gscip.h:584
std::vector< double > linear_coefficients
Definition gscip.h:519
std::vector< SCIP_Var * > quadratic_variables2
Definition gscip.h:532
*quadratic_variables2[i] std::vector< SCIP_Var * > quadratic_variables1
Definition gscip.h:531
std::vector< SCIP_Var * > linear_variables
Definition gscip.h:518
std::vector< double > quadratic_coefficients
Definition gscip.h:533
std::vector< GScipSolution > solutions
Definition gscip.h:98
absl::flat_hash_map< SCIP_VAR *, double > primal_ray
Definition gscip.h:105
std::vector< double > objective_values
Definition gscip.h:100
std::vector< double > weights
Definition gscip.h:561
std::vector< SCIP_VAR * > variables
Definition gscip.h:552