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