OR-Tools  9.6
gscip_ext.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
15 
16 #include <cmath>
17 #include <limits>
18 #include <string>
19 #include <vector>
20 
21 #include "absl/strings/string_view.h"
22 #include "ortools/base/logging.h"
24 
25 namespace operations_research {
26 
27 namespace {
28 
29 std::string MaybeExtendName(absl::string_view base_name,
30  absl::string_view extension) {
31  if (base_name.empty()) {
32  return "";
33  }
34  return absl::StrCat(base_name, "/", extension);
35 }
36 
37 } // namespace
38 
39 GScipLinearExpr::GScipLinearExpr(SCIP_VAR* variable) { terms[variable] = 1.0; }
40 
41 GScipLinearExpr::GScipLinearExpr(double offset) : offset(offset) {}
42 
44  const GScipLinearExpr& right) {
45  left.offset -= right.offset;
46  for (const auto& term : right.terms) {
47  left.terms[term.first] -= term.second;
48  }
49  return left;
50 }
51 
53  expr.offset = -expr.offset;
54  for (auto& term : expr.terms) {
55  term.second = -term.second;
56  }
57  return expr;
58 }
59 
60 // Returns the range -inf <= left.terms - right.terms <= right.offset -
61 // left.offset
63  const GScipLinearExpr& right) {
64  GScipLinearExpr diff = GScipDifference(left, right);
65  GScipLinearRange result;
66  result.lower_bound = -std::numeric_limits<double>::infinity();
67  result.upper_bound = -diff.offset;
68  for (const auto& term : diff.terms) {
69  result.variables.push_back(term.first);
70  result.coefficients.push_back(term.second);
71  }
72  return result;
73 }
74 
75 absl::Status GScipCreateAbs(GScip* gscip, SCIP_Var* x, SCIP_Var* abs_x,
76  const std::string& name) {
77  return GScipCreateMaximum(
78  gscip, GScipLinearExpr(abs_x),
80 }
81 
82 absl::Status GScipCreateMaximum(GScip* gscip, const GScipLinearExpr& resultant,
83  const std::vector<GScipLinearExpr>& terms,
84  const std::string& name) {
85  // TODO(user): it may be better to write this in terms of the disjuntive
86  // constraint, we need to support disjunctions in gscip.h to do this.
87  //
88  // z_i in {0,1}, indicates if y = x_i
89  //
90  // x_i <= y
91  // z_i => y <= x_i
92  // \sum_i z_i == 1
93  std::vector<SCIP_VAR*> indicators;
94  for (int i = 0; i < terms.size(); ++i) {
95  auto z = gscip->AddVariable(0.0, 1.0, 0.0, GScipVarType::kInteger,
96  MaybeExtendName(name, absl::StrCat("z_", i)));
97  RETURN_IF_ERROR(z.status());
98  indicators.push_back(*z);
99  }
100 
101  for (int i = 0; i < terms.size(); ++i) {
102  // x_i <= y
104  gscip
105  ->AddLinearConstraint(
106  GScipLe(terms.at(i), resultant),
107  MaybeExtendName(name, absl::StrCat("x_", i, "_le_y")))
108  .status());
109  // z_i => y <= x_i
110  {
111  GScipLinearRange y_less_x = GScipLe(resultant, terms.at(i));
112  CHECK_EQ(y_less_x.lower_bound, -std::numeric_limits<double>::infinity());
114  ind.indicator_variable = indicators.at(i);
115  ind.variables = y_less_x.variables;
116  ind.coefficients = y_less_x.coefficients;
117  ind.upper_bound = y_less_x.upper_bound;
119  gscip
120  ->AddIndicatorConstraint(
121  ind, MaybeExtendName(
122  name, absl::StrCat("y_le__x_", i, "_if_z_", i)))
123  .status());
124  }
125  }
126 
127  // sum_i z_i = 1.
128  GScipLinearRange z_use;
129  z_use.upper_bound = 1.0;
130  z_use.lower_bound = 1.0;
131  z_use.variables = indicators;
132  z_use.coefficients = std::vector<double>(indicators.size(), 1.0);
133 
134  return gscip->AddLinearConstraint(z_use, MaybeExtendName(name, "one_z"))
135  .status();
136 }
137 
138 absl::Status GScipCreateMinimum(GScip* gscip, const GScipLinearExpr& resultant,
139  const std::vector<GScipLinearExpr>& terms,
140  const std::string& name) {
141  std::vector<GScipLinearExpr> negated_terms;
142  negated_terms.reserve(terms.size());
143  for (const GScipLinearExpr& e : terms) {
144  negated_terms.push_back(GScipNegate(e));
145  }
146  return GScipCreateMaximum(gscip, GScipNegate(resultant), negated_terms, name);
147 }
148 
150  GScip* gscip, std::vector<SCIP_Var*> quadratic_variables1,
151  std::vector<SCIP_Var*> quadratic_variables2,
152  std::vector<double> quadratic_coefficients, const std::string& name) {
153  constexpr double kInf = std::numeric_limits<double>::infinity();
154  auto obj_term =
156  MaybeExtendName(name, "obj"));
157  RETURN_IF_ERROR(obj_term.status());
159  range.quadratic_variables1 = quadratic_variables1;
160  range.quadratic_variables2 = quadratic_variables2;
161  range.quadratic_coefficients = quadratic_coefficients;
162  range.linear_coefficients = {-1.0};
163  range.linear_variables = {*obj_term};
164  if (gscip->ObjectiveIsMaximize()) {
165  // maximize z
166  // z <= Q(x, y)
167  // => 0 <= Q(x, y) - z <= inf
168  range.lower_bound = 0.0;
169  } else {
170  // minimize z
171  // z >= Q(x, y)
172  // => 0 >= Q(x, y) - z >= -inf
173  range.upper_bound = 0.0;
174  }
175  return gscip->AddQuadraticConstraint(range, MaybeExtendName(name, "cons"))
176  .status();
177 }
178 
180  GScip* gscip, const GScipIndicatorRangeConstraint& indicator_range,
181  const std::string& name, const GScipConstraintOptions& options) {
182  if (std::isfinite(indicator_range.range.upper_bound)) {
183  GScipIndicatorConstraint ub_constraint;
184  ub_constraint.upper_bound = indicator_range.range.upper_bound;
185  ub_constraint.variables = indicator_range.range.variables;
186  ub_constraint.coefficients = indicator_range.range.coefficients;
187  ub_constraint.indicator_variable = indicator_range.indicator_variable;
188  ub_constraint.negate_indicator = indicator_range.negate_indicator;
189  RETURN_IF_ERROR(gscip
190  ->AddIndicatorConstraint(
191  ub_constraint, MaybeExtendName(name, "ub"), options)
192  .status());
193  }
194  if (std::isfinite(indicator_range.range.lower_bound)) {
195  // want z -> lb <= a * x
196  // <=> z -> -lb >= -a * x
197  GScipIndicatorConstraint lb_constraint;
198  lb_constraint.upper_bound = -indicator_range.range.lower_bound;
199  lb_constraint.variables = indicator_range.range.variables;
200  for (const double c : indicator_range.range.coefficients) {
201  lb_constraint.coefficients.push_back(-c);
202  }
203  lb_constraint.indicator_variable = indicator_range.indicator_variable;
204  lb_constraint.negate_indicator = indicator_range.negate_indicator;
205  RETURN_IF_ERROR(gscip
206  ->AddIndicatorConstraint(
207  lb_constraint, MaybeExtendName(name, "lb"), options)
208  .status());
209  }
210  return absl::OkStatus();
211 }
212 
213 } // namespace operations_research
#define RETURN_IF_ERROR(expr)
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:329
absl::StatusOr< SCIP_CONS * > AddLinearConstraint(const GScipLinearRange &range, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition: gscip.cc:365
absl::StatusOr< SCIP_CONS * > AddQuadraticConstraint(const GScipQuadraticRange &range, const std::string &name="", const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
Definition: gscip.cc:399
const std::string name
absl::Status status
Definition: g_gurobi.cc:41
Collection of objects used to extend the Constraint Solver library.
GScipLinearRange GScipLe(const GScipLinearExpr left, const GScipLinearExpr &right)
Definition: gscip_ext.cc:62
GScipLinearExpr GScipDifference(GScipLinearExpr left, const GScipLinearExpr &right)
Definition: gscip_ext.cc:43
absl::Status GScipCreateMaximum(GScip *gscip, const GScipLinearExpr &resultant, const std::vector< GScipLinearExpr > &terms, const std::string &name)
Definition: gscip_ext.cc:82
absl::Status GScipCreateAbs(GScip *gscip, SCIP_Var *x, SCIP_Var *abs_x, const std::string &name)
Definition: gscip_ext.cc:75
absl::Status GScipAddQuadraticObjectiveTerm(GScip *gscip, std::vector< SCIP_Var * > quadratic_variables1, std::vector< SCIP_Var * > quadratic_variables2, std::vector< double > quadratic_coefficients, const std::string &name)
Definition: gscip_ext.cc:149
absl::Status GScipCreateMinimum(GScip *gscip, const GScipLinearExpr &resultant, const std::vector< GScipLinearExpr > &terms, const std::string &name)
Definition: gscip_ext.cc:138
absl::Status GScipCreateIndicatorRange(GScip *gscip, const GScipIndicatorRangeConstraint &indicator_range, const std::string &name, const GScipConstraintOptions &options)
Definition: gscip_ext.cc:179
GScipLinearExpr GScipNegate(GScipLinearExpr expr)
Definition: gscip_ext.cc:52
const std::optional< Range > & range
Definition: statistics.cc:36
std::vector< SCIP_Var * > variables
Definition: gscip.h:454
absl::flat_hash_map< SCIP_VAR *, double > terms
Definition: gscip_ext.h:50
std::vector< SCIP_VAR * > variables
Definition: gscip.h:100
std::vector< double > coefficients
Definition: gscip.h:101