OR-Tools  9.3
gscip.cc
Go to the documentation of this file.
1// Copyright 2010-2021 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#include "ortools/gscip/gscip.h"
15
16#include <stdio.h>
17
18#include <algorithm>
19#include <cstdint>
20#include <functional>
21#include <limits>
22#include <memory>
23#include <string>
24#include <utility>
25#include <vector>
26
27#include "absl/container/flat_hash_map.h"
28#include "absl/container/flat_hash_set.h"
29#include "absl/memory/memory.h"
30#include "absl/status/status.h"
31#include "absl/status/statusor.h"
32#include "absl/strings/str_cat.h"
33#include "absl/strings/str_format.h"
34#include "absl/strings/string_view.h"
35#include "absl/types/span.h"
38#include "ortools/gscip/gscip.pb.h"
44#include "scip/cons_linear.h"
45#include "scip/cons_quadratic.h"
46#include "scip/scip.h"
47#include "scip/scip_general.h"
48#include "scip/scip_param.h"
49#include "scip/scip_prob.h"
50#include "scip/scip_solvingstats.h"
51#include "scip/scipdefplugins.h"
52#include "scip/type_cons.h"
53#include "scip/type_scip.h"
54#include "scip/type_var.h"
55
56namespace operations_research {
57
58#define RETURN_ERROR_UNLESS(x) \
59 if (!(x)) \
60 return util::StatusBuilder(absl::InvalidArgumentError(absl::StrFormat( \
61 "Condition violated at %s:%d: %s", __FILE__, __LINE__, #x)))
62
63namespace {
64
65constexpr absl::string_view kLinearConstraintHandlerName = "linear";
66
67SCIP_VARTYPE ConvertVarType(const GScipVarType var_type) {
68 switch (var_type) {
70 return SCIP_VARTYPE_CONTINUOUS;
72 return SCIP_VARTYPE_IMPLINT;
74 return SCIP_VARTYPE_INTEGER;
75 }
76}
77
78GScipVarType ConvertVarType(const SCIP_VARTYPE var_type) {
79 switch (var_type) {
80 case SCIP_VARTYPE_CONTINUOUS:
82 case SCIP_VARTYPE_IMPLINT:
84 case SCIP_VARTYPE_INTEGER:
85 case SCIP_VARTYPE_BINARY:
87 }
88}
89
90GScipOutput::Status ConvertStatus(const SCIP_STATUS scip_status) {
91 switch (scip_status) {
92 case SCIP_STATUS_UNKNOWN:
93 return GScipOutput::UNKNOWN;
94 case SCIP_STATUS_USERINTERRUPT:
95 return GScipOutput::USER_INTERRUPT;
96 case SCIP_STATUS_BESTSOLLIMIT:
97 return GScipOutput::BEST_SOL_LIMIT;
98 case SCIP_STATUS_MEMLIMIT:
99 return GScipOutput::MEM_LIMIT;
100 case SCIP_STATUS_NODELIMIT:
101 return GScipOutput::NODE_LIMIT;
102 case SCIP_STATUS_RESTARTLIMIT:
103 return GScipOutput::RESTART_LIMIT;
104 case SCIP_STATUS_SOLLIMIT:
105 return GScipOutput::SOL_LIMIT;
106 case SCIP_STATUS_STALLNODELIMIT:
107 return GScipOutput::STALL_NODE_LIMIT;
108 case SCIP_STATUS_TIMELIMIT:
109 return GScipOutput::TIME_LIMIT;
110 case SCIP_STATUS_TOTALNODELIMIT:
111 return GScipOutput::TOTAL_NODE_LIMIT;
112 case SCIP_STATUS_OPTIMAL:
113 return GScipOutput::OPTIMAL;
114 case SCIP_STATUS_GAPLIMIT:
115 return GScipOutput::GAP_LIMIT;
116 case SCIP_STATUS_INFEASIBLE:
117 return GScipOutput::INFEASIBLE;
118 case SCIP_STATUS_UNBOUNDED:
119 return GScipOutput::UNBOUNDED;
120 case SCIP_STATUS_INFORUNBD:
121 return GScipOutput::INF_OR_UNBD;
122 case SCIP_STATUS_TERMINATE:
123 return GScipOutput::TERMINATE;
124 default:
125 LOG(FATAL) << "Unrecognized scip status: " << scip_status;
126 }
127}
128
129SCIP_PARAMEMPHASIS ConvertEmphasis(
130 const GScipParameters::Emphasis gscip_emphasis) {
131 switch (gscip_emphasis) {
132 case GScipParameters::DEFAULT_EMPHASIS:
133 return SCIP_PARAMEMPHASIS_DEFAULT;
134 case GScipParameters::CP_SOLVER:
135 return SCIP_PARAMEMPHASIS_CPSOLVER;
136 case GScipParameters::EASY_CIP:
137 return SCIP_PARAMEMPHASIS_EASYCIP;
138 case GScipParameters::FEASIBILITY:
139 return SCIP_PARAMEMPHASIS_FEASIBILITY;
140 case GScipParameters::HARD_LP:
141 return SCIP_PARAMEMPHASIS_HARDLP;
142 case GScipParameters::OPTIMALITY:
143 return SCIP_PARAMEMPHASIS_OPTIMALITY;
145 return SCIP_PARAMEMPHASIS_COUNTER;
146 case GScipParameters::PHASE_FEAS:
147 return SCIP_PARAMEMPHASIS_PHASEFEAS;
148 case GScipParameters::PHASE_IMPROVE:
149 return SCIP_PARAMEMPHASIS_PHASEIMPROVE;
150 case GScipParameters::PHASE_PROOF:
151 return SCIP_PARAMEMPHASIS_PHASEPROOF;
152 default:
153 LOG(FATAL) << "Unrecognized gscip_emphasis: "
154 << ProtoEnumToString(gscip_emphasis);
155 }
156}
157
158SCIP_PARAMSETTING ConvertMetaParamValue(
159 const GScipParameters::MetaParamValue gscip_meta_param_value) {
160 switch (gscip_meta_param_value) {
161 case GScipParameters::DEFAULT_META_PARAM_VALUE:
162 return SCIP_PARAMSETTING_DEFAULT;
163 case GScipParameters::AGGRESSIVE:
164 return SCIP_PARAMSETTING_AGGRESSIVE;
165 case GScipParameters::FAST:
166 return SCIP_PARAMSETTING_FAST;
167 case GScipParameters::OFF:
168 return SCIP_PARAMSETTING_OFF;
169 default:
170 LOG(FATAL) << "Unrecognized gscip_meta_param_value: "
171 << ProtoEnumToString(gscip_meta_param_value);
172 }
173}
174
175absl::Status CheckSolutionsInOrder(const GScipResult& result,
176 const bool is_maximize) {
177 auto objective_as_good_as = [is_maximize](double left, double right) {
178 if (is_maximize) {
179 return left >= right;
180 }
181 return left <= right;
182 };
183 for (int i = 1; i < result.objective_values.size(); ++i) {
184 const double previous = result.objective_values[i - 1];
185 const double current = result.objective_values[i];
186 if (!objective_as_good_as(previous, current)) {
188 << "Expected SCIP solutions to be in best objective order "
189 "first, but for "
190 << (is_maximize ? "maximization" : "minimization")
191 << " problem, the " << i - 1 << " objective is " << previous
192 << " and the " << i << " objective is " << current;
193 }
194 }
195 return absl::OkStatus();
196}
197
198} // namespace
199
201 static GScipVariableOptions var_options;
202 return var_options;
203}
204
206 static GScipConstraintOptions constraint_options;
207 return constraint_options;
208}
209
210absl::Status GScip::SetParams(const GScipParameters& params,
211 const std::string& legacy_params) {
212 if (params.has_silence_output()) {
213 SCIPsetMessagehdlrQuiet(scip_, params.silence_output());
214 }
215 if (!params.search_logs_filename().empty()) {
216 SCIPsetMessagehdlrLogfile(scip_, params.search_logs_filename().c_str());
217 }
218
219 const SCIP_Bool set_param_quiet =
220 static_cast<SCIP_Bool>(!params.silence_output());
221
222 RETURN_IF_SCIP_ERROR(SCIPsetEmphasis(
223 scip_, ConvertEmphasis(params.emphasis()), set_param_quiet));
224 if (params.has_heuristics()) {
225 RETURN_IF_SCIP_ERROR(SCIPsetHeuristics(
226 scip_, ConvertMetaParamValue(params.heuristics()), set_param_quiet));
227 }
228 if (params.has_presolve()) {
229 RETURN_IF_SCIP_ERROR(SCIPsetPresolving(
230 scip_, ConvertMetaParamValue(params.presolve()), set_param_quiet));
231 }
232 if (params.has_separating()) {
233 RETURN_IF_SCIP_ERROR(SCIPsetSeparating(
234 scip_, ConvertMetaParamValue(params.separating()), set_param_quiet));
235 }
236 for (const auto& bool_param : params.bool_params()) {
238 (SCIPsetBoolParam(scip_, bool_param.first.c_str(), bool_param.second)));
239 }
240 for (const auto& int_param : params.int_params()) {
242 (SCIPsetIntParam(scip_, int_param.first.c_str(), int_param.second)));
243 }
244 for (const auto& long_param : params.long_params()) {
245 RETURN_IF_SCIP_ERROR((SCIPsetLongintParam(scip_, long_param.first.c_str(),
246 long_param.second)));
247 }
248 for (const auto& char_param : params.char_params()) {
249 if (char_param.second.size() != 1) {
250 return absl::InvalidArgumentError(
251 absl::StrCat("Character parameters must be single character strings, "
252 "but parameter: ",
253 char_param.first, " was: ", char_param.second));
254 }
255 RETURN_IF_SCIP_ERROR((SCIPsetCharParam(scip_, char_param.first.c_str(),
256 char_param.second[0])));
257 }
258 for (const auto& string_param : params.string_params()) {
259 RETURN_IF_SCIP_ERROR((SCIPsetStringParam(scip_, string_param.first.c_str(),
260 string_param.second.c_str())));
261 }
262 for (const auto& real_param : params.real_params()) {
264 (SCIPsetRealParam(scip_, real_param.first.c_str(), real_param.second)));
265 }
266 if (!legacy_params.empty()) {
268 LegacyScipSetSolverSpecificParameters(legacy_params, scip_));
269 }
270 return absl::OkStatus();
271}
272
273absl::StatusOr<std::unique_ptr<GScip>> GScip::Create(
274 const std::string& problem_name) {
275 SCIP* scip = nullptr;
276 RETURN_IF_SCIP_ERROR(SCIPcreate(&scip));
277 RETURN_IF_SCIP_ERROR(SCIPincludeDefaultPlugins(scip));
278 RETURN_IF_SCIP_ERROR(SCIPcreateProbBasic(scip, problem_name.c_str()));
279 // NOTE(user): the constructor is private, so we cannot call make_unique.
280 return absl::WrapUnique(new GScip(scip));
281}
282
283GScip::GScip(SCIP* scip) : scip_(scip) {}
284
285double GScip::ScipInf() { return SCIPinfinity(scip_); }
286
287absl::Status GScip::FreeTransform() {
288 return SCIP_TO_STATUS(SCIPfreeTransform(scip_));
289}
290
291std::string GScip::ScipVersion() {
292 return absl::StrFormat("SCIP %d.%d.%d [LP solver: %s]", SCIPmajorVersion(),
293 SCIPminorVersion(), SCIPtechVersion(),
294 SCIPlpiGetSolverName());
295}
296
298 if (scip_ == nullptr) {
299 return true;
300 }
301 return SCIPinterruptSolve(scip_) == SCIP_OKAY;
302}
303
304absl::Status GScip::CleanUp() {
305 if (scip_ != nullptr) {
306 for (SCIP_VAR* variable : variables_) {
307 if (variable != nullptr) {
308 RETURN_IF_SCIP_ERROR(SCIPreleaseVar(scip_, &variable));
309 }
310 }
311 for (SCIP_CONS* constraint : constraints_) {
312 if (constraint != nullptr) {
313 RETURN_IF_SCIP_ERROR(SCIPreleaseCons(scip_, &constraint));
314 }
315 }
316 RETURN_IF_SCIP_ERROR(SCIPfree(&scip_));
317 }
318 return absl::OkStatus();
319}
320
322 const absl::Status clean_up_status = CleanUp();
323 LOG_IF(DFATAL, !clean_up_status.ok()) << clean_up_status;
324}
325
326absl::StatusOr<SCIP_VAR*> GScip::AddVariable(
327 double lb, double ub, double obj_coef, GScipVarType var_type,
328 const std::string& var_name, const GScipVariableOptions& options) {
329 SCIP_VAR* var = nullptr;
330 OR_ASSIGN_OR_RETURN3(lb, ScipInfClamp(lb), _ << "invalid lower bound");
331 OR_ASSIGN_OR_RETURN3(ub, ScipInfClamp(ub), _ << "invalid upper bound");
332 RETURN_IF_SCIP_ERROR(SCIPcreateVarBasic(scip_, /*var=*/&var,
333 /*name=*/var_name.c_str(),
334 /*lb=*/lb, /*ub=*/ub,
335 /*obj=*/obj_coef,
336 ConvertVarType(var_type)));
337 RETURN_IF_SCIP_ERROR(SCIPvarSetInitial(var, options.initial));
338 RETURN_IF_SCIP_ERROR(SCIPvarSetRemovable(var, options.removable));
339 RETURN_IF_SCIP_ERROR(SCIPaddVar(scip_, var));
340 if (options.keep_alive) {
341 variables_.insert(var);
342 } else {
343 RETURN_IF_SCIP_ERROR(SCIPreleaseVar(scip_, &var));
344 }
345 return var;
346}
347
348absl::Status GScip::MaybeKeepConstraintAlive(
349 SCIP_CONS* constraint, const GScipConstraintOptions& options) {
350 if (options.keep_alive) {
351 constraints_.insert(constraint);
352 } else {
353 RETURN_IF_SCIP_ERROR(SCIPreleaseCons(scip_, &constraint));
354 }
355 return absl::OkStatus();
356}
357
358absl::StatusOr<SCIP_CONS*> GScip::AddLinearConstraint(
359 const GScipLinearRange& range, const std::string& name,
360 const GScipConstraintOptions& options) {
361 SCIP_CONS* constraint = nullptr;
362 RETURN_ERROR_UNLESS(range.variables.size() == range.coefficients.size())
363 << "Error adding constraint: " << name << ".";
364 OR_ASSIGN_OR_RETURN3(const double lb, ScipInfClamp(range.lower_bound),
365 _ << "invalid lower bound");
366 OR_ASSIGN_OR_RETURN3(const double ub, ScipInfClamp(range.upper_bound),
367 _ << "invalid upper bound");
368 RETURN_IF_SCIP_ERROR(SCIPcreateConsLinear(
369 scip_, &constraint, name.c_str(), range.variables.size(),
370 const_cast<SCIP_VAR**>(range.variables.data()),
371 const_cast<double*>(range.coefficients.data()),
372 /*lhs=*/lb, /*rhs=*/ub,
373 /*initial=*/options.initial,
374 /*separate=*/options.separate,
375 /*enforce=*/options.enforce,
376 /*check=*/options.check,
377 /*propagate=*/options.propagate,
378 /*local=*/options.local,
379 /*modifiable=*/options.modifiable,
380 /*dynamic=*/options.dynamic,
381 /*removable=*/options.removable,
382 /*stickingatnode=*/options.sticking_at_node));
383 RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint));
384 RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options));
385 return constraint;
386}
387
388absl::StatusOr<SCIP_CONS*> GScip::AddQuadraticConstraint(
389 const GScipQuadraticRange& range, const std::string& name,
390 const GScipConstraintOptions& options) {
391 SCIP_CONS* constraint = nullptr;
392 const int num_lin_vars = range.linear_variables.size();
393 RETURN_ERROR_UNLESS(num_lin_vars == range.linear_coefficients.size())
394 << "Error adding quadratic constraint: " << name << " in linear term.";
395 const int num_quad_vars = range.quadratic_variables1.size();
396 RETURN_ERROR_UNLESS(num_quad_vars == range.quadratic_variables2.size())
397 << "Error adding quadratic constraint: " << name << " in quadratic term.";
398 RETURN_ERROR_UNLESS(num_quad_vars == range.quadratic_coefficients.size())
399 << "Error adding quadratic constraint: " << name << " in quadratic term.";
400 OR_ASSIGN_OR_RETURN3(const double lb, ScipInfClamp(range.lower_bound),
401 _ << "invalid lower bound");
402 OR_ASSIGN_OR_RETURN3(const double ub, ScipInfClamp(range.upper_bound),
403 _ << "invalid upper bound");
404 RETURN_IF_SCIP_ERROR(SCIPcreateConsQuadratic(
405 scip_, &constraint, name.c_str(), num_lin_vars,
406 const_cast<SCIP_Var**>(range.linear_variables.data()),
407 const_cast<double*>(range.linear_coefficients.data()), num_quad_vars,
408 const_cast<SCIP_Var**>(range.quadratic_variables1.data()),
409 const_cast<SCIP_Var**>(range.quadratic_variables2.data()),
410 const_cast<double*>(range.quadratic_coefficients.data()),
411 /*lhs=*/lb, /*rhs=*/ub,
412 /*initial=*/options.initial,
413 /*separate=*/options.separate,
414 /*enforce=*/options.enforce,
415 /*check=*/options.check,
416 /*propagate=*/options.propagate,
417 /*local=*/options.local,
418 /*modifiable=*/options.modifiable,
419 /*dynamic=*/options.dynamic,
420 /*removable=*/options.removable));
421 RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint));
422 RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options));
423 return constraint;
424}
425
426absl::StatusOr<SCIP_CONS*> GScip::AddIndicatorConstraint(
427 const GScipIndicatorConstraint& indicator_constraint,
428 const std::string& name, const GScipConstraintOptions& options) {
429 SCIP_VAR* indicator = indicator_constraint.indicator_variable;
430 RETURN_ERROR_UNLESS(indicator != nullptr)
431 << "Error adding indicator constraint: " << name << ".";
432 if (indicator_constraint.negate_indicator) {
433 RETURN_IF_SCIP_ERROR(SCIPgetNegatedVar(scip_, indicator, &indicator));
434 }
435
436 SCIP_CONS* constraint = nullptr;
437 RETURN_ERROR_UNLESS(indicator_constraint.variables.size() ==
438 indicator_constraint.coefficients.size())
439 << "Error adding indicator constraint: " << name << ".";
440 OR_ASSIGN_OR_RETURN3(const double ub,
441 ScipInfClamp(indicator_constraint.upper_bound),
442 _ << "invalid upper bound");
443 RETURN_IF_SCIP_ERROR(SCIPcreateConsIndicator(
444 scip_, &constraint, name.c_str(), indicator,
445 indicator_constraint.variables.size(),
446 const_cast<SCIP_Var**>(indicator_constraint.variables.data()),
447 const_cast<double*>(indicator_constraint.coefficients.data()),
448 /*rhs=*/ub,
449 /*initial=*/options.initial,
450 /*separate=*/options.separate,
451 /*enforce=*/options.enforce,
452 /*check=*/options.check,
453 /*propagate=*/options.propagate,
454 /*local=*/options.local,
455 /*dynamic=*/options.dynamic,
456 /*removable=*/options.removable,
457 /*stickingatnode=*/options.sticking_at_node));
458 RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint));
459 RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options));
460 return constraint;
461}
462
463absl::StatusOr<SCIP_CONS*> GScip::AddAndConstraint(
464 const GScipLogicalConstraintData& logical_data, const std::string& name,
465 const GScipConstraintOptions& options) {
466 RETURN_ERROR_UNLESS(logical_data.resultant != nullptr)
467 << "Error adding and constraint: " << name << ".";
468 SCIP_CONS* constraint = nullptr;
470 SCIPcreateConsAnd(scip_, &constraint, name.c_str(),
471 logical_data.resultant, logical_data.operators.size(),
472 const_cast<SCIP_VAR**>(logical_data.operators.data()),
473 /*initial=*/options.initial,
474 /*separate=*/options.separate,
475 /*enforce=*/options.enforce,
476 /*check=*/options.check,
477 /*propagate=*/options.propagate,
478 /*local=*/options.local,
479 /*modifiable=*/options.modifiable,
480 /*dynamic=*/options.dynamic,
481 /*removable=*/options.removable,
482 /*stickingatnode=*/options.sticking_at_node));
483 RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint));
484 RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options));
485 return constraint;
486}
487
488absl::StatusOr<SCIP_CONS*> GScip::AddOrConstraint(
489 const GScipLogicalConstraintData& logical_data, const std::string& name,
490 const GScipConstraintOptions& options) {
491 RETURN_ERROR_UNLESS(logical_data.resultant != nullptr)
492 << "Error adding or constraint: " << name << ".";
493 SCIP_CONS* constraint = nullptr;
495 SCIPcreateConsOr(scip_, &constraint, name.c_str(), logical_data.resultant,
496 logical_data.operators.size(),
497 const_cast<SCIP_Var**>(logical_data.operators.data()),
498 /*initial=*/options.initial,
499 /*separate=*/options.separate,
500 /*enforce=*/options.enforce,
501 /*check=*/options.check,
502 /*propagate=*/options.propagate,
503 /*local=*/options.local,
504 /*modifiable=*/options.modifiable,
505 /*dynamic=*/options.dynamic,
506 /*removable=*/options.removable,
507 /*stickingatnode=*/options.sticking_at_node));
508 RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint));
509 RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options));
510 return constraint;
511}
512
513namespace {
514
515absl::Status ValidateSOSData(const GScipSOSData& sos_data,
516 const std::string& name) {
517 RETURN_ERROR_UNLESS(!sos_data.variables.empty())
518 << "Error adding SOS constraint: " << name << ".";
519 if (!sos_data.weights.empty()) {
520 RETURN_ERROR_UNLESS(sos_data.variables.size() == sos_data.weights.size())
521 << " Error adding SOS constraint: " << name << ".";
522 }
523 absl::flat_hash_set<double> distinct_weights;
524 for (const double w : sos_data.weights) {
525 RETURN_ERROR_UNLESS(!distinct_weights.contains(w))
526 << "Error adding SOS constraint: " << name
527 << ", weights must be distinct, but found value " << w << " twice.";
528 distinct_weights.insert(w);
529 }
530 return absl::OkStatus();
531}
532
533} // namespace
534
535absl::StatusOr<SCIP_CONS*> GScip::AddSOS1Constraint(
536 const GScipSOSData& sos_data, const std::string& name,
537 const GScipConstraintOptions& options) {
538 RETURN_IF_ERROR(ValidateSOSData(sos_data, name));
539 SCIP_CONS* constraint = nullptr;
540 double* weights = nullptr;
541 if (!sos_data.weights.empty()) {
542 weights = const_cast<double*>(sos_data.weights.data());
543 }
544
545 RETURN_IF_SCIP_ERROR(SCIPcreateConsSOS1(
546 scip_, &constraint, name.c_str(), sos_data.variables.size(),
547 const_cast<SCIP_Var**>(sos_data.variables.data()), weights,
548 /*initial=*/options.initial,
549 /*separate=*/options.separate,
550 /*enforce=*/options.enforce,
551 /*check=*/options.check,
552 /*propagate=*/options.propagate,
553 /*local=*/options.local,
554 /*dynamic=*/options.dynamic,
555 /*removable=*/options.removable,
556 /*stickingatnode=*/options.sticking_at_node));
557 RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint));
558 RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options));
559 return constraint;
560}
561
562absl::StatusOr<SCIP_CONS*> GScip::AddSOS2Constraint(
563 const GScipSOSData& sos_data, const std::string& name,
564 const GScipConstraintOptions& options) {
565 RETURN_IF_ERROR(ValidateSOSData(sos_data, name));
566 SCIP_CONS* constraint = nullptr;
567 double* weights = nullptr;
568 if (!sos_data.weights.empty()) {
569 weights = const_cast<double*>(sos_data.weights.data());
570 }
571 RETURN_IF_SCIP_ERROR(SCIPcreateConsSOS2(
572 scip_, &constraint, name.c_str(), sos_data.variables.size(),
573 const_cast<SCIP_Var**>(sos_data.variables.data()), weights,
574 /*initial=*/options.initial,
575 /*separate=*/options.separate,
576 /*enforce=*/options.enforce,
577 /*check=*/options.check,
578 /*propagate=*/options.propagate,
579 /*local=*/options.local,
580 /*dynamic=*/options.dynamic,
581 /*removable=*/options.removable,
582 /*stickingatnode=*/options.sticking_at_node));
583 RETURN_IF_SCIP_ERROR(SCIPaddCons(scip_, constraint));
584 RETURN_IF_ERROR(MaybeKeepConstraintAlive(constraint, options));
585 return constraint;
586}
587
588absl::Status GScip::SetMaximize(bool is_maximize) {
589 RETURN_IF_SCIP_ERROR(SCIPsetObjsense(
590 scip_, is_maximize ? SCIP_OBJSENSE_MAXIMIZE : SCIP_OBJSENSE_MINIMIZE));
591 return absl::OkStatus();
592}
593
594absl::Status GScip::SetObjectiveOffset(double offset) {
595 double old_offset = SCIPgetOrigObjoffset(scip_);
596 double delta_offset = offset - old_offset;
597 RETURN_IF_SCIP_ERROR(SCIPaddOrigObjoffset(scip_, delta_offset));
598 return absl::OkStatus();
599}
600
602 return SCIPgetObjsense(scip_) == SCIP_OBJSENSE_MAXIMIZE;
603}
604
605double GScip::ObjectiveOffset() { return SCIPgetOrigObjoffset(scip_); }
606
607absl::Status GScip::SetBranchingPriority(SCIP_VAR* var, int priority) {
608 RETURN_IF_SCIP_ERROR(SCIPchgVarBranchPriority(scip_, var, priority));
609 return absl::OkStatus();
610}
611
612absl::Status GScip::SetLb(SCIP_VAR* var, double lb) {
613 OR_ASSIGN_OR_RETURN3(lb, ScipInfClamp(lb), _ << "invalid lower bound");
614 RETURN_IF_SCIP_ERROR(SCIPchgVarLb(scip_, var, lb));
615 return absl::OkStatus();
616}
617
618absl::Status GScip::SetUb(SCIP_VAR* var, double ub) {
619 OR_ASSIGN_OR_RETURN3(ub, ScipInfClamp(ub), _ << "invalid upper bound");
620 RETURN_IF_SCIP_ERROR(SCIPchgVarUb(scip_, var, ub));
621 return absl::OkStatus();
622}
623
624absl::Status GScip::SetObjCoef(SCIP_VAR* var, double obj_coef) {
625 RETURN_IF_SCIP_ERROR(SCIPchgVarObj(scip_, var, obj_coef));
626 return absl::OkStatus();
627}
628
629absl::Status GScip::SetVarType(SCIP_VAR* var, GScipVarType var_type) {
630 SCIP_Bool infeasible;
632 SCIPchgVarType(scip_, var, ConvertVarType(var_type), &infeasible));
633 return absl::OkStatus();
634}
635
636absl::Status GScip::DeleteVariable(SCIP_VAR* var) {
637 SCIP_Bool did_delete;
638 RETURN_IF_SCIP_ERROR(SCIPdelVar(scip_, var, &did_delete));
639 RETURN_ERROR_UNLESS(static_cast<bool>(did_delete))
640 << "Failed to delete variable named: " << Name(var);
641 variables_.erase(var);
642 RETURN_IF_SCIP_ERROR(SCIPreleaseVar(scip_, &var));
643 return absl::OkStatus();
644}
645
647 const absl::flat_hash_set<SCIP_VAR*>& vars) {
648 for (SCIP_CONS* constraint : constraints_) {
649 if (!IsConstraintLinear(constraint)) {
650 return absl::InvalidArgumentError(absl::StrCat(
651 "Model contains nonlinear constraint: ", Name(constraint)));
652 }
653 }
654 return absl::OkStatus();
655}
656
657absl::Status GScip::SafeBulkDelete(const absl::flat_hash_set<SCIP_VAR*>& vars) {
659 // Now, we can assume that all constraints are linear.
660 for (SCIP_CONS* constraint : constraints_) {
661 const absl::Span<SCIP_VAR* const> nonzeros =
662 LinearConstraintVariables(constraint);
663 const std::vector<SCIP_VAR*> nonzeros_copy(nonzeros.begin(),
664 nonzeros.end());
665 for (SCIP_VAR* var : nonzeros_copy) {
666 if (vars.contains(var)) {
668 }
669 }
670 }
671 for (SCIP_VAR* const var : vars) {
673 }
674 return absl::OkStatus();
675}
676
677double GScip::Lb(SCIP_VAR* var) {
678 return ScipInfUnclamp(SCIPvarGetLbOriginal(var));
679}
680
681double GScip::Ub(SCIP_VAR* var) {
682 return ScipInfUnclamp(SCIPvarGetUbOriginal(var));
683}
684
685double GScip::ObjCoef(SCIP_VAR* var) { return SCIPvarGetObj(var); }
686
688 return ConvertVarType(SCIPvarGetType(var));
689}
690
691absl::string_view GScip::Name(SCIP_VAR* var) { return SCIPvarGetName(var); }
692
693absl::string_view GScip::ConstraintType(SCIP_CONS* constraint) {
694 return absl::string_view(SCIPconshdlrGetName(SCIPconsGetHdlr(constraint)));
695}
696
697bool GScip::IsConstraintLinear(SCIP_CONS* constraint) {
698 return ConstraintType(constraint) == kLinearConstraintHandlerName;
699}
700
701absl::Span<const double> GScip::LinearConstraintCoefficients(
702 SCIP_CONS* constraint) {
703 int num_vars = SCIPgetNVarsLinear(scip_, constraint);
704 return absl::MakeConstSpan(SCIPgetValsLinear(scip_, constraint), num_vars);
705}
706
707absl::Span<SCIP_VAR* const> GScip::LinearConstraintVariables(
708 SCIP_CONS* constraint) {
709 int num_vars = SCIPgetNVarsLinear(scip_, constraint);
710 return absl::MakeConstSpan(SCIPgetVarsLinear(scip_, constraint), num_vars);
711}
712
713double GScip::LinearConstraintLb(SCIP_CONS* constraint) {
714 return ScipInfUnclamp(SCIPgetLhsLinear(scip_, constraint));
715}
716
717double GScip::LinearConstraintUb(SCIP_CONS* constraint) {
718 return ScipInfUnclamp(SCIPgetRhsLinear(scip_, constraint));
719}
720
721absl::string_view GScip::Name(SCIP_CONS* constraint) {
722 return SCIPconsGetName(constraint);
723}
724
725absl::Status GScip::SetLinearConstraintLb(SCIP_CONS* constraint, double lb) {
726 OR_ASSIGN_OR_RETURN3(lb, ScipInfClamp(lb), _ << "invalid lower bound");
727 RETURN_IF_SCIP_ERROR(SCIPchgLhsLinear(scip_, constraint, lb));
728 return absl::OkStatus();
729}
730
731absl::Status GScip::SetLinearConstraintUb(SCIP_CONS* constraint, double ub) {
732 OR_ASSIGN_OR_RETURN3(ub, ScipInfClamp(ub), _ << "invalid upper bound");
733 RETURN_IF_SCIP_ERROR(SCIPchgRhsLinear(scip_, constraint, ub));
734 return absl::OkStatus();
735}
736
737absl::Status GScip::DeleteConstraint(SCIP_CONS* constraint) {
738 RETURN_IF_SCIP_ERROR(SCIPdelCons(scip_, constraint));
739 constraints_.erase(constraint);
740 RETURN_IF_SCIP_ERROR(SCIPreleaseCons(scip_, &constraint));
741 return absl::OkStatus();
742}
743
744absl::Status GScip::SetLinearConstraintCoef(SCIP_CONS* constraint,
745 SCIP_VAR* var, double value) {
746 // TODO(user): this operation is slow (linear in the nnz in the constraint).
747 // It would be better to just use a bulk operation, but there doesn't appear
748 // to be any?
749 RETURN_IF_SCIP_ERROR(SCIPchgCoefLinear(scip_, constraint, var, value));
750 return absl::OkStatus();
751}
752
753absl::Status GScip::AddLinearConstraintCoef(SCIP_CONS* const constraint,
754 SCIP_VAR* const var,
755 const double value) {
756 RETURN_IF_SCIP_ERROR(SCIPaddCoefLinear(scip_, constraint, var, value));
757 return absl::OkStatus();
758}
759
760absl::StatusOr<GScipHintResult> GScip::SuggestHint(
761 const GScipSolution& partial_solution) {
762 SCIP_SOL* solution;
763 const int scip_num_vars = SCIPgetNOrigVars(scip_);
764 const bool is_solution_partial = partial_solution.size() < scip_num_vars;
765 if (is_solution_partial) {
766 RETURN_IF_SCIP_ERROR(SCIPcreatePartialSol(scip_, &solution, nullptr));
767 } else {
768 // This is actually a full solution
769 RETURN_ERROR_UNLESS(partial_solution.size() == scip_num_vars)
770 << "Error suggesting hint.";
771 RETURN_IF_SCIP_ERROR(SCIPcreateSol(scip_, &solution, nullptr));
772 }
773 for (const auto& var_value_pair : partial_solution) {
774 RETURN_IF_SCIP_ERROR(SCIPsetSolVal(scip_, solution, var_value_pair.first,
775 var_value_pair.second));
776 }
777 if (!is_solution_partial) {
778 SCIP_Bool is_feasible;
779 RETURN_IF_SCIP_ERROR(SCIPcheckSol(
780 scip_, solution, /*printreason=*/false, /*completely=*/true,
781 /*checkbounds=*/true, /*checkintegrality=*/true, /*checklprows=*/true,
782 &is_feasible));
783 if (!static_cast<bool>(is_feasible)) {
784 RETURN_IF_SCIP_ERROR(SCIPfreeSol(scip_, &solution));
786 }
787 }
788 SCIP_Bool is_stored;
789 RETURN_IF_SCIP_ERROR(SCIPaddSolFree(scip_, &solution, &is_stored));
790 if (static_cast<bool>(is_stored)) {
792 } else {
794 }
795}
796
797absl::StatusOr<GScipResult> GScip::Solve(
798 const GScipParameters& params, const std::string& legacy_params,
799 const GScipMessageHandler message_handler) {
800 // A four step process:
801 // 1. Apply parameters.
802 // 2. Solve the problem.
803 // 3. Extract solution and solve statistics.
804 // 4. Prepare the solver for further modification/solves (reset parameters,
805 // free the solutions found).
806 GScipResult result;
807
808 // Step 1: apply parameters.
809 const absl::Status param_status = SetParams(params, legacy_params);
810 if (!param_status.ok()) {
811 result.gscip_output.set_status(GScipOutput::INVALID_SOLVER_PARAMETERS);
812 // Conversion to std::string for open source build.
813 result.gscip_output.set_status_detail(
814 std::string(param_status.message())); // NOLINT
815 return result;
816 }
817 if (params.print_scip_model()) {
818 RETURN_IF_SCIP_ERROR(SCIPwriteOrigProblem(scip_, nullptr, "cip", FALSE));
819 }
820 if (!params.scip_model_filename().empty()) {
821 RETURN_IF_SCIP_ERROR(SCIPwriteOrigProblem(
822 scip_, params.scip_model_filename().c_str(), "cip", FALSE));
823 }
824 if (params.has_objective_limit()) {
825 OR_ASSIGN_OR_RETURN3(const double scip_obj_limit,
826 ScipInfClamp(params.objective_limit()),
827 _ << "invalid objective_limit");
828 RETURN_IF_SCIP_ERROR(SCIPsetObjlimit(scip_, scip_obj_limit));
829 }
830
831 // Install the message handler if necessary. We do this after setting the
832 // parameters so that parameters that applies to the default message handler
833 // like `quiet` are indeed applied to it and not to our temporary
834 // handler.
837 MessageHandlerPtr previous_handler;
838 MessageHandlerPtr new_handler;
839 if (message_handler != nullptr) {
840 previous_handler = CaptureMessageHandlerPtr(SCIPgetMessagehdlr(scip_));
841 ASSIGN_OR_RETURN(new_handler,
842 internal::MakeSCIPMessageHandler(message_handler));
843 SCIPsetMessagehdlr(scip_, new_handler.get());
844 }
845 // Make sure we prevent any call of message_handler after this function has
846 // returned, until the new_handler is reset (see below).
847 const internal::ScopedSCIPMessageHandlerDisabler new_handler_disabler(
848 new_handler);
849
850 // Step 2: Solve.
851 // NOTE(user): after solve, SCIP will either be in stage PRESOLVING,
852 // SOLVING, OR SOLVED.
853 if (GScipMaxNumThreads(params) > 1) {
854 RETURN_IF_SCIP_ERROR(SCIPsolveConcurrent(scip_));
855 } else {
856 RETURN_IF_SCIP_ERROR(SCIPsolve(scip_));
857 }
858 const SCIP_STAGE stage = SCIPgetStage(scip_);
859 if (stage != SCIP_STAGE_PRESOLVING && stage != SCIP_STAGE_SOLVING &&
860 stage != SCIP_STAGE_SOLVED) {
861 result.gscip_output.set_status(GScipOutput::UNKNOWN);
862 result.gscip_output.set_status_detail(
863 absl::StrCat("Unpexpected SCIP final stage= ", stage,
864 " was expected to be either SCIP_STAGE_PRESOLVING, "
865 "SCIP_STAGE_SOLVING, or SCIP_STAGE_SOLVED"));
866 return result;
867 }
868 if (params.print_detailed_solving_stats()) {
869 RETURN_IF_SCIP_ERROR(SCIPprintStatistics(scip_, nullptr));
870 }
871 if (!params.detailed_solving_stats_filename().empty()) {
872 FILE* file = fopen(params.detailed_solving_stats_filename().c_str(), "w");
873 if (file == nullptr) {
874 return absl::InvalidArgumentError(absl::StrCat(
875 "Could not open file: ", params.detailed_solving_stats_filename(),
876 " to write SCIP solve stats."));
877 }
878 RETURN_IF_SCIP_ERROR(SCIPprintStatistics(scip_, file));
879 int close_result = fclose(file);
880 if (close_result != 0) {
881 return absl::InvalidArgumentError(absl::StrCat(
882 "Error: ", close_result,
883 " closing file: ", params.detailed_solving_stats_filename(),
884 " when writing solve stats."));
885 }
886 }
887 // Step 3: Extract solution information.
888 // Some outputs are available unconditionally, and some are only ready if at
889 // least presolve succeeded.
890 GScipSolvingStats* stats = result.gscip_output.mutable_stats();
891 const int num_scip_solutions = SCIPgetNSols(scip_);
892 const int num_returned_solutions =
893 std::min(num_scip_solutions, std::max(1, params.num_solutions()));
894 SCIP_SOL** all_solutions = SCIPgetSols(scip_);
895 stats->set_best_objective(ScipInfUnclamp(SCIPgetPrimalbound(scip_)));
896 for (int i = 0; i < num_returned_solutions; ++i) {
897 SCIP_SOL* scip_sol = all_solutions[i];
898 const double obj_value = ScipInfUnclamp(SCIPgetSolOrigObj(scip_, scip_sol));
899 GScipSolution solution;
900 for (SCIP_VAR* v : variables_) {
901 solution[v] = SCIPgetSolVal(scip_, scip_sol, v);
902 }
903 result.solutions.push_back(solution);
904 result.objective_values.push_back(obj_value);
905 }
906 RETURN_IF_ERROR(CheckSolutionsInOrder(result, ObjectiveIsMaximize()));
907 // Can only check for primal ray if we made it past presolve.
908 if (stage != SCIP_STAGE_PRESOLVING && SCIPhasPrimalRay(scip_)) {
909 for (SCIP_VAR* v : variables_) {
910 result.primal_ray[v] = SCIPgetPrimalRayVal(scip_, v);
911 }
912 }
913 // TODO(user): refactor this into a new method.
914 stats->set_best_bound(ScipInfUnclamp(SCIPgetDualbound(scip_)));
915 stats->set_node_count(SCIPgetNTotalNodes(scip_));
916 stats->set_first_lp_relaxation_bound(SCIPgetFirstLPDualboundRoot(scip_));
917 stats->set_root_node_bound(SCIPgetDualboundRoot(scip_));
918 if (stage != SCIP_STAGE_PRESOLVING) {
919 stats->set_total_lp_iterations(SCIPgetNLPIterations(scip_));
920 stats->set_primal_simplex_iterations(SCIPgetNPrimalLPIterations(scip_));
921 stats->set_dual_simplex_iterations(SCIPgetNDualLPIterations(scip_));
922 stats->set_deterministic_time(SCIPgetDeterministicTime(scip_));
923 }
924 result.gscip_output.set_status(ConvertStatus(SCIPgetStatus(scip_)));
925
926 // Step 4: clean up.
927 RETURN_IF_ERROR(FreeTransform());
928
929 // Restore the previous message handler. We must do so AFTER we reset the
930 // stage of the problem with FreeTransform(). Doing so before will fail since
931 // changing the message handler is only possible in INIT and PROBLEM stages.
932 if (message_handler != nullptr) {
933 RETURN_IF_SCIP_ERROR(SCIPsetMessagehdlr(scip_, previous_handler.get()));
934
935 // Resetting the unique_ptr will free the associated handler which will
936 // flush the buffer if the last log line was unfinished. If we were not
937 // resetting it, the last new_handler_disabler would disable the handler and
938 // the remainder of the buffer content would be lost.
939 new_handler.reset();
940 }
941 if (params.has_objective_limit()) {
942 RETURN_IF_SCIP_ERROR(SCIPsetObjlimit(scip_, SCIP_INVALID));
943 }
944
945 RETURN_IF_SCIP_ERROR(SCIPresetParams(scip_));
946 // The `silence_output` and `search_logs_filename` parameters are special
947 // since those are not parameters but properties of the SCIP message
948 // handler. Hence we reset them explicitly.
949 SCIPsetMessagehdlrQuiet(scip_, false);
950 SCIPsetMessagehdlrLogfile(scip_, nullptr);
951
952 return result;
953}
954
955absl::StatusOr<bool> GScip::DefaultBoolParamValue(
956 const std::string& parameter_name) {
957 SCIP_Bool default_value;
959 SCIPgetBoolParam(scip_, parameter_name.c_str(), &default_value));
960 return static_cast<bool>(default_value);
961}
962
963absl::StatusOr<int> GScip::DefaultIntParamValue(
964 const std::string& parameter_name) {
965 int default_value;
967 SCIPgetIntParam(scip_, parameter_name.c_str(), &default_value));
968 return default_value;
969}
970
971absl::StatusOr<int64_t> GScip::DefaultLongParamValue(
972 const std::string& parameter_name) {
973 SCIP_Longint result;
975 SCIPgetLongintParam(scip_, parameter_name.c_str(), &result));
976 return static_cast<int64_t>(result);
977}
978
979absl::StatusOr<double> GScip::DefaultRealParamValue(
980 const std::string& parameter_name) {
981 double result;
983 SCIPgetRealParam(scip_, parameter_name.c_str(), &result));
984 return result;
985}
986
987absl::StatusOr<char> GScip::DefaultCharParamValue(
988 const std::string& parameter_name) {
989 char result;
991 SCIPgetCharParam(scip_, parameter_name.c_str(), &result));
992 return result;
993}
994
995absl::StatusOr<std::string> GScip::DefaultStringParamValue(
996 const std::string& parameter_name) {
997 char* result;
999 SCIPgetStringParam(scip_, parameter_name.c_str(), &result));
1000 return std::string(result);
1001}
1002
1003absl::StatusOr<double> GScip::ScipInfClamp(const double d) {
1004 const double kScipInf = ScipInf();
1005 if (d == std::numeric_limits<double>::infinity()) {
1006 return kScipInf;
1007 }
1008 if (d == -std::numeric_limits<double>::infinity()) {
1009 return -kScipInf;
1010 }
1011 // NaN is considered finite here.
1012 if (d >= kScipInf || d <= -kScipInf) {
1014 << d << " is not in SCIP's finite range: (" << -kScipInf << ", "
1015 << kScipInf << ")";
1016 }
1017 return d;
1018}
1019
1020double GScip::ScipInfUnclamp(double d) {
1021 const double kScipInf = ScipInf();
1022 if (d >= kScipInf) return std::numeric_limits<double>::infinity();
1023 if (d <= -kScipInf) return -std::numeric_limits<double>::infinity();
1024 return d;
1025}
1026
1027#undef RETURN_ERROR_UNLESS
1028
1029} // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define LOG_IF(severity, condition)
Definition: base/logging.h:479
#define LOG(severity)
Definition: base/logging.h:420
#define ASSIGN_OR_RETURN(lhs, rexpr)
#define RETURN_IF_ERROR(expr)
double LinearConstraintUb(SCIP_CONS *constraint)
Definition: gscip.cc:717
absl::Status SetObjectiveOffset(double offset)
Definition: gscip.cc:594
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:326
absl::Status DeleteVariable(SCIP_VAR *var)
Definition: gscip.cc:636
absl::StatusOr< SCIP_CONS * > AddOrConstraint(const GScipLogicalConstraintData &logical_data, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition: gscip.cc:488
absl::StatusOr< double > DefaultRealParamValue(const std::string &parameter_name)
Definition: gscip.cc:979
absl::Status CanSafeBulkDelete(const absl::flat_hash_set< SCIP_VAR * > &vars)
Definition: gscip.cc:646
absl::StatusOr< SCIP_CONS * > AddAndConstraint(const GScipLogicalConstraintData &logical_data, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition: gscip.cc:463
absl::StatusOr< SCIP_CONS * > AddLinearConstraint(const GScipLinearRange &range, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition: gscip.cc:358
bool IsConstraintLinear(SCIP_CONS *constraint)
Definition: gscip.cc:697
absl::string_view ConstraintType(SCIP_CONS *constraint)
Definition: gscip.cc:693
absl::StatusOr< int64_t > DefaultLongParamValue(const std::string &parameter_name)
Definition: gscip.cc:971
absl::StatusOr< int > DefaultIntParamValue(const std::string &parameter_name)
Definition: gscip.cc:963
absl::Status DeleteConstraint(SCIP_CONS *constraint)
Definition: gscip.cc:737
absl::Status SetLinearConstraintUb(SCIP_CONS *constraint, double ub)
Definition: gscip.cc:731
absl::Status SafeBulkDelete(const absl::flat_hash_set< SCIP_VAR * > &vars)
Definition: gscip.cc:657
static absl::StatusOr< std::unique_ptr< GScip > > Create(const std::string &problem_name)
Definition: gscip.cc:273
double Ub(SCIP_VAR *var)
Definition: gscip.cc:681
double ObjCoef(SCIP_VAR *var)
Definition: gscip.cc:685
absl::Status SetMaximize(bool is_maximize)
Definition: gscip.cc:588
absl::StatusOr< std::string > DefaultStringParamValue(const std::string &parameter_name)
Definition: gscip.cc:995
absl::StatusOr< bool > DefaultBoolParamValue(const std::string &parameter_name)
Definition: gscip.cc:955
absl::StatusOr< SCIP_CONS * > AddIndicatorConstraint(const GScipIndicatorConstraint &indicator_constraint, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition: gscip.cc:426
double Lb(SCIP_VAR *var)
Definition: gscip.cc:677
absl::Status SetLb(SCIP_VAR *var, double lb)
Definition: gscip.cc:612
absl::Span< SCIP_VAR *const > LinearConstraintVariables(SCIP_CONS *constraint)
Definition: gscip.cc:707
double LinearConstraintLb(SCIP_CONS *constraint)
Definition: gscip.cc:713
absl::Status SetLinearConstraintCoef(SCIP_CONS *constraint, SCIP_VAR *var, double value)
Definition: gscip.cc:744
absl::Status SetLinearConstraintLb(SCIP_CONS *constraint, double lb)
Definition: gscip.cc:725
absl::StatusOr< GScipHintResult > SuggestHint(const GScipSolution &partial_solution)
Definition: gscip.cc:760
absl::StatusOr< GScipResult > Solve(const GScipParameters &params=GScipParameters(), const std::string &legacy_params="", GScipMessageHandler message_handler=nullptr)
Definition: gscip.cc:797
GScipVarType VarType(SCIP_VAR *var)
Definition: gscip.cc:687
absl::Status SetVarType(SCIP_VAR *var, GScipVarType var_type)
Definition: gscip.cc:629
absl::Status SetBranchingPriority(SCIP_VAR *var, int priority)
Definition: gscip.cc:607
absl::StatusOr< char > DefaultCharParamValue(const std::string &parameter_name)
Definition: gscip.cc:987
absl::Span< const double > LinearConstraintCoefficients(SCIP_CONS *constraint)
Definition: gscip.cc:701
absl::Status SetUb(SCIP_VAR *var, double ub)
Definition: gscip.cc:618
absl::Status SetObjCoef(SCIP_VAR *var, double obj_coef)
Definition: gscip.cc:624
absl::StatusOr< SCIP_CONS * > AddSOS2Constraint(const GScipSOSData &sos_data, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition: gscip.cc:562
static std::string ScipVersion()
Definition: gscip.cc:291
absl::StatusOr< SCIP_CONS * > AddQuadraticConstraint(const GScipQuadraticRange &range, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition: gscip.cc:388
absl::string_view Name(SCIP_VAR *var)
Definition: gscip.cc:691
absl::Status AddLinearConstraintCoef(SCIP_CONS *constraint, SCIP_VAR *var, double value)
Definition: gscip.cc:753
absl::StatusOr< SCIP_CONS * > AddSOS1Constraint(const GScipSOSData &sos_data, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition: gscip.cc:535
const std::string name
int64_t value
IntVar * var
Definition: expr_array.cc:1874
#define RETURN_ERROR_UNLESS(x)
Definition: gscip.cc:58
const int FATAL
Definition: log_severity.h:32
absl::StatusOr< MessageHandlerPtr > MakeSCIPMessageHandler(const GScipMessageHandler gscip_message_handler)
std::unique_ptr< SCIP_MESSAGEHDLR, ReleaseSCIPMessageHandler > MessageHandlerPtr
MessageHandlerPtr CaptureMessageHandlerPtr(SCIP_MESSAGEHDLR *const handler)
Collection of objects used to extend the Constraint Solver library.
const GScipConstraintOptions & DefaultGScipConstraintOptions()
Definition: gscip.cc:205
std::function< void(GScipMessageType type, absl::string_view message)> GScipMessageHandler
int GScipMaxNumThreads(const GScipParameters &parameters)
absl::Status LegacyScipSetSolverSpecificParameters(const std::string &parameters, SCIP *scip)
std::string ProtoEnumToString(ProtoEnumType enum_value)
const GScipVariableOptions & DefaultGScipVariableOptions()
Definition: gscip.cc:200
absl::flat_hash_map< SCIP_VAR *, double > GScipSolution
Definition: gscip.h:74
StatusBuilder InternalErrorBuilder()
StatusBuilder InvalidArgumentErrorBuilder()
#define SCIP_TO_STATUS(x)
#define RETURN_IF_SCIP_ERROR(x)
std::vector< SCIP_Var * > variables
Definition: gscip.h:439
std::vector< SCIP_VAR * > variables
Definition: gscip.h:100
std::vector< double > coefficients
Definition: gscip.h:101
std::vector< SCIP_VAR * > operators
Definition: gscip.h:452
std::vector< SCIP_Var * > quadratic_variables1
Definition: gscip.h:399
std::vector< SCIP_Var * > quadratic_variables2
Definition: gscip.h:400
std::vector< SCIP_Var * > linear_variables
Definition: gscip.h:386
std::vector< double > linear_coefficients
Definition: gscip.h:387
std::vector< double > quadratic_coefficients
Definition: gscip.h:401
absl::flat_hash_map< SCIP_VAR *, double > primal_ray
Definition: gscip.h:90
std::vector< double > objective_values
Definition: gscip.h:85
std::vector< GScipSolution > solutions
Definition: gscip.h:83
std::vector< SCIP_VAR * > variables
Definition: gscip.h:420
std::vector< double > weights
Definition: gscip.h:429
#define OR_ASSIGN_OR_RETURN3(lhs, rexpr, error_expression)