OR-Tools  8.1
linear_constraint.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 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 "ortools/base/mathutil.h"
17 #include "ortools/sat/integer.h"
18 
19 namespace operations_research {
20 namespace sat {
21 
22 void LinearConstraintBuilder::AddTerm(IntegerVariable var, IntegerValue coeff) {
23  // We can either add var or NegationOf(var), and we always choose the
24  // positive one.
25  if (VariableIsPositive(var)) {
26  terms_.push_back({var, coeff});
27  } else {
28  terms_.push_back({NegationOf(var), -coeff});
29  }
30 }
31 
33  IntegerValue coeff) {
34  // We can either add var or NegationOf(var), and we always choose the
35  // positive one.
36  if (expr.var != kNoIntegerVariable) {
37  if (VariableIsPositive(expr.var)) {
38  terms_.push_back({expr.var, coeff * expr.coeff});
39  } else {
40  terms_.push_back({NegationOf(expr.var), -coeff * expr.coeff});
41  }
42  }
43  if (lb_ > kMinIntegerValue) lb_ -= coeff * expr.constant;
44  if (ub_ < kMaxIntegerValue) ub_ -= coeff * expr.constant;
45 }
46 
48  if (lb_ > kMinIntegerValue) lb_ -= value;
49  if (ub_ < kMaxIntegerValue) ub_ -= value;
50 }
51 
52 ABSL_MUST_USE_RESULT bool LinearConstraintBuilder::AddLiteralTerm(
53  Literal lit, IntegerValue coeff) {
54  bool has_direct_view = encoder_.GetLiteralView(lit) != kNoIntegerVariable;
55  bool has_opposite_view =
56  encoder_.GetLiteralView(lit.Negated()) != kNoIntegerVariable;
57 
58  // If a literal has both views, we want to always keep the same
59  // representative: the smallest IntegerVariable. Note that AddTerm() will
60  // also make sure to use the associated positive variable.
61  if (has_direct_view && has_opposite_view) {
62  if (encoder_.GetLiteralView(lit) <=
63  encoder_.GetLiteralView(lit.Negated())) {
64  has_opposite_view = false;
65  } else {
66  has_direct_view = false;
67  }
68  }
69  if (has_direct_view) {
70  AddTerm(encoder_.GetLiteralView(lit), coeff);
71  return true;
72  }
73  if (has_opposite_view) {
74  AddTerm(encoder_.GetLiteralView(lit.Negated()), -coeff);
75  if (lb_ > kMinIntegerValue) lb_ -= coeff;
76  if (ub_ < kMaxIntegerValue) ub_ -= coeff;
77  return true;
78  }
79  return false;
80 }
81 
83  std::vector<std::pair<IntegerVariable, IntegerValue>>* terms,
84  LinearConstraint* constraint) {
85  constraint->vars.clear();
86  constraint->coeffs.clear();
87 
88  // Sort and add coeff of duplicate variables. Note that a variable and
89  // its negation will appear one after another in the natural order.
90  std::sort(terms->begin(), terms->end());
91  IntegerVariable previous_var = kNoIntegerVariable;
92  IntegerValue current_coeff(0);
93  for (const std::pair<IntegerVariable, IntegerValue> entry : *terms) {
94  if (previous_var == entry.first) {
95  current_coeff += entry.second;
96  } else if (previous_var == NegationOf(entry.first)) {
97  current_coeff -= entry.second;
98  } else {
99  if (current_coeff != 0) {
100  constraint->vars.push_back(previous_var);
101  constraint->coeffs.push_back(current_coeff);
102  }
103  previous_var = entry.first;
104  current_coeff = entry.second;
105  }
106  }
107  if (current_coeff != 0) {
108  constraint->vars.push_back(previous_var);
109  constraint->coeffs.push_back(current_coeff);
110  }
111 }
112 
114  LinearConstraint result;
115  result.lb = lb_;
116  result.ub = ub_;
117  CleanTermsAndFillConstraint(&terms_, &result);
118  return result;
119 }
120 
122  const LinearConstraint& constraint,
124  double activity = 0;
125  for (int i = 0; i < constraint.vars.size(); ++i) {
126  const IntegerVariable var = constraint.vars[i];
127  const IntegerValue coeff = constraint.coeffs[i];
128  activity += coeff.value() * values[var];
129  }
130  return activity;
131 }
132 
133 double ComputeL2Norm(const LinearConstraint& constraint) {
134  double sum = 0.0;
135  for (const IntegerValue coeff : constraint.coeffs) {
136  sum += ToDouble(coeff) * ToDouble(coeff);
137  }
138  return std::sqrt(sum);
139 }
140 
141 IntegerValue ComputeInfinityNorm(const LinearConstraint& constraint) {
142  IntegerValue result(0);
143  for (const IntegerValue coeff : constraint.coeffs) {
144  result = std::max(result, IntTypeAbs(coeff));
145  }
146  return result;
147 }
148 
149 double ScalarProduct(const LinearConstraint& constraint1,
150  const LinearConstraint& constraint2) {
151  DCHECK(std::is_sorted(constraint1.vars.begin(), constraint1.vars.end()));
152  DCHECK(std::is_sorted(constraint2.vars.begin(), constraint2.vars.end()));
153  double scalar_product = 0.0;
154  int index_1 = 0;
155  int index_2 = 0;
156  while (index_1 < constraint1.vars.size() &&
157  index_2 < constraint2.vars.size()) {
158  if (constraint1.vars[index_1] == constraint2.vars[index_2]) {
159  scalar_product += ToDouble(constraint1.coeffs[index_1]) *
160  ToDouble(constraint2.coeffs[index_2]);
161  index_1++;
162  index_2++;
163  } else if (constraint1.vars[index_1] > constraint2.vars[index_2]) {
164  index_2++;
165  } else {
166  index_1++;
167  }
168  }
169  return scalar_product;
170 }
171 
172 namespace {
173 
174 // TODO(user): Template for any integer type and expose this?
175 IntegerValue ComputeGcd(const std::vector<IntegerValue>& values) {
176  if (values.empty()) return IntegerValue(1);
177  int64 gcd = 0;
178  for (const IntegerValue value : values) {
179  gcd = MathUtil::GCD64(gcd, std::abs(value.value()));
180  if (gcd == 1) break;
181  }
182  if (gcd < 0) return IntegerValue(1); // Can happen with kint64min.
183  return IntegerValue(gcd);
184 }
185 
186 } // namespace
187 
188 void DivideByGCD(LinearConstraint* constraint) {
189  if (constraint->coeffs.empty()) return;
190  const IntegerValue gcd = ComputeGcd(constraint->coeffs);
191  if (gcd == 1) return;
192 
193  if (constraint->lb > kMinIntegerValue) {
194  constraint->lb = CeilRatio(constraint->lb, gcd);
195  }
196  if (constraint->ub < kMaxIntegerValue) {
197  constraint->ub = FloorRatio(constraint->ub, gcd);
198  }
199  for (IntegerValue& coeff : constraint->coeffs) coeff /= gcd;
200 }
201 
203  int new_size = 0;
204  const int size = constraint->vars.size();
205  for (int i = 0; i < size; ++i) {
206  if (constraint->coeffs[i] == 0) continue;
207  constraint->vars[new_size] = constraint->vars[i];
208  constraint->coeffs[new_size] = constraint->coeffs[i];
209  ++new_size;
210  }
211  constraint->vars.resize(new_size);
212  constraint->coeffs.resize(new_size);
213 }
214 
216  const int size = constraint->vars.size();
217  for (int i = 0; i < size; ++i) {
218  const IntegerValue coeff = constraint->coeffs[i];
219  if (coeff < 0) {
220  constraint->coeffs[i] = -coeff;
221  constraint->vars[i] = NegationOf(constraint->vars[i]);
222  }
223  }
224 }
225 
227  const int size = constraint->vars.size();
228  for (int i = 0; i < size; ++i) {
229  const IntegerVariable var = constraint->vars[i];
230  if (!VariableIsPositive(var)) {
231  constraint->coeffs[i] = -constraint->coeffs[i];
232  constraint->vars[i] = NegationOf(var);
233  }
234  }
235 }
236 
237 // TODO(user): it would be better if LinearConstraint natively supported
238 // term and not two separated vectors. Fix?
239 //
240 // TODO(user): This is really similar to CleanTermsAndFillConstraint(), maybe
241 // we should just make the later switch negative variable to positive ones to
242 // avoid an extra linear scan on each new cuts.
244  std::vector<std::pair<IntegerVariable, IntegerValue>> terms;
245 
246  const int size = ct->vars.size();
247  for (int i = 0; i < size; ++i) {
248  if (VariableIsPositive(ct->vars[i])) {
249  terms.push_back({ct->vars[i], ct->coeffs[i]});
250  } else {
251  terms.push_back({NegationOf(ct->vars[i]), -ct->coeffs[i]});
252  }
253  }
254  std::sort(terms.begin(), terms.end());
255 
256  ct->vars.clear();
257  ct->coeffs.clear();
258  for (const auto& term : terms) {
259  ct->vars.push_back(term.first);
260  ct->coeffs.push_back(term.second);
261  }
262 }
263 
265  absl::flat_hash_set<IntegerVariable> seen_variables;
266  const int size = ct.vars.size();
267  for (int i = 0; i < size; ++i) {
268  if (VariableIsPositive(ct.vars[i])) {
269  if (!seen_variables.insert(ct.vars[i]).second) return false;
270  } else {
271  if (!seen_variables.insert(NegationOf(ct.vars[i])).second) return false;
272  }
273  }
274  return true;
275 }
276 
278  LinearExpression canonical_expr;
279  canonical_expr.offset = expr.offset;
280  for (int i = 0; i < expr.vars.size(); ++i) {
281  if (expr.coeffs[i] < 0) {
282  canonical_expr.vars.push_back(NegationOf(expr.vars[i]));
283  canonical_expr.coeffs.push_back(-expr.coeffs[i]);
284  } else {
285  canonical_expr.vars.push_back(expr.vars[i]);
286  canonical_expr.coeffs.push_back(expr.coeffs[i]);
287  }
288  }
289  return canonical_expr;
290 }
291 
292 IntegerValue LinExprLowerBound(const LinearExpression& expr,
293  const IntegerTrail& integer_trail) {
294  IntegerValue lower_bound = expr.offset;
295  for (int i = 0; i < expr.vars.size(); ++i) {
296  DCHECK_GE(expr.coeffs[i], 0) << "The expression is not canonicalized";
297  lower_bound += expr.coeffs[i] * integer_trail.LowerBound(expr.vars[i]);
298  }
299  return lower_bound;
300 }
301 
302 IntegerValue LinExprUpperBound(const LinearExpression& expr,
303  const IntegerTrail& integer_trail) {
304  IntegerValue upper_bound = expr.offset;
305  for (int i = 0; i < expr.vars.size(); ++i) {
306  DCHECK_GE(expr.coeffs[i], 0) << "The expression is not canonicalized";
307  upper_bound += expr.coeffs[i] * integer_trail.UpperBound(expr.vars[i]);
308  }
309  return upper_bound;
310 }
311 
313  LinearExpression result;
314  result.vars = NegationOf(expr.vars);
315  result.coeffs = expr.coeffs;
316  result.offset = -expr.offset;
317  return result;
318 }
319 
321  LinearExpression result;
322  result.offset = expr.offset;
323  for (int i = 0; i < expr.vars.size(); ++i) {
324  if (VariableIsPositive(expr.vars[i])) {
325  result.vars.push_back(expr.vars[i]);
326  result.coeffs.push_back(expr.coeffs[i]);
327  } else {
328  result.vars.push_back(NegationOf(expr.vars[i]));
329  result.coeffs.push_back(-expr.coeffs[i]);
330  }
331  }
332  return result;
333 }
334 
335 IntegerValue GetCoefficient(const IntegerVariable var,
336  const LinearExpression& expr) {
337  for (int i = 0; i < expr.vars.size(); ++i) {
338  if (expr.vars[i] == var) {
339  return expr.coeffs[i];
340  } else if (expr.vars[i] == NegationOf(var)) {
341  return -expr.coeffs[i];
342  }
343  }
344  return IntegerValue(0);
345 }
346 
347 IntegerValue GetCoefficientOfPositiveVar(const IntegerVariable var,
348  const LinearExpression& expr) {
350  for (int i = 0; i < expr.vars.size(); ++i) {
351  if (expr.vars[i] == var) {
352  return expr.coeffs[i];
353  }
354  }
355  return IntegerValue(0);
356 }
357 
358 } // namespace sat
359 } // namespace operations_research
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::sat::AffineExpression::constant
IntegerValue constant
Definition: integer.h:242
operations_research::sat::AffineExpression
Definition: integer.h:205
operations_research::sat::IntegerTrail
Definition: integer.h:533
operations_research::sat::kNoIntegerVariable
const IntegerVariable kNoIntegerVariable(-1)
operations_research::sat::CleanTermsAndFillConstraint
void CleanTermsAndFillConstraint(std::vector< std::pair< IntegerVariable, IntegerValue >> *terms, LinearConstraint *constraint)
Definition: linear_constraint.cc:82
operations_research::sat::ScalarProduct
double ScalarProduct(const LinearConstraint &constraint1, const LinearConstraint &constraint2)
Definition: linear_constraint.cc:149
operations_research::sat::FloorRatio
IntegerValue FloorRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:90
operations_research::sat::VariableIsPositive
bool VariableIsPositive(IntegerVariable i)
Definition: integer.h:130
max
int64 max
Definition: alldiff_cst.cc:139
operations_research::sat::LinearConstraint::vars
std::vector< IntegerVariable > vars
Definition: linear_constraint.h:42
operations_research::sat::LinearConstraintBuilder::Build
LinearConstraint Build()
Definition: linear_constraint.cc:113
operations_research::sat::CeilRatio
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:81
linear_constraint.h
operations_research::sat::IntegerEncoder::GetLiteralView
const IntegerVariable GetLiteralView(Literal lit) const
Definition: integer.h:420
operations_research::sat::NoDuplicateVariable
bool NoDuplicateVariable(const LinearConstraint &ct)
Definition: linear_constraint.cc:264
operations_research::sat::AffineExpression::coeff
IntegerValue coeff
Definition: integer.h:241
value
int64 value
Definition: demon_profiler.cc:43
operations_research::sat::LinExprUpperBound
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
Definition: linear_constraint.cc:302
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
operations_research::MathUtil::GCD64
static int64 GCD64(int64 x, int64 y)
Definition: mathutil.h:107
operations_research::sat::NegationOf
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:27
int64
int64_t int64
Definition: integral_types.h:34
operations_research::sat::Literal::Negated
Literal Negated() const
Definition: sat_base.h:91
operations_research::sat::LinearConstraintBuilder::AddTerm
void AddTerm(IntegerVariable var, IntegerValue coeff)
Definition: linear_constraint.cc:22
operations_research::sat::GetCoefficient
IntegerValue GetCoefficient(const IntegerVariable var, const LinearExpression &expr)
Definition: linear_constraint.cc:335
operations_research::sat::LinearConstraint
Definition: linear_constraint.h:39
operations_research::sat::IntTypeAbs
IntType IntTypeAbs(IntType t)
Definition: integer.h:77
operations_research::sat::IntegerTrail::UpperBound
IntegerValue UpperBound(IntegerVariable i) const
Definition: integer.h:1287
operations_research::sat::LinearExpression::offset
IntegerValue offset
Definition: linear_constraint.h:176
operations_research::sat::ComputeActivity
double ComputeActivity(const LinearConstraint &constraint, const absl::StrongVector< IntegerVariable, double > &values)
Definition: linear_constraint.cc:121
operations_research::sat::LinearConstraintBuilder::AddLiteralTerm
ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff)
Definition: linear_constraint.cc:52
operations_research::sat::kMaxIntegerValue
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
operations_research::sat::CanonicalizeExpr
LinearExpression CanonicalizeExpr(const LinearExpression &expr)
Definition: linear_constraint.cc:277
mathutil.h
operations_research::sat::LinearExpression
Definition: linear_constraint.h:173
operations_research::sat::LinearConstraint::lb
IntegerValue lb
Definition: linear_constraint.h:40
ct
const Constraint * ct
Definition: demon_profiler.cc:42
operations_research::sat::PositiveVarExpr
LinearExpression PositiveVarExpr(const LinearExpression &expr)
Definition: linear_constraint.cc:320
DCHECK
#define DCHECK(condition)
Definition: base/logging.h:884
operations_research::sat::LinExprLowerBound
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
Definition: linear_constraint.cc:292
operations_research::sat::MakeAllCoefficientsPositive
void MakeAllCoefficientsPositive(LinearConstraint *constraint)
Definition: linear_constraint.cc:215
operations_research::sat::GetCoefficientOfPositiveVar
IntegerValue GetCoefficientOfPositiveVar(const IntegerVariable var, const LinearExpression &expr)
Definition: linear_constraint.cc:347
operations_research::sat::ComputeL2Norm
double ComputeL2Norm(const LinearConstraint &constraint)
Definition: linear_constraint.cc:133
DCHECK_GE
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:889
operations_research::sat::Literal
Definition: sat_base.h:64
operations_research::sat::RemoveZeroTerms
void RemoveZeroTerms(LinearConstraint *constraint)
Definition: linear_constraint.cc:202
operations_research::sat::ToDouble
double ToDouble(IntegerValue value)
Definition: integer.h:69
absl::StrongVector< IntegerVariable, double >
operations_research::sat::kMinIntegerValue
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
operations_research::sat::MakeAllVariablesPositive
void MakeAllVariablesPositive(LinearConstraint *constraint)
Definition: linear_constraint.cc:226
operations_research::sat::LinearExpression::coeffs
std::vector< IntegerValue > coeffs
Definition: linear_constraint.h:175
operations_research::sat::LinearExpression::vars
std::vector< IntegerVariable > vars
Definition: linear_constraint.h:174
operations_research::sat::AffineExpression::var
IntegerVariable var
Definition: integer.h:240
operations_research::sat::IntegerTrail::LowerBound
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1283
operations_research::sat::ComputeInfinityNorm
IntegerValue ComputeInfinityNorm(const LinearConstraint &constraint)
Definition: linear_constraint.cc:141
operations_research::sat::LinearConstraint::coeffs
std::vector< IntegerValue > coeffs
Definition: linear_constraint.h:43
operations_research::sat::DivideByGCD
void DivideByGCD(LinearConstraint *constraint)
Definition: linear_constraint.cc:188
operations_research::sat::LinearConstraint::ub
IntegerValue ub
Definition: linear_constraint.h:41
operations_research::sat::LinearConstraintBuilder::AddConstant
void AddConstant(IntegerValue value)
Definition: linear_constraint.cc:47
CHECK
#define CHECK(condition)
Definition: base/logging.h:495
operations_research::sat::CanonicalizeConstraint
void CanonicalizeConstraint(LinearConstraint *ct)
Definition: linear_constraint.cc:243
integer.h