OR-Tools  8.1
linear_relaxation.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 <vector>
17 
18 #include "absl/container/flat_hash_set.h"
20 #include "ortools/base/stl_util.h"
23 #include "ortools/sat/integer.h"
27 #include "ortools/sat/sat_base.h"
29 
30 namespace operations_research {
31 namespace sat {
32 
33 bool AppendFullEncodingRelaxation(IntegerVariable var, const Model& model,
34  LinearRelaxation* relaxation) {
35  const auto* encoder = model.Get<IntegerEncoder>();
36  if (encoder == nullptr) return false;
37  if (!encoder->VariableIsFullyEncoded(var)) return false;
38 
39  const auto& encoding = encoder->FullDomainEncoding(var);
40  const IntegerValue var_min = model.Get<IntegerTrail>()->LowerBound(var);
41 
42  LinearConstraintBuilder at_least_one(&model, IntegerValue(1),
44  LinearConstraintBuilder encoding_ct(&model, var_min, var_min);
45  encoding_ct.AddTerm(var, IntegerValue(1));
46 
47  // Create the constraint if all literal have a view.
48  std::vector<Literal> at_most_one;
49 
50  for (const auto value_literal : encoding) {
51  const Literal lit = value_literal.literal;
52  const IntegerValue delta = value_literal.value - var_min;
53  DCHECK_GE(delta, IntegerValue(0));
54  at_most_one.push_back(lit);
55  if (!at_least_one.AddLiteralTerm(lit, IntegerValue(1))) return false;
56  if (delta != IntegerValue(0)) {
57  if (!encoding_ct.AddLiteralTerm(lit, -delta)) return false;
58  }
59  }
60 
61  relaxation->linear_constraints.push_back(at_least_one.Build());
62  relaxation->linear_constraints.push_back(encoding_ct.Build());
63  relaxation->at_most_ones.push_back(at_most_one);
64  return true;
65 }
66 
67 namespace {
68 
69 // TODO(user): Not super efficient.
70 std::pair<IntegerValue, IntegerValue> GetMinAndMaxNotEncoded(
71  IntegerVariable var,
72  const absl::flat_hash_set<IntegerValue>& encoded_values,
73  const Model& model) {
74  const auto* domains = model.Get<IntegerDomains>();
75  if (domains == nullptr || var >= domains->size()) {
77  }
78 
79  // The domain can be large, but the list of values shouldn't, so this
80  // runs in O(encoded_values.size());
81  IntegerValue min = kMaxIntegerValue;
82  for (const ClosedInterval interval : (*domains)[var]) {
83  for (IntegerValue v(interval.start); v <= interval.end; ++v) {
84  if (!gtl::ContainsKey(encoded_values, v)) {
85  min = v;
86  break;
87  }
88  }
89  if (min != kMaxIntegerValue) break;
90  }
91 
92  IntegerValue max = kMinIntegerValue;
93  const auto& domain = (*domains)[var];
94  for (int i = domain.NumIntervals() - 1; i >= 0; --i) {
95  const ClosedInterval interval = domain[i];
96  for (IntegerValue v(interval.end); v >= interval.start; --v) {
97  if (!gtl::ContainsKey(encoded_values, v)) {
98  max = v;
99  break;
100  }
101  }
102  if (max != kMinIntegerValue) break;
103  }
104 
105  return {min, max};
106 }
107 
108 } // namespace
109 
110 void AppendPartialEncodingRelaxation(IntegerVariable var, const Model& model,
111  LinearRelaxation* relaxation) {
112  const auto* encoder = model.Get<IntegerEncoder>();
113  const auto* integer_trail = model.Get<IntegerTrail>();
114  if (encoder == nullptr || integer_trail == nullptr) return;
115 
116  const std::vector<IntegerEncoder::ValueLiteralPair>& encoding =
117  encoder->PartialDomainEncoding(var);
118  if (encoding.empty()) return;
119 
120  std::vector<Literal> at_most_one_ct;
121  absl::flat_hash_set<IntegerValue> encoded_values;
122  for (const auto value_literal : encoding) {
123  const Literal literal = value_literal.literal;
124 
125  // Note that we skip pairs that do not have an Integer view.
126  if (encoder->GetLiteralView(literal) == kNoIntegerVariable &&
127  encoder->GetLiteralView(literal.Negated()) == kNoIntegerVariable) {
128  continue;
129  }
130 
131  at_most_one_ct.push_back(literal);
132  encoded_values.insert(value_literal.value);
133  }
134  if (encoded_values.empty()) return;
135 
136  // TODO(user): The PartialDomainEncoding() function automatically exclude
137  // values that are no longer in the initial domain, so we could be a bit
138  // tighter here. That said, this is supposed to be called just after the
139  // presolve, so it shouldn't really matter.
140  const auto pair = GetMinAndMaxNotEncoded(var, encoded_values, model);
141  if (pair.first == kMaxIntegerValue) {
142  // TODO(user): try to remove the duplication with
143  // AppendFullEncodingRelaxation()? actually I am not sure we need the other
144  // function since this one is just more general.
145  LinearConstraintBuilder exactly_one_ct(&model, IntegerValue(1),
146  IntegerValue(1));
147  LinearConstraintBuilder encoding_ct(&model, IntegerValue(0),
148  IntegerValue(0));
149  encoding_ct.AddTerm(var, IntegerValue(1));
150  for (const auto value_literal : encoding) {
151  const Literal lit = value_literal.literal;
152  CHECK(exactly_one_ct.AddLiteralTerm(lit, IntegerValue(1)));
153  CHECK(
154  encoding_ct.AddLiteralTerm(lit, IntegerValue(-value_literal.value)));
155  }
156  relaxation->linear_constraints.push_back(exactly_one_ct.Build());
157  relaxation->linear_constraints.push_back(encoding_ct.Build());
158  return;
159  }
160 
161  // min + sum li * (xi - min) <= var.
162  const IntegerValue d_min = pair.first;
163  LinearConstraintBuilder lower_bound_ct(&model, d_min, kMaxIntegerValue);
164  lower_bound_ct.AddTerm(var, IntegerValue(1));
165  for (const auto value_literal : encoding) {
166  CHECK(lower_bound_ct.AddLiteralTerm(value_literal.literal,
167  d_min - value_literal.value));
168  }
169 
170  // var <= max + sum li * (xi - max).
171  const IntegerValue d_max = pair.second;
172  LinearConstraintBuilder upper_bound_ct(&model, kMinIntegerValue, d_max);
173  upper_bound_ct.AddTerm(var, IntegerValue(1));
174  for (const auto value_literal : encoding) {
175  CHECK(upper_bound_ct.AddLiteralTerm(value_literal.literal,
176  d_max - value_literal.value));
177  }
178 
179  // Note that empty/trivial constraints will be filtered later.
180  relaxation->at_most_ones.push_back(at_most_one_ct);
181  relaxation->linear_constraints.push_back(lower_bound_ct.Build());
182  relaxation->linear_constraints.push_back(upper_bound_ct.Build());
183 }
184 
186  const Model& model,
187  LinearRelaxation* relaxation) {
188  const auto* integer_trail = model.Get<IntegerTrail>();
189  const auto* encoder = model.Get<IntegerEncoder>();
190  if (integer_trail == nullptr || encoder == nullptr) return;
191 
192  const std::map<IntegerValue, Literal>& greater_than_encoding =
193  encoder->PartialGreaterThanEncoding(var);
194  if (greater_than_encoding.empty()) return;
195 
196  // Start by the var >= side.
197  // And also add the implications between used literals.
198  {
199  IntegerValue prev_used_bound = integer_trail->LowerBound(var);
200  LinearConstraintBuilder lb_constraint(&model, prev_used_bound,
202  lb_constraint.AddTerm(var, IntegerValue(1));
203  LiteralIndex prev_literal_index = kNoLiteralIndex;
204  for (const auto entry : greater_than_encoding) {
205  if (entry.first <= prev_used_bound) continue;
206 
207  const LiteralIndex literal_index = entry.second.Index();
208  const IntegerValue diff = prev_used_bound - entry.first;
209 
210  // Skip the entry if the literal doesn't have a view.
211  if (!lb_constraint.AddLiteralTerm(entry.second, diff)) continue;
212  if (prev_literal_index != kNoLiteralIndex) {
213  // Add var <= prev_var, which is the same as var + not(prev_var) <= 1
214  relaxation->at_most_ones.push_back(
215  {Literal(literal_index), Literal(prev_literal_index).Negated()});
216  }
217  prev_used_bound = entry.first;
218  prev_literal_index = literal_index;
219  }
220  relaxation->linear_constraints.push_back(lb_constraint.Build());
221  }
222 
223  // Do the same for the var <= side by using NegationOfVar().
224  // Note that we do not need to add the implications between literals again.
225  {
226  IntegerValue prev_used_bound = integer_trail->LowerBound(NegationOf(var));
227  LinearConstraintBuilder lb_constraint(&model, prev_used_bound,
229  lb_constraint.AddTerm(var, IntegerValue(-1));
230  for (const auto entry :
231  encoder->PartialGreaterThanEncoding(NegationOf(var))) {
232  if (entry.first <= prev_used_bound) continue;
233  const IntegerValue diff = prev_used_bound - entry.first;
234 
235  // Skip the entry if the literal doesn't have a view.
236  if (!lb_constraint.AddLiteralTerm(entry.second, diff)) continue;
237  prev_used_bound = entry.first;
238  }
239  relaxation->linear_constraints.push_back(lb_constraint.Build());
240  }
241 }
242 
243 namespace {
244 // Adds enforcing_lit => target <= bounding_var to relaxation.
245 void AppendEnforcedUpperBound(const Literal enforcing_lit,
246  const IntegerVariable target,
247  const IntegerVariable bounding_var, Model* model,
248  LinearRelaxation* relaxation) {
249  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
250  const IntegerValue max_target_value = integer_trail->UpperBound(target);
251  const IntegerValue min_var_value = integer_trail->LowerBound(bounding_var);
252  const IntegerValue max_term_value = max_target_value - min_var_value;
253  LinearConstraintBuilder lc(model, kMinIntegerValue, max_term_value);
254  lc.AddTerm(target, IntegerValue(1));
255  lc.AddTerm(bounding_var, IntegerValue(-1));
256  CHECK(lc.AddLiteralTerm(enforcing_lit, max_term_value));
257  relaxation->linear_constraints.push_back(lc.Build());
258 }
259 
260 // Adds {enforcing_lits} => rhs_domain_min <= expr <= rhs_domain_max.
261 // Requires expr offset to be 0.
262 void AppendEnforcedLinearExpression(
263  const std::vector<Literal>& enforcing_literals,
264  const LinearExpression& expr, const IntegerValue rhs_domain_min,
265  const IntegerValue rhs_domain_max, const Model& model,
266  LinearRelaxation* relaxation) {
267  CHECK_EQ(expr.offset, IntegerValue(0));
268  const LinearExpression canonical_expr = CanonicalizeExpr(expr);
269  const IntegerTrail* integer_trail = model.Get<IntegerTrail>();
270  const IntegerValue min_expr_value =
271  LinExprLowerBound(canonical_expr, *integer_trail);
272 
273  if (rhs_domain_min > min_expr_value) {
274  // And(ei) => terms >= rhs_domain_min
275  // <=> Sum_i (~ei * (rhs_domain_min - min_expr_value)) + terms >=
276  // rhs_domain_min
277  LinearConstraintBuilder lc(&model, rhs_domain_min, kMaxIntegerValue);
278  for (const Literal& literal : enforcing_literals) {
279  CHECK(lc.AddLiteralTerm(literal.Negated(),
280  rhs_domain_min - min_expr_value));
281  }
282  for (int i = 0; i < canonical_expr.vars.size(); i++) {
283  lc.AddTerm(canonical_expr.vars[i], canonical_expr.coeffs[i]);
284  }
285  relaxation->linear_constraints.push_back(lc.Build());
286  }
287  const IntegerValue max_expr_value =
288  LinExprUpperBound(canonical_expr, *integer_trail);
289  if (rhs_domain_max < max_expr_value) {
290  // And(ei) => terms <= rhs_domain_max
291  // <=> Sum_i (~ei * (rhs_domain_max - max_expr_value)) + terms <=
292  // rhs_domain_max
293  LinearConstraintBuilder lc(&model, kMinIntegerValue, rhs_domain_max);
294  for (const Literal& literal : enforcing_literals) {
295  CHECK(lc.AddLiteralTerm(literal.Negated(),
296  rhs_domain_max - max_expr_value));
297  }
298  for (int i = 0; i < canonical_expr.vars.size(); i++) {
299  lc.AddTerm(canonical_expr.vars[i], canonical_expr.coeffs[i]);
300  }
301  relaxation->linear_constraints.push_back(lc.Build());
302  }
303 }
304 
305 } // namespace
306 
307 // Add a linear relaxation of the CP constraint to the set of linear
308 // constraints. The highest linearization_level is, the more types of constraint
309 // we encode. This method should be called only for linearization_level > 0.
310 //
311 // Note: IntProd is linearized dynamically using the cut generators.
312 //
313 // TODO(user): In full generality, we could encode all the constraint as an LP.
314 // TODO(user,user): Add unit tests for this method.
315 void TryToLinearizeConstraint(const CpModelProto& model_proto,
316  const ConstraintProto& ct, Model* model,
317  int linearization_level,
318  LinearRelaxation* relaxation) {
319  CHECK_EQ(model->GetOrCreate<SatSolver>()->CurrentDecisionLevel(), 0);
320  DCHECK_GT(linearization_level, 0);
321  auto* mapping = model->GetOrCreate<CpModelMapping>();
322  if (ct.constraint_case() == ConstraintProto::ConstraintCase::kBoolOr) {
323  if (linearization_level < 2) return;
324  LinearConstraintBuilder lc(model, IntegerValue(1), kMaxIntegerValue);
325  for (const int enforcement_ref : ct.enforcement_literal()) {
326  CHECK(lc.AddLiteralTerm(mapping->Literal(NegatedRef(enforcement_ref)),
327  IntegerValue(1)));
328  }
329  for (const int ref : ct.bool_or().literals()) {
330  CHECK(lc.AddLiteralTerm(mapping->Literal(ref), IntegerValue(1)));
331  }
332  relaxation->linear_constraints.push_back(lc.Build());
333  } else if (ct.constraint_case() ==
334  ConstraintProto::ConstraintCase::kBoolAnd) {
335  // TODO(user): These constraints can be many, and if they are not regrouped
336  // in big at most ones, then they should probably only added lazily as cuts.
337  // Regroup this with future clique-cut separation logic.
338  if (linearization_level < 2) return;
339  if (!HasEnforcementLiteral(ct)) return;
340  if (ct.enforcement_literal().size() == 1) {
341  const Literal enforcement = mapping->Literal(ct.enforcement_literal(0));
342  for (const int ref : ct.bool_and().literals()) {
343  relaxation->at_most_ones.push_back(
344  {enforcement, mapping->Literal(ref).Negated()});
345  }
346  return;
347  }
348 
349  // Andi(e_i) => Andj(x_j)
350  // <=> num_rhs_terms <= Sum_j(x_j) + num_rhs_terms * Sum_i(~e_i)
351  int num_literals = ct.bool_and().literals_size();
352  LinearConstraintBuilder lc(model, IntegerValue(num_literals),
354  for (const int ref : ct.bool_and().literals()) {
355  CHECK(lc.AddLiteralTerm(mapping->Literal(ref), IntegerValue(1)));
356  }
357  for (const int enforcement_ref : ct.enforcement_literal()) {
358  CHECK(lc.AddLiteralTerm(mapping->Literal(NegatedRef(enforcement_ref)),
359  IntegerValue(num_literals)));
360  }
361  relaxation->linear_constraints.push_back(lc.Build());
362  } else if (ct.constraint_case() ==
363  ConstraintProto::ConstraintCase::kAtMostOne) {
364  if (HasEnforcementLiteral(ct)) return;
365  std::vector<Literal> at_most_one;
366  for (const int ref : ct.at_most_one().literals()) {
367  at_most_one.push_back(mapping->Literal(ref));
368  }
369  relaxation->at_most_ones.push_back(at_most_one);
370  } else if (ct.constraint_case() == ConstraintProto::ConstraintCase::kIntMax) {
371  if (HasEnforcementLiteral(ct)) return;
372  const IntegerVariable target = mapping->Integer(ct.int_max().target());
373  const std::vector<IntegerVariable> vars =
374  mapping->Integers(ct.int_max().vars());
375  AppendMaxRelaxation(target, vars, linearization_level, model, relaxation);
376 
377  } else if (ct.constraint_case() == ConstraintProto::ConstraintCase::kIntMin) {
378  if (HasEnforcementLiteral(ct)) return;
379  const IntegerVariable negative_target =
380  NegationOf(mapping->Integer(ct.int_min().target()));
381  const std::vector<IntegerVariable> negative_vars =
382  NegationOf(mapping->Integers(ct.int_min().vars()));
383  AppendMaxRelaxation(negative_target, negative_vars, linearization_level,
384  model, relaxation);
385  } else if (ct.constraint_case() == ConstraintProto::ConstraintCase::kLinear) {
386  AppendLinearConstraintRelaxation(ct, linearization_level, *model,
387  relaxation);
388  } else if (ct.constraint_case() ==
389  ConstraintProto::ConstraintCase::kCircuit) {
390  if (HasEnforcementLiteral(ct)) return;
391  const int num_arcs = ct.circuit().literals_size();
392  CHECK_EQ(num_arcs, ct.circuit().tails_size());
393  CHECK_EQ(num_arcs, ct.circuit().heads_size());
394 
395  // Each node must have exactly one incoming and one outgoing arc (note that
396  // it can be the unique self-arc of this node too).
397  std::map<int, std::vector<Literal>> incoming_arc_constraints;
398  std::map<int, std::vector<Literal>> outgoing_arc_constraints;
399  for (int i = 0; i < num_arcs; i++) {
400  const Literal arc = mapping->Literal(ct.circuit().literals(i));
401  const int tail = ct.circuit().tails(i);
402  const int head = ct.circuit().heads(i);
403 
404  // Make sure this literal has a view.
406  outgoing_arc_constraints[tail].push_back(arc);
407  incoming_arc_constraints[head].push_back(arc);
408  }
409  for (const auto* node_map :
410  {&outgoing_arc_constraints, &incoming_arc_constraints}) {
411  for (const auto& entry : *node_map) {
412  const std::vector<Literal>& exactly_one = entry.second;
413  if (exactly_one.size() > 1) {
414  LinearConstraintBuilder at_least_one_lc(model, IntegerValue(1),
416  for (const Literal l : exactly_one) {
417  CHECK(at_least_one_lc.AddLiteralTerm(l, IntegerValue(1)));
418  }
419 
420  // We separate the two constraints.
421  relaxation->at_most_ones.push_back(exactly_one);
422  relaxation->linear_constraints.push_back(at_least_one_lc.Build());
423  }
424  }
425  }
426  } else if (ct.constraint_case() ==
427  ConstraintProto::ConstraintCase::kElement) {
428  const IntegerVariable index = mapping->Integer(ct.element().index());
429  const IntegerVariable target = mapping->Integer(ct.element().target());
430  const std::vector<IntegerVariable> vars =
431  mapping->Integers(ct.element().vars());
432 
433  // We only relax the case where all the vars are constant.
434  // target = sum (index == i) * fixed_vars[i].
435  LinearConstraintBuilder constraint(model, IntegerValue(0), IntegerValue(0));
436  constraint.AddTerm(target, IntegerValue(-1));
437  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
438  for (const auto literal_value : model->Add(FullyEncodeVariable((index)))) {
439  const IntegerVariable var = vars[literal_value.value.value()];
440  if (!model->Get(IsFixed(var))) return;
441 
442  // Make sure this literal has a view.
443  model->Add(NewIntegerVariableFromLiteral(literal_value.literal));
444  CHECK(constraint.AddLiteralTerm(literal_value.literal,
445  integer_trail->LowerBound(var)));
446  }
447 
448  relaxation->linear_constraints.push_back(constraint.Build());
449  } else if (ct.constraint_case() ==
450  ConstraintProto::ConstraintCase::kInterval) {
451  if (linearization_level < 2) return;
452  const IntegerVariable start = mapping->Integer(ct.interval().start());
453  const IntegerVariable size = mapping->Integer(ct.interval().size());
454  const IntegerVariable end = mapping->Integer(ct.interval().end());
455  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
456  const bool size_is_fixed = integer_trail->IsFixed(size);
457  const IntegerValue rhs =
458  size_is_fixed ? -integer_trail->LowerBound(size) : IntegerValue(0);
459  LinearConstraintBuilder lc(model, rhs, rhs);
460  lc.AddTerm(start, IntegerValue(1));
461  if (!size_is_fixed) {
462  lc.AddTerm(size, IntegerValue(1));
463  }
464  lc.AddTerm(end, IntegerValue(-1));
465  if (HasEnforcementLiteral(ct)) {
466  LinearConstraint tmp_lc = lc.Build();
467  LinearExpression expr;
468  expr.coeffs = tmp_lc.coeffs;
469  expr.vars = tmp_lc.vars;
470  AppendEnforcedLinearExpression(
471  mapping->Literals(ct.enforcement_literal()), expr, tmp_lc.ub,
472  tmp_lc.ub, *model, relaxation);
473  } else {
474  relaxation->linear_constraints.push_back(lc.Build());
475  }
476  } else if (ct.constraint_case() ==
477  ConstraintProto::ConstraintCase::kNoOverlap) {
478  AppendNoOverlapRelaxation(model_proto, ct, linearization_level, model,
479  relaxation);
480  } else if (ct.constraint_case() ==
481  ConstraintProto::ConstraintCase::kCumulative) {
482  AppendCumulativeRelaxation(model_proto, ct, linearization_level, model,
483  relaxation);
484  }
485 }
486 
487 void AddCumulativeCut(const std::vector<IntervalVariable>& intervals,
488  const std::vector<IntegerVariable>& demands,
489  IntegerValue capacity_lower_bound, Model* model,
490  LinearRelaxation* relaxation) {
491  SchedulingConstraintHelper helper(intervals, model);
492  const int num_intervals = helper.NumTasks();
493 
494  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
495 
496  IntegerValue min_of_starts = kMaxIntegerValue;
497  IntegerValue max_of_ends = kMinIntegerValue;
498 
499  int num_variable_sizes = 0;
500  int num_optionals = 0;
501 
502  for (int index = 0; index < num_intervals; ++index) {
503  min_of_starts = std::min(min_of_starts, helper.StartMin(index));
504  max_of_ends = std::max(max_of_ends, helper.EndMax(index));
505 
506  if (helper.IsOptional(index)) {
507  num_optionals++;
508  }
509 
510  if (!helper.SizeIsFixed(index) ||
511  (!demands.empty() && !integer_trail->IsFixed(demands[index]))) {
512  num_variable_sizes++;
513  }
514  }
515 
516  VLOG(2) << "Span [" << min_of_starts << ".." << max_of_ends << "] with "
517  << num_optionals << " optional intervals, and " << num_variable_sizes
518  << " variable size intervals out of " << num_intervals
519  << " intervals";
520 
521  if (num_variable_sizes + num_optionals == 0) return;
522 
523  const IntegerVariable span_start =
524  integer_trail->AddIntegerVariable(min_of_starts, max_of_ends);
525  const IntegerVariable span_size = integer_trail->AddIntegerVariable(
526  IntegerValue(0), max_of_ends - min_of_starts);
527  const IntegerVariable span_end =
528  integer_trail->AddIntegerVariable(min_of_starts, max_of_ends);
529 
530  IntervalVariable span_var;
531  if (num_optionals < num_intervals) {
532  span_var = model->Add(NewInterval(span_start, span_end, span_size));
533  } else {
534  const Literal span_lit = Literal(model->Add(NewBooleanVariable()), true);
535  span_var = model->Add(
536  NewOptionalInterval(span_start, span_end, span_size, span_lit));
537  }
538 
539  model->Add(SpanOfIntervals(span_var, intervals));
540 
541  LinearConstraintBuilder lc(model, kMinIntegerValue, IntegerValue(0));
542  lc.AddTerm(span_size, -capacity_lower_bound);
543  for (int i = 0; i < num_intervals; ++i) {
544  const IntegerValue demand_lower_bound =
545  demands.empty() ? IntegerValue(1)
546  : integer_trail->LowerBound(demands[i]);
547  const bool demand_is_fixed =
548  demands.empty() || integer_trail->IsFixed(demands[i]);
549  if (!helper.IsOptional(i)) {
550  if (helper.SizeIsFixed(i) && !demands.empty()) {
551  lc.AddTerm(demands[i], helper.SizeMin(i));
552  } else if (demand_is_fixed) {
553  lc.AddTerm(helper.SizeVars()[i], demand_lower_bound);
554  } else { // demand and size are not fixed.
555  DCHECK(!demands.empty());
556  // We use McCormick equation.
557  // demand * size = (demand_min + delta_d) * (size_min + delta_s) =
558  // demand_min * size_min + delta_d * size_min +
559  // delta_s * demand_min + delta_s * delta_d
560  // which is >= (by ignoring the quatratic term)
561  // demand_min * size + size_min * demand - demand_min * size_min
562  lc.AddTerm(helper.SizeVars()[i], demand_lower_bound);
563  lc.AddTerm(demands[i], helper.SizeMin(i));
564  lc.AddConstant(-helper.SizeMin(i) * demand_lower_bound);
565  }
566  } else {
567  if (!lc.AddLiteralTerm(helper.PresenceLiteral(i),
568  helper.SizeMin(i) * demand_lower_bound)) {
569  return;
570  }
571  }
572  }
573  relaxation->linear_constraints.push_back(lc.Build());
574 }
575 
576 void AppendCumulativeRelaxation(const CpModelProto& model_proto,
577  const ConstraintProto& ct,
578  int linearization_level, Model* model,
579  LinearRelaxation* relaxation) {
580  CHECK(ct.has_cumulative());
581  if (linearization_level < 2) return;
582  if (HasEnforcementLiteral(ct)) return;
583 
584  auto* mapping = model->GetOrCreate<CpModelMapping>();
585  const std::vector<IntegerVariable> demands =
586  mapping->Integers(ct.cumulative().demands());
587  std::vector<IntervalVariable> intervals =
588  mapping->Intervals(ct.cumulative().intervals());
589  const IntegerValue capacity_lower_bound =
590  model->GetOrCreate<IntegerTrail>()->LowerBound(
591  mapping->Integer(ct.cumulative().capacity()));
592  AddCumulativeCut(intervals, demands, capacity_lower_bound, model, relaxation);
593 }
594 
595 void AppendNoOverlapRelaxation(const CpModelProto& model_proto,
596  const ConstraintProto& ct,
597  int linearization_level, Model* model,
598  LinearRelaxation* relaxation) {
599  CHECK(ct.has_no_overlap());
600  if (linearization_level < 2) return;
601  if (HasEnforcementLiteral(ct)) return;
602 
603  auto* mapping = model->GetOrCreate<CpModelMapping>();
604  std::vector<IntervalVariable> intervals =
605  mapping->Intervals(ct.no_overlap().intervals());
606  AddCumulativeCut(intervals, /*demands=*/{},
607  /*capacity_lower_bound=*/IntegerValue(1), model, relaxation);
608 }
609 
610 void AppendMaxRelaxation(IntegerVariable target,
611  const std::vector<IntegerVariable>& vars,
612  int linearization_level, Model* model,
613  LinearRelaxation* relaxation) {
614  // Case X = max(X_1, X_2, ..., X_N)
615  // Part 1: Encode X >= max(X_1, X_2, ..., X_N)
616  for (const IntegerVariable var : vars) {
617  // This deal with the corner case X = max(X, Y, Z, ..) !
618  // Note that this can be presolved into X >= Y, X >= Z, ...
619  if (target == var) continue;
620  LinearConstraintBuilder lc(model, kMinIntegerValue, IntegerValue(0));
621  lc.AddTerm(var, IntegerValue(1));
622  lc.AddTerm(target, IntegerValue(-1));
623  relaxation->linear_constraints.push_back(lc.Build());
624  }
625 
626  // Part 2: Encode upper bound on X.
627  if (linearization_level < 2) return;
628  GenericLiteralWatcher* watcher = model->GetOrCreate<GenericLiteralWatcher>();
629  // For size = 2, we do this with 1 less variable.
630  IntegerEncoder* encoder = model->GetOrCreate<IntegerEncoder>();
631  if (vars.size() == 2) {
632  IntegerVariable y = model->Add(NewIntegerVariable(0, 1));
633  const Literal y_lit =
634  encoder->GetOrCreateLiteralAssociatedToEquality(y, IntegerValue(1));
635  AppendEnforcedUpperBound(y_lit, target, vars[0], model, relaxation);
636 
637  // TODO(user,user): It makes more sense to use ConditionalLowerOrEqual()
638  // here, but that degrades perf on the road*.fzn problem. Understand why.
639  IntegerSumLE* upper_bound1 = new IntegerSumLE(
640  {y_lit}, {target, vars[0]}, {IntegerValue(1), IntegerValue(-1)},
641  IntegerValue(0), model);
642  upper_bound1->RegisterWith(watcher);
643  model->TakeOwnership(upper_bound1);
644  AppendEnforcedUpperBound(y_lit.Negated(), target, vars[1], model,
645  relaxation);
646  IntegerSumLE* upper_bound2 = new IntegerSumLE(
647  {y_lit.Negated()}, {target, vars[1]},
648  {IntegerValue(1), IntegerValue(-1)}, IntegerValue(0), model);
649  upper_bound2->RegisterWith(watcher);
650  model->TakeOwnership(upper_bound2);
651  return;
652  }
653  // For each X_i, we encode y_i => X <= X_i. And at least one of the y_i is
654  // true. Note that the correct y_i will be chosen because of the first part in
655  // linearlization (X >= X_i).
656  // TODO(user): Only lower bound is needed, experiment.
657  LinearConstraintBuilder lc_exactly_one(model, IntegerValue(1),
658  IntegerValue(1));
659  std::vector<Literal> exactly_one_literals;
660  exactly_one_literals.reserve(vars.size());
661  for (const IntegerVariable var : vars) {
662  if (target == var) continue;
663  // y => X <= X_i.
664  // <=> max_term_value * y + X - X_i <= max_term_value.
665  // where max_tern_value is X_ub - X_i_lb.
666  IntegerVariable y = model->Add(NewIntegerVariable(0, 1));
667  const Literal y_lit =
668  encoder->GetOrCreateLiteralAssociatedToEquality(y, IntegerValue(1));
669 
670  AppendEnforcedUpperBound(y_lit, target, var, model, relaxation);
671  IntegerSumLE* upper_bound_constraint = new IntegerSumLE(
672  {y_lit}, {target, var}, {IntegerValue(1), IntegerValue(-1)},
673  IntegerValue(0), model);
674  upper_bound_constraint->RegisterWith(watcher);
675  model->TakeOwnership(upper_bound_constraint);
676  exactly_one_literals.push_back(y_lit);
677 
678  CHECK(lc_exactly_one.AddLiteralTerm(y_lit, IntegerValue(1)));
679  }
680  model->Add(ExactlyOneConstraint(exactly_one_literals));
681  relaxation->linear_constraints.push_back(lc_exactly_one.Build());
682 }
683 
684 std::vector<IntegerVariable> AppendLinMaxRelaxation(
685  IntegerVariable target, const std::vector<LinearExpression>& exprs,
686  Model* model, LinearRelaxation* relaxation) {
687  // We want to linearize X = max(exprs[1], exprs[2], ..., exprs[d]).
688  // Part 1: Encode X >= max(exprs[1], exprs[2], ..., exprs[d])
689  for (const LinearExpression& expr : exprs) {
691  for (int i = 0; i < expr.vars.size(); ++i) {
692  lc.AddTerm(expr.vars[i], expr.coeffs[i]);
693  }
694  lc.AddTerm(target, IntegerValue(-1));
695  relaxation->linear_constraints.push_back(lc.Build());
696  }
697 
698  // Part 2: Encode upper bound on X.
699 
700  // Add linking constraint to the CP solver
701  // sum zi = 1 and for all i, zi => max = expr_i.
702  const int num_exprs = exprs.size();
703  IntegerEncoder* encoder = model->GetOrCreate<IntegerEncoder>();
704  GenericLiteralWatcher* watcher = model->GetOrCreate<GenericLiteralWatcher>();
705 
706  // TODO(user): For the case where num_exprs = 2, Create only one z var.
707  std::vector<IntegerVariable> z_vars;
708  std::vector<Literal> z_lits;
709  z_vars.reserve(num_exprs);
710  z_lits.reserve(num_exprs);
711  LinearConstraintBuilder lc_exactly_one(model, IntegerValue(1),
712  IntegerValue(1));
713  std::vector<Literal> exactly_one_literals;
714  for (int i = 0; i < num_exprs; ++i) {
715  IntegerVariable z = model->Add(NewIntegerVariable(0, 1));
716  z_vars.push_back(z);
717  const Literal z_lit =
718  encoder->GetOrCreateLiteralAssociatedToEquality(z, IntegerValue(1));
719  z_lits.push_back(z_lit);
720  LinearExpression local_expr;
721  local_expr.vars = NegationOf(exprs[i].vars);
722  local_expr.vars.push_back(target);
723  local_expr.coeffs = exprs[i].coeffs;
724  local_expr.coeffs.push_back(IntegerValue(1));
725  IntegerSumLE* upper_bound = new IntegerSumLE(
726  {z_lit}, local_expr.vars, local_expr.coeffs, exprs[i].offset, model);
727  upper_bound->RegisterWith(watcher);
728  model->TakeOwnership(upper_bound);
729 
730  CHECK(lc_exactly_one.AddLiteralTerm(z_lit, IntegerValue(1)));
731  }
732  model->Add(ExactlyOneConstraint(z_lits));
733 
734  // For the relaxation, we use different constraints with a stronger linear
735  // relaxation as explained in the .h
736  // TODO(user): Consider passing the x_vars to this method instead of
737  // computing it here.
738  std::vector<IntegerVariable> x_vars;
739  for (int i = 0; i < num_exprs; ++i) {
740  x_vars.insert(x_vars.end(), exprs[i].vars.begin(), exprs[i].vars.end());
741  }
743  // All expressions should only contain positive variables.
744  DCHECK(std::all_of(x_vars.begin(), x_vars.end(), [](IntegerVariable var) {
745  return VariableIsPositive(var);
746  }));
747 
748  std::vector<std::vector<IntegerValue>> sum_of_max_corner_diff(
749  num_exprs, std::vector<IntegerValue>(num_exprs, IntegerValue(0)));
750 
751  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
752  for (int i = 0; i < num_exprs; ++i) {
753  for (int j = 0; j < num_exprs; ++j) {
754  if (i == j) continue;
755  for (const IntegerVariable x_var : x_vars) {
756  const IntegerValue lb = integer_trail->LevelZeroLowerBound(x_var);
757  const IntegerValue ub = integer_trail->LevelZeroUpperBound(x_var);
758  const IntegerValue diff =
759  GetCoefficient(x_var, exprs[j]) - GetCoefficient(x_var, exprs[i]);
760  sum_of_max_corner_diff[i][j] += std::max(diff * lb, diff * ub);
761  }
762  }
763  }
764  for (int i = 0; i < num_exprs; ++i) {
765  LinearConstraintBuilder lc(model, kMinIntegerValue, IntegerValue(0));
766  lc.AddTerm(target, IntegerValue(1));
767  for (int j = 0; j < exprs[i].vars.size(); ++j) {
768  lc.AddTerm(exprs[i].vars[j], -exprs[i].coeffs[j]);
769  }
770  for (int j = 0; j < num_exprs; ++j) {
771  CHECK(lc.AddLiteralTerm(z_lits[j],
772  -exprs[j].offset - sum_of_max_corner_diff[i][j]));
773  }
774  relaxation->linear_constraints.push_back(lc.Build());
775  }
776 
777  relaxation->linear_constraints.push_back(lc_exactly_one.Build());
778  return z_vars;
779 }
780 
781 void AppendLinearConstraintRelaxation(const ConstraintProto& constraint_proto,
782  const int linearization_level,
783  const Model& model,
784  LinearRelaxation* relaxation) {
785  auto* mapping = model.Get<CpModelMapping>();
786 
787  // Note that we ignore the holes in the domain.
788  //
789  // TODO(user): In LoadLinearConstraint() we already created intermediate
790  // Booleans for each disjoint interval, we should reuse them here if
791  // possible.
792  //
793  // TODO(user): process the "at most one" part of a == 1 separately?
794  const IntegerValue rhs_domain_min =
795  IntegerValue(constraint_proto.linear().domain(0));
796  const IntegerValue rhs_domain_max =
797  IntegerValue(constraint_proto.linear().domain(
798  constraint_proto.linear().domain_size() - 1));
799  if (rhs_domain_min == kint64min && rhs_domain_max == kint64max) return;
800 
801  if (!HasEnforcementLiteral(constraint_proto)) {
802  LinearConstraintBuilder lc(&model, rhs_domain_min, rhs_domain_max);
803  for (int i = 0; i < constraint_proto.linear().vars_size(); i++) {
804  const int ref = constraint_proto.linear().vars(i);
805  const int64 coeff = constraint_proto.linear().coeffs(i);
806  lc.AddTerm(mapping->Integer(ref), IntegerValue(coeff));
807  }
808  relaxation->linear_constraints.push_back(lc.Build());
809  return;
810  }
811 
812  // Reified version.
813  if (linearization_level < 2) return;
814 
815  // We linearize fully reified constraints of size 1 all together for a given
816  // variable. But we need to process half-reified ones.
817  if (!mapping->IsHalfEncodingConstraint(&constraint_proto) &&
818  constraint_proto.linear().vars_size() <= 1) {
819  return;
820  }
821 
822  std::vector<Literal> enforcing_literals;
823  enforcing_literals.reserve(constraint_proto.enforcement_literal_size());
824  for (const int enforcement_ref : constraint_proto.enforcement_literal()) {
825  enforcing_literals.push_back(mapping->Literal(enforcement_ref));
826  }
827  LinearExpression expr;
828  expr.vars.reserve(constraint_proto.linear().vars_size());
829  expr.coeffs.reserve(constraint_proto.linear().vars_size());
830  for (int i = 0; i < constraint_proto.linear().vars_size(); i++) {
831  int ref = constraint_proto.linear().vars(i);
832  IntegerValue coeff(constraint_proto.linear().coeffs(i));
833  if (!RefIsPositive(ref)) {
834  ref = PositiveRef(ref);
835  coeff = -coeff;
836  }
837  const IntegerVariable int_var = mapping->Integer(ref);
838  expr.vars.push_back(int_var);
839  expr.coeffs.push_back(coeff);
840  }
841  AppendEnforcedLinearExpression(enforcing_literals, expr, rhs_domain_min,
842  rhs_domain_max, model, relaxation);
843 }
844 
845 } // namespace sat
846 } // namespace operations_research
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::sat::CpModelMapping::Integers
std::vector< IntegerVariable > Integers(const List &list) const
Definition: cp_model_loader.h:129
tail
int64 tail
Definition: routing_flow.cc:127
operations_research::sat::LowerBound
std::function< int64(const Model &)> LowerBound(IntegerVariable v)
Definition: integer.h:1394
operations_research::sat::LinearRelaxation
Definition: linear_relaxation.h:28
operations_research::sat::SchedulingConstraintHelper::StartMin
IntegerValue StartMin(int t) const
Definition: intervals.h:374
operations_research::sat::AddCumulativeCut
void AddCumulativeCut(const std::vector< IntervalVariable > &intervals, const std::vector< IntegerVariable > &demands, IntegerValue capacity_lower_bound, Model *model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:487
min
int64 min
Definition: alldiff_cst.cc:138
operations_research::sat::IntegerTrail
Definition: integer.h:518
VLOG
#define VLOG(verboselevel)
Definition: base/logging.h:978
cp_model.pb.h
operations_research::sat::kNoIntegerVariable
const IntegerVariable kNoIntegerVariable(-1)
max
int64 max
Definition: alldiff_cst.cc:139
operations_research::sat::AppendFullEncodingRelaxation
bool AppendFullEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:33
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::IntegerSumLE
Definition: integer_expr.h:50
operations_research::sat::kNoLiteralIndex
const LiteralIndex kNoLiteralIndex(-1)
operations_research::sat::AppendNoOverlapRelaxation
void AppendNoOverlapRelaxation(const CpModelProto &model_proto, const ConstraintProto &ct, int linearization_level, Model *model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:595
operations_research::sat::SchedulingConstraintHelper::PresenceLiteral
Literal PresenceLiteral(int index) const
Definition: intervals.h:265
linear_constraint.h
operations_research::sat::IntegerTrail::LevelZeroUpperBound
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
Definition: integer.h:1291
operations_research::sat::IntegerTrail::LevelZeroLowerBound
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Definition: integer.h:1286
operations_research::sat::SatSolver
Definition: sat_solver.h:58
DCHECK_GT
#define DCHECK_GT(val1, val2)
Definition: base/logging.h:890
model_proto
CpModelProto const * model_proto
Definition: cp_model_solver.cc:2081
operations_research::sat::LinExprUpperBound
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
Definition: linear_constraint.cc:301
operations_research::sat::SchedulingConstraintHelper::IsOptional
bool IsOptional(int t) const
Definition: intervals.h:403
operations_research::sat::AppendLinMaxRelaxation
std::vector< IntegerVariable > AppendLinMaxRelaxation(IntegerVariable target, const std::vector< LinearExpression > &exprs, Model *model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:684
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::ExactlyOneConstraint
std::function< void(Model *)> ExactlyOneConstraint(const std::vector< Literal > &literals)
Definition: sat_solver.h:871
operations_research::sat::NegationOf
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:42
kint64min
static const int64 kint64min
Definition: integral_types.h:60
operations_research::sat::SchedulingConstraintHelper::EndMax
IntegerValue EndMax(int t) const
Definition: intervals.h:386
operations_research::sat::AppendCumulativeRelaxation
void AppendCumulativeRelaxation(const CpModelProto &model_proto, const ConstraintProto &ct, int linearization_level, Model *model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:576
operations_research::sat::IntegerTrail::AddIntegerVariable
IntegerVariable AddIntegerVariable(IntegerValue lower_bound, IntegerValue upper_bound)
Definition: integer.cc:615
int64
int64_t int64
Definition: integral_types.h:34
operations_research::sat::Literal::Negated
Literal Negated() const
Definition: sat_base.h:91
index
int index
Definition: pack.cc:508
sat_base.h
operations_research::sat::LinearConstraintBuilder::AddTerm
void AddTerm(IntegerVariable var, IntegerValue coeff)
Definition: linear_constraint.cc:22
operations_research::sat::Literal::Literal
Literal(int signed_value)
Definition: sat_base.h:68
operations_research::sat::AppendPartialEncodingRelaxation
void AppendPartialEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:110
operations_research::sat::GenericLiteralWatcher
Definition: integer.h:1075
operations_research::sat::GetCoefficient
IntegerValue GetCoefficient(const IntegerVariable var, const LinearExpression &expr)
Definition: linear_constraint.cc:334
operations_research::sat::SchedulingConstraintHelper::SizeIsFixed
bool SizeIsFixed(int t) const
Definition: intervals.h:368
operations_research::sat::SatSolver::CurrentDecisionLevel
int CurrentDecisionLevel() const
Definition: sat_solver.h:361
operations_research::sat::PositiveRef
int PositiveRef(int ref)
Definition: cp_model_utils.h:33
operations_research::sat::LinearConstraint
Definition: linear_constraint.h:39
operations_research::sat::NewBooleanVariable
std::function< BooleanVariable(Model *)> NewBooleanVariable()
Definition: integer.h:1339
operations_research::sat::NewIntegerVariable
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64 lb, int64 ub)
Definition: integer.h:1353
operations_research::sat::LinearConstraintBuilder
Definition: linear_constraint.h:87
operations_research::sat::IntegerEncoder::FullDomainEncoding
std::vector< ValueLiteralPair > FullDomainEncoding(IntegerVariable var) const
Definition: integer.cc:121
operations_research::sat::AppendMaxRelaxation
void AppendMaxRelaxation(IntegerVariable target, const std::vector< IntegerVariable > &vars, int linearization_level, Model *model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:610
operations_research::sat::SchedulingConstraintHelper
Definition: intervals.h:137
operations_research::sat::IntegerEncoder::GetOrCreateLiteralAssociatedToEquality
Literal GetOrCreateLiteralAssociatedToEquality(IntegerVariable var, IntegerValue value)
Definition: integer.cc:263
operations_research::sat::LinearConstraintBuilder::AddLiteralTerm
ABSL_MUST_USE_RESULT bool AddLiteralTerm(Literal lit, IntegerValue coeff)
Definition: linear_constraint.cc:52
gtl::STLSortAndRemoveDuplicates
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
Definition: stl_util.h:58
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
integer_expr.h
CHECK_EQ
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:697
operations_research::sat::LinearExpression
Definition: linear_constraint.h:172
operations_research::sat::NewIntegerVariableFromLiteral
std::function< IntegerVariable(Model *)> NewIntegerVariableFromLiteral(Literal lit)
Definition: integer.h:1371
operations_research::sat::LinearRelaxation::linear_constraints
std::vector< LinearConstraint > linear_constraints
Definition: linear_relaxation.h:29
linear_relaxation.h
operations_research::sat::HasEnforcementLiteral
bool HasEnforcementLiteral(const ConstraintProto &ct)
Definition: cp_model_utils.h:37
operations_research::sat::Model
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
operations_research::sat::SchedulingConstraintHelper::NumTasks
int NumTasks() const
Definition: intervals.h:157
ct
const Constraint * ct
Definition: demon_profiler.cc:42
operations_research::sat::SchedulingConstraintHelper::SizeVars
const std::vector< IntegerVariable > & SizeVars() const
Definition: intervals.h:263
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:291
operations_research::sat::IsFixed
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
Definition: integer.h:1406
operations_research::sat::NegatedRef
int NegatedRef(int ref)
Definition: cp_model_utils.h:32
operations_research::sat::NewInterval
std::function< IntervalVariable(Model *)> NewInterval(int64 min_start, int64 max_end, int64 size)
Definition: intervals.h:569
DCHECK_GE
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:889
model
GRBmodel * model
Definition: gurobi_interface.cc:269
operations_research::sat::Literal
Definition: sat_base.h:64
operations_research::sat::RefIsPositive
bool RefIsPositive(int ref)
Definition: cp_model_utils.h:34
operations_research::sat::SchedulingConstraintHelper::SizeMin
IntegerValue SizeMin(int t) const
Definition: intervals.h:356
operations_research::sat::kMinIntegerValue
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
stl_util.h
iterator_adaptors.h
operations_research::sat::LinearExpression::coeffs
std::vector< IntegerValue > coeffs
Definition: linear_constraint.h:174
delta
int64 delta
Definition: resource.cc:1684
operations_research::sat::IntegerTrail::IsFixed
bool IsFixed(IntegerVariable i) const
Definition: integer.h:1244
operations_research::sat::SpanOfIntervals
std::function< void(Model *)> SpanOfIntervals(IntervalVariable span, const std::vector< IntervalVariable > &intervals)
Definition: scheduling_constraints.cc:306
operations_research::sat::CpModelMapping::Intervals
std::vector< IntervalVariable > Intervals(const ProtoIndices &indices) const
Definition: cp_model_loader.h:143
cp_model_loader.h
operations_research::sat::LinearExpression::vars
std::vector< IntegerVariable > vars
Definition: linear_constraint.h:173
interval
IntervalVar * interval
Definition: resource.cc:98
operations_research::sat::IntegerTrail::LowerBound
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1236
operations_research::sat::AppendLinearConstraintRelaxation
void AppendLinearConstraintRelaxation(const ConstraintProto &constraint_proto, const int linearization_level, const Model &model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:781
operations_research::sat::AppendPartialGreaterThanEncodingRelaxation
void AppendPartialGreaterThanEncodingRelaxation(IntegerVariable var, const Model &model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:185
operations_research::sat::LinearConstraint::coeffs
std::vector< IntegerValue > coeffs
Definition: linear_constraint.h:43
operations_research::sat::CpModelMapping
Definition: cp_model_loader.h:63
head
int64 head
Definition: routing_flow.cc:128
literal
Literal literal
Definition: optimization.cc:84
operations_research::sat::NewOptionalInterval
std::function< IntervalVariable(Model *)> NewOptionalInterval(int64 min_start, int64 max_end, int64 size, Literal is_present)
Definition: intervals.h:599
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::FullyEncodeVariable
std::function< std::vector< IntegerEncoder::ValueLiteralPair >Model *)> FullyEncodeVariable(IntegerVariable var)
Definition: integer.h:1514
operations_research::sat::IntegerEncoder
Definition: integer.h:262
operations_research::sat::TryToLinearizeConstraint
void TryToLinearizeConstraint(const CpModelProto &model_proto, const ConstraintProto &ct, Model *model, int linearization_level, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:315
integer.h
linear_programming_constraint.h
kint64max
static const int64 kint64max
Definition: integral_types.h:62
operations_research::sat::LinearRelaxation::at_most_ones
std::vector< std::vector< Literal > > at_most_ones
Definition: linear_relaxation.h:30
gtl::ContainsKey
bool ContainsKey(const Collection &collection, const Key &key)
Definition: map_util.h:170
scheduling_constraints.h
operations_research::sat::IntegerSumLE::RegisterWith
void RegisterWith(GenericLiteralWatcher *watcher)
Definition: integer_expr.cc:236