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