OR-Tools  8.0
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 
121 double ComputeActivity(const LinearConstraint& constraint,
123  double activity = 0;
124  for (int i = 0; i < constraint.vars.size(); ++i) {
125  const IntegerVariable var = constraint.vars[i];
126  const IntegerValue coeff = constraint.coeffs[i];
127  activity += coeff.value() * values[var];
128  }
129  return activity;
130 }
131 
132 double ComputeL2Norm(const LinearConstraint& constraint) {
133  double sum = 0.0;
134  for (const IntegerValue coeff : constraint.coeffs) {
135  sum += ToDouble(coeff) * ToDouble(coeff);
136  }
137  return std::sqrt(sum);
138 }
139 
140 IntegerValue ComputeInfinityNorm(const LinearConstraint& constraint) {
141  IntegerValue result(0);
142  for (const IntegerValue coeff : constraint.coeffs) {
143  result = std::max(result, IntTypeAbs(coeff));
144  }
145  return result;
146 }
147 
148 double ScalarProduct(const LinearConstraint& constraint1,
149  const LinearConstraint& constraint2) {
150  DCHECK(std::is_sorted(constraint1.vars.begin(), constraint1.vars.end()));
151  DCHECK(std::is_sorted(constraint2.vars.begin(), constraint2.vars.end()));
152  double scalar_product = 0.0;
153  int index_1 = 0;
154  int index_2 = 0;
155  while (index_1 < constraint1.vars.size() &&
156  index_2 < constraint2.vars.size()) {
157  if (constraint1.vars[index_1] == constraint2.vars[index_2]) {
158  scalar_product += ToDouble(constraint1.coeffs[index_1]) *
159  ToDouble(constraint2.coeffs[index_2]);
160  index_1++;
161  index_2++;
162  } else if (constraint1.vars[index_1] > constraint2.vars[index_2]) {
163  index_2++;
164  } else {
165  index_1++;
166  }
167  }
168  return scalar_product;
169 }
170 
171 namespace {
172 
173 // TODO(user): Template for any integer type and expose this?
174 IntegerValue ComputeGcd(const std::vector<IntegerValue>& values) {
175  if (values.empty()) return IntegerValue(1);
176  int64 gcd = 0;
177  for (const IntegerValue value : values) {
178  gcd = MathUtil::GCD64(gcd, std::abs(value.value()));
179  if (gcd == 1) break;
180  }
181  if (gcd < 0) return IntegerValue(1); // Can happen with kint64min.
182  return IntegerValue(gcd);
183 }
184 
185 } // namespace
186 
187 void DivideByGCD(LinearConstraint* constraint) {
188  if (constraint->coeffs.empty()) return;
189  const IntegerValue gcd = ComputeGcd(constraint->coeffs);
190  if (gcd == 1) return;
191 
192  if (constraint->lb > kMinIntegerValue) {
193  constraint->lb = CeilRatio(constraint->lb, gcd);
194  }
195  if (constraint->ub < kMaxIntegerValue) {
196  constraint->ub = FloorRatio(constraint->ub, gcd);
197  }
198  for (IntegerValue& coeff : constraint->coeffs) coeff /= gcd;
199 }
200 
202  int new_size = 0;
203  const int size = constraint->vars.size();
204  for (int i = 0; i < size; ++i) {
205  if (constraint->coeffs[i] == 0) continue;
206  constraint->vars[new_size] = constraint->vars[i];
207  constraint->coeffs[new_size] = constraint->coeffs[i];
208  ++new_size;
209  }
210  constraint->vars.resize(new_size);
211  constraint->coeffs.resize(new_size);
212 }
213 
215  const int size = constraint->vars.size();
216  for (int i = 0; i < size; ++i) {
217  const IntegerValue coeff = constraint->coeffs[i];
218  if (coeff < 0) {
219  constraint->coeffs[i] = -coeff;
220  constraint->vars[i] = NegationOf(constraint->vars[i]);
221  }
222  }
223 }
224 
226  const int size = constraint->vars.size();
227  for (int i = 0; i < size; ++i) {
228  const IntegerVariable var = constraint->vars[i];
229  if (!VariableIsPositive(var)) {
230  constraint->coeffs[i] = -constraint->coeffs[i];
231  constraint->vars[i] = NegationOf(var);
232  }
233  }
234 }
235 
236 // TODO(user): it would be better if LinearConstraint natively supported
237 // term and not two separated vectors. Fix?
238 //
239 // TODO(user): This is really similar to CleanTermsAndFillConstraint(), maybe
240 // we should just make the later switch negative variable to positive ones to
241 // avoid an extra linear scan on each new cuts.
243  std::vector<std::pair<IntegerVariable, IntegerValue>> terms;
244 
245  const int size = ct->vars.size();
246  for (int i = 0; i < size; ++i) {
247  if (VariableIsPositive(ct->vars[i])) {
248  terms.push_back({ct->vars[i], ct->coeffs[i]});
249  } else {
250  terms.push_back({NegationOf(ct->vars[i]), -ct->coeffs[i]});
251  }
252  }
253  std::sort(terms.begin(), terms.end());
254 
255  ct->vars.clear();
256  ct->coeffs.clear();
257  for (const auto& term : terms) {
258  ct->vars.push_back(term.first);
259  ct->coeffs.push_back(term.second);
260  }
261 }
262 
264  absl::flat_hash_set<IntegerVariable> seen_variables;
265  const int size = ct.vars.size();
266  for (int i = 0; i < size; ++i) {
267  if (VariableIsPositive(ct.vars[i])) {
268  if (!seen_variables.insert(ct.vars[i]).second) return false;
269  } else {
270  if (!seen_variables.insert(NegationOf(ct.vars[i])).second) return false;
271  }
272  }
273  return true;
274 }
275 
277  LinearExpression canonical_expr;
278  canonical_expr.offset = expr.offset;
279  for (int i = 0; i < expr.vars.size(); ++i) {
280  if (expr.coeffs[i] < 0) {
281  canonical_expr.vars.push_back(NegationOf(expr.vars[i]));
282  canonical_expr.coeffs.push_back(-expr.coeffs[i]);
283  } else {
284  canonical_expr.vars.push_back(expr.vars[i]);
285  canonical_expr.coeffs.push_back(expr.coeffs[i]);
286  }
287  }
288  return canonical_expr;
289 }
290 
291 IntegerValue LinExprLowerBound(const LinearExpression& expr,
292  const IntegerTrail& integer_trail) {
293  IntegerValue lower_bound = expr.offset;
294  for (int i = 0; i < expr.vars.size(); ++i) {
295  DCHECK_GE(expr.coeffs[i], 0) << "The expression is not canonicalized";
296  lower_bound += expr.coeffs[i] * integer_trail.LowerBound(expr.vars[i]);
297  }
298  return lower_bound;
299 }
300 
301 IntegerValue LinExprUpperBound(const LinearExpression& expr,
302  const IntegerTrail& integer_trail) {
303  IntegerValue upper_bound = expr.offset;
304  for (int i = 0; i < expr.vars.size(); ++i) {
305  DCHECK_GE(expr.coeffs[i], 0) << "The expression is not canonicalized";
306  upper_bound += expr.coeffs[i] * integer_trail.UpperBound(expr.vars[i]);
307  }
308  return upper_bound;
309 }
310 
312  LinearExpression result;
313  result.vars = NegationOf(expr.vars);
314  result.coeffs = expr.coeffs;
315  result.offset = -expr.offset;
316  return result;
317 }
318 
320  LinearExpression result;
321  result.offset = expr.offset;
322  for (int i = 0; i < expr.vars.size(); ++i) {
323  if (VariableIsPositive(expr.vars[i])) {
324  result.vars.push_back(expr.vars[i]);
325  result.coeffs.push_back(expr.coeffs[i]);
326  } else {
327  result.vars.push_back(NegationOf(expr.vars[i]));
328  result.coeffs.push_back(-expr.coeffs[i]);
329  }
330  }
331  return result;
332 }
333 
334 IntegerValue GetCoefficient(const IntegerVariable var,
335  const LinearExpression& expr) {
336  for (int i = 0; i < expr.vars.size(); ++i) {
337  if (expr.vars[i] == var) {
338  return expr.coeffs[i];
339  } else if (expr.vars[i] == NegationOf(var)) {
340  return -expr.coeffs[i];
341  }
342  }
343  return IntegerValue(0);
344 }
345 
346 IntegerValue GetCoefficientOfPositiveVar(const IntegerVariable var,
347  const LinearExpression& expr) {
348  CHECK(VariableIsPositive(var));
349  for (int i = 0; i < expr.vars.size(); ++i) {
350  if (expr.vars[i] == var) {
351  return expr.coeffs[i];
352  }
353  }
354  return IntegerValue(0);
355 }
356 
357 } // namespace sat
358 } // namespace operations_research
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::sat::AffineExpression::constant
IntegerValue constant
Definition: integer.h:227
operations_research::sat::AffineExpression
Definition: integer.h:203
operations_research::sat::IntegerTrail
Definition: integer.h:523
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:148
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
gtl::ITIVector< IntegerVariable, double >
operations_research::sat::IntegerEncoder::GetLiteralView
const IntegerVariable GetLiteralView(Literal lit) const
Definition: integer.h:411
operations_research::sat::NoDuplicateVariable
bool NoDuplicateVariable(const LinearConstraint &ct)
Definition: linear_constraint.cc:263
operations_research::sat::AffineExpression::coeff
IntegerValue coeff
Definition: integer.h:226
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:301
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:42
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:334
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:1232
operations_research::sat::LinearExpression::offset
IntegerValue offset
Definition: linear_constraint.h:175
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:276
mathutil.h
operations_research::sat::LinearExpression
Definition: linear_constraint.h:172
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:319
operations_research::sat::LinExprLowerBound
IntegerValue LinExprLowerBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
Definition: linear_constraint.cc:291
operations_research::sat::MakeAllCoefficientsPositive
void MakeAllCoefficientsPositive(LinearConstraint *constraint)
Definition: linear_constraint.cc:214
operations_research::sat::GetCoefficientOfPositiveVar
IntegerValue GetCoefficientOfPositiveVar(const IntegerVariable var, const LinearExpression &expr)
Definition: linear_constraint.cc:346
operations_research::sat::ComputeL2Norm
double ComputeL2Norm(const LinearConstraint &constraint)
Definition: linear_constraint.cc:132
operations_research::sat::Literal
Definition: sat_base.h:64
operations_research::sat::RemoveZeroTerms
void RemoveZeroTerms(LinearConstraint *constraint)
Definition: linear_constraint.cc:201
operations_research::sat::ToDouble
double ToDouble(IntegerValue value)
Definition: integer.h:69
operations_research::sat::kMinIntegerValue
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
operations_research::sat::MakeAllVariablesPositive
void MakeAllVariablesPositive(LinearConstraint *constraint)
Definition: linear_constraint.cc:225
operations_research::sat::ComputeActivity
double ComputeActivity(const LinearConstraint &constraint, const gtl::ITIVector< IntegerVariable, double > &values)
Definition: linear_constraint.cc:121
operations_research::sat::LinearExpression::coeffs
std::vector< IntegerValue > coeffs
Definition: linear_constraint.h:174
operations_research::sat::LinearExpression::vars
std::vector< IntegerVariable > vars
Definition: linear_constraint.h:173
operations_research::sat::AffineExpression::var
IntegerVariable var
Definition: integer.h:225
operations_research::sat::IntegerTrail::LowerBound
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1228
operations_research::sat::ComputeInfinityNorm
IntegerValue ComputeInfinityNorm(const LinearConstraint &constraint)
Definition: linear_constraint.cc:140
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:187
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
operations_research::sat::CanonicalizeConstraint
void CanonicalizeConstraint(LinearConstraint *ct)
Definition: linear_constraint.cc:242
integer.h