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 // TODO(user): Use affine demand.
488 void AddCumulativeCut(const std::vector<IntervalVariable>& intervals,
489  const std::vector<IntegerVariable>& demands,
490  IntegerValue capacity_lower_bound, Model* model,
491  LinearRelaxation* relaxation) {
492  // TODO(user): Keep a map intervals -> helper, or ct_index->helper to avoid
493  // creating many helpers for the same constraint.
494  auto* helper = new SchedulingConstraintHelper(intervals, model);
495  model->TakeOwnership(helper);
496  const int num_intervals = helper->NumTasks();
497 
498  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
499 
500  IntegerValue min_of_starts = kMaxIntegerValue;
501  IntegerValue max_of_ends = kMinIntegerValue;
502 
503  int num_variable_sizes = 0;
504  int num_optionals = 0;
505 
506  for (int index = 0; index < num_intervals; ++index) {
507  min_of_starts = std::min(min_of_starts, helper->StartMin(index));
508  max_of_ends = std::max(max_of_ends, helper->EndMax(index));
509 
510  if (helper->IsOptional(index)) {
511  num_optionals++;
512  }
513 
514  if (!helper->SizeIsFixed(index) ||
515  (!demands.empty() && !integer_trail->IsFixed(demands[index]))) {
516  num_variable_sizes++;
517  }
518  }
519 
520  VLOG(2) << "Span [" << min_of_starts << ".." << max_of_ends << "] with "
521  << num_optionals << " optional intervals, and " << num_variable_sizes
522  << " variable size intervals out of " << num_intervals
523  << " intervals";
524 
525  if (num_variable_sizes + num_optionals == 0) return;
526 
527  const IntegerVariable span_start =
528  integer_trail->AddIntegerVariable(min_of_starts, max_of_ends);
529  const IntegerVariable span_size = integer_trail->AddIntegerVariable(
530  IntegerValue(0), max_of_ends - min_of_starts);
531  const IntegerVariable span_end =
532  integer_trail->AddIntegerVariable(min_of_starts, max_of_ends);
533 
534  IntervalVariable span_var;
535  if (num_optionals < num_intervals) {
536  span_var = model->Add(NewInterval(span_start, span_end, span_size));
537  } else {
538  const Literal span_lit = Literal(model->Add(NewBooleanVariable()), true);
539  span_var = model->Add(
540  NewOptionalInterval(span_start, span_end, span_size, span_lit));
541  }
542 
543  model->Add(SpanOfIntervals(span_var, intervals));
544 
545  LinearConstraintBuilder lc(model, kMinIntegerValue, IntegerValue(0));
546  lc.AddTerm(span_size, -capacity_lower_bound);
547  for (int i = 0; i < num_intervals; ++i) {
548  const IntegerValue demand_lower_bound =
549  demands.empty() ? IntegerValue(1)
550  : integer_trail->LowerBound(demands[i]);
551  const bool demand_is_fixed =
552  demands.empty() || integer_trail->IsFixed(demands[i]);
553  if (!helper->IsOptional(i)) {
554  if (helper->SizeIsFixed(i) && !demands.empty()) {
555  lc.AddTerm(demands[i], helper->SizeMin(i));
556  } else if (demand_is_fixed) {
557  lc.AddTerm(helper->Sizes()[i], demand_lower_bound);
558  } else { // demand and size are not fixed.
559  DCHECK(!demands.empty());
560  // We use McCormick equation.
561  // demand * size = (demand_min + delta_d) * (size_min + delta_s) =
562  // demand_min * size_min + delta_d * size_min +
563  // delta_s * demand_min + delta_s * delta_d
564  // which is >= (by ignoring the quatratic term)
565  // demand_min * size + size_min * demand - demand_min * size_min
566  lc.AddTerm(helper->Sizes()[i], demand_lower_bound);
567  lc.AddTerm(demands[i], helper->SizeMin(i));
568  lc.AddConstant(-helper->SizeMin(i) * demand_lower_bound);
569  }
570  } else {
571  if (!lc.AddLiteralTerm(helper->PresenceLiteral(i),
572  helper->SizeMin(i) * demand_lower_bound)) {
573  return;
574  }
575  }
576  }
577  relaxation->linear_constraints.push_back(lc.Build());
578 }
579 
580 void AppendCumulativeRelaxation(const CpModelProto& model_proto,
581  const ConstraintProto& ct,
582  int linearization_level, Model* model,
583  LinearRelaxation* relaxation) {
584  CHECK(ct.has_cumulative());
585  if (linearization_level < 2) return;
586  if (HasEnforcementLiteral(ct)) return;
587 
588  auto* mapping = model->GetOrCreate<CpModelMapping>();
589  const std::vector<IntegerVariable> demands =
590  mapping->Integers(ct.cumulative().demands());
591  std::vector<IntervalVariable> intervals =
592  mapping->Intervals(ct.cumulative().intervals());
593  const IntegerValue capacity_lower_bound =
594  model->GetOrCreate<IntegerTrail>()->LowerBound(
595  mapping->Integer(ct.cumulative().capacity()));
596  AddCumulativeCut(intervals, demands, capacity_lower_bound, model, relaxation);
597 }
598 
599 void AppendNoOverlapRelaxation(const CpModelProto& model_proto,
600  const ConstraintProto& ct,
601  int linearization_level, Model* model,
602  LinearRelaxation* relaxation) {
603  CHECK(ct.has_no_overlap());
604  if (linearization_level < 2) return;
605  if (HasEnforcementLiteral(ct)) return;
606 
607  auto* mapping = model->GetOrCreate<CpModelMapping>();
608  std::vector<IntervalVariable> intervals =
609  mapping->Intervals(ct.no_overlap().intervals());
610  AddCumulativeCut(intervals, /*demands=*/{},
611  /*capacity_lower_bound=*/IntegerValue(1), model, relaxation);
612 }
613 
614 void AppendMaxRelaxation(IntegerVariable target,
615  const std::vector<IntegerVariable>& vars,
616  int linearization_level, Model* model,
617  LinearRelaxation* relaxation) {
618  // Case X = max(X_1, X_2, ..., X_N)
619  // Part 1: Encode X >= max(X_1, X_2, ..., X_N)
620  for (const IntegerVariable var : vars) {
621  // This deal with the corner case X = max(X, Y, Z, ..) !
622  // Note that this can be presolved into X >= Y, X >= Z, ...
623  if (target == var) continue;
624  LinearConstraintBuilder lc(model, kMinIntegerValue, IntegerValue(0));
625  lc.AddTerm(var, IntegerValue(1));
626  lc.AddTerm(target, IntegerValue(-1));
627  relaxation->linear_constraints.push_back(lc.Build());
628  }
629 
630  // Part 2: Encode upper bound on X.
631  if (linearization_level < 2) return;
632  GenericLiteralWatcher* watcher = model->GetOrCreate<GenericLiteralWatcher>();
633  // For size = 2, we do this with 1 less variable.
634  IntegerEncoder* encoder = model->GetOrCreate<IntegerEncoder>();
635  if (vars.size() == 2) {
636  IntegerVariable y = model->Add(NewIntegerVariable(0, 1));
637  const Literal y_lit =
638  encoder->GetOrCreateLiteralAssociatedToEquality(y, IntegerValue(1));
639  AppendEnforcedUpperBound(y_lit, target, vars[0], model, relaxation);
640 
641  // TODO(user,user): It makes more sense to use ConditionalLowerOrEqual()
642  // here, but that degrades perf on the road*.fzn problem. Understand why.
643  IntegerSumLE* upper_bound1 = new IntegerSumLE(
644  {y_lit}, {target, vars[0]}, {IntegerValue(1), IntegerValue(-1)},
645  IntegerValue(0), model);
646  upper_bound1->RegisterWith(watcher);
647  model->TakeOwnership(upper_bound1);
648  AppendEnforcedUpperBound(y_lit.Negated(), target, vars[1], model,
649  relaxation);
650  IntegerSumLE* upper_bound2 = new IntegerSumLE(
651  {y_lit.Negated()}, {target, vars[1]},
652  {IntegerValue(1), IntegerValue(-1)}, IntegerValue(0), model);
653  upper_bound2->RegisterWith(watcher);
654  model->TakeOwnership(upper_bound2);
655  return;
656  }
657  // For each X_i, we encode y_i => X <= X_i. And at least one of the y_i is
658  // true. Note that the correct y_i will be chosen because of the first part in
659  // linearlization (X >= X_i).
660  // TODO(user): Only lower bound is needed, experiment.
661  LinearConstraintBuilder lc_exactly_one(model, IntegerValue(1),
662  IntegerValue(1));
663  std::vector<Literal> exactly_one_literals;
664  exactly_one_literals.reserve(vars.size());
665  for (const IntegerVariable var : vars) {
666  if (target == var) continue;
667  // y => X <= X_i.
668  // <=> max_term_value * y + X - X_i <= max_term_value.
669  // where max_tern_value is X_ub - X_i_lb.
670  IntegerVariable y = model->Add(NewIntegerVariable(0, 1));
671  const Literal y_lit =
672  encoder->GetOrCreateLiteralAssociatedToEquality(y, IntegerValue(1));
673 
674  AppendEnforcedUpperBound(y_lit, target, var, model, relaxation);
675  IntegerSumLE* upper_bound_constraint = new IntegerSumLE(
676  {y_lit}, {target, var}, {IntegerValue(1), IntegerValue(-1)},
677  IntegerValue(0), model);
678  upper_bound_constraint->RegisterWith(watcher);
679  model->TakeOwnership(upper_bound_constraint);
680  exactly_one_literals.push_back(y_lit);
681 
682  CHECK(lc_exactly_one.AddLiteralTerm(y_lit, IntegerValue(1)));
683  }
684  model->Add(ExactlyOneConstraint(exactly_one_literals));
685  relaxation->linear_constraints.push_back(lc_exactly_one.Build());
686 }
687 
688 std::vector<IntegerVariable> AppendLinMaxRelaxation(
689  IntegerVariable target, const std::vector<LinearExpression>& exprs,
690  Model* model, LinearRelaxation* relaxation) {
691  // We want to linearize X = max(exprs[1], exprs[2], ..., exprs[d]).
692  // Part 1: Encode X >= max(exprs[1], exprs[2], ..., exprs[d])
693  for (const LinearExpression& expr : exprs) {
695  for (int i = 0; i < expr.vars.size(); ++i) {
696  lc.AddTerm(expr.vars[i], expr.coeffs[i]);
697  }
698  lc.AddTerm(target, IntegerValue(-1));
699  relaxation->linear_constraints.push_back(lc.Build());
700  }
701 
702  // Part 2: Encode upper bound on X.
703 
704  // Add linking constraint to the CP solver
705  // sum zi = 1 and for all i, zi => max = expr_i.
706  const int num_exprs = exprs.size();
707  IntegerEncoder* encoder = model->GetOrCreate<IntegerEncoder>();
708  GenericLiteralWatcher* watcher = model->GetOrCreate<GenericLiteralWatcher>();
709 
710  // TODO(user): For the case where num_exprs = 2, Create only one z var.
711  std::vector<IntegerVariable> z_vars;
712  std::vector<Literal> z_lits;
713  z_vars.reserve(num_exprs);
714  z_lits.reserve(num_exprs);
715  LinearConstraintBuilder lc_exactly_one(model, IntegerValue(1),
716  IntegerValue(1));
717  std::vector<Literal> exactly_one_literals;
718  for (int i = 0; i < num_exprs; ++i) {
719  IntegerVariable z = model->Add(NewIntegerVariable(0, 1));
720  z_vars.push_back(z);
721  const Literal z_lit =
722  encoder->GetOrCreateLiteralAssociatedToEquality(z, IntegerValue(1));
723  z_lits.push_back(z_lit);
724  LinearExpression local_expr;
725  local_expr.vars = NegationOf(exprs[i].vars);
726  local_expr.vars.push_back(target);
727  local_expr.coeffs = exprs[i].coeffs;
728  local_expr.coeffs.push_back(IntegerValue(1));
729  IntegerSumLE* upper_bound = new IntegerSumLE(
730  {z_lit}, local_expr.vars, local_expr.coeffs, exprs[i].offset, model);
731  upper_bound->RegisterWith(watcher);
732  model->TakeOwnership(upper_bound);
733 
734  CHECK(lc_exactly_one.AddLiteralTerm(z_lit, IntegerValue(1)));
735  }
736  model->Add(ExactlyOneConstraint(z_lits));
737 
738  // For the relaxation, we use different constraints with a stronger linear
739  // relaxation as explained in the .h
740  // TODO(user): Consider passing the x_vars to this method instead of
741  // computing it here.
742  std::vector<IntegerVariable> x_vars;
743  for (int i = 0; i < num_exprs; ++i) {
744  x_vars.insert(x_vars.end(), exprs[i].vars.begin(), exprs[i].vars.end());
745  }
747  // All expressions should only contain positive variables.
748  DCHECK(std::all_of(x_vars.begin(), x_vars.end(), [](IntegerVariable var) {
749  return VariableIsPositive(var);
750  }));
751 
752  std::vector<std::vector<IntegerValue>> sum_of_max_corner_diff(
753  num_exprs, std::vector<IntegerValue>(num_exprs, IntegerValue(0)));
754 
755  IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
756  for (int i = 0; i < num_exprs; ++i) {
757  for (int j = 0; j < num_exprs; ++j) {
758  if (i == j) continue;
759  for (const IntegerVariable x_var : x_vars) {
760  const IntegerValue lb = integer_trail->LevelZeroLowerBound(x_var);
761  const IntegerValue ub = integer_trail->LevelZeroUpperBound(x_var);
762  const IntegerValue diff =
763  GetCoefficient(x_var, exprs[j]) - GetCoefficient(x_var, exprs[i]);
764  sum_of_max_corner_diff[i][j] += std::max(diff * lb, diff * ub);
765  }
766  }
767  }
768  for (int i = 0; i < num_exprs; ++i) {
769  LinearConstraintBuilder lc(model, kMinIntegerValue, IntegerValue(0));
770  lc.AddTerm(target, IntegerValue(1));
771  for (int j = 0; j < exprs[i].vars.size(); ++j) {
772  lc.AddTerm(exprs[i].vars[j], -exprs[i].coeffs[j]);
773  }
774  for (int j = 0; j < num_exprs; ++j) {
775  CHECK(lc.AddLiteralTerm(z_lits[j],
776  -exprs[j].offset - sum_of_max_corner_diff[i][j]));
777  }
778  relaxation->linear_constraints.push_back(lc.Build());
779  }
780 
781  relaxation->linear_constraints.push_back(lc_exactly_one.Build());
782  return z_vars;
783 }
784 
785 void AppendLinearConstraintRelaxation(const ConstraintProto& constraint_proto,
786  const int linearization_level,
787  const Model& model,
788  LinearRelaxation* relaxation) {
789  auto* mapping = model.Get<CpModelMapping>();
790 
791  // Note that we ignore the holes in the domain.
792  //
793  // TODO(user): In LoadLinearConstraint() we already created intermediate
794  // Booleans for each disjoint interval, we should reuse them here if
795  // possible.
796  //
797  // TODO(user): process the "at most one" part of a == 1 separately?
798  const IntegerValue rhs_domain_min =
799  IntegerValue(constraint_proto.linear().domain(0));
800  const IntegerValue rhs_domain_max =
801  IntegerValue(constraint_proto.linear().domain(
802  constraint_proto.linear().domain_size() - 1));
803  if (rhs_domain_min == kint64min && rhs_domain_max == kint64max) return;
804 
805  if (!HasEnforcementLiteral(constraint_proto)) {
806  LinearConstraintBuilder lc(&model, rhs_domain_min, rhs_domain_max);
807  for (int i = 0; i < constraint_proto.linear().vars_size(); i++) {
808  const int ref = constraint_proto.linear().vars(i);
809  const int64 coeff = constraint_proto.linear().coeffs(i);
810  lc.AddTerm(mapping->Integer(ref), IntegerValue(coeff));
811  }
812  relaxation->linear_constraints.push_back(lc.Build());
813  return;
814  }
815 
816  // Reified version.
817  if (linearization_level < 2) return;
818 
819  // We linearize fully reified constraints of size 1 all together for a given
820  // variable. But we need to process half-reified ones.
821  if (!mapping->IsHalfEncodingConstraint(&constraint_proto) &&
822  constraint_proto.linear().vars_size() <= 1) {
823  return;
824  }
825 
826  std::vector<Literal> enforcing_literals;
827  enforcing_literals.reserve(constraint_proto.enforcement_literal_size());
828  for (const int enforcement_ref : constraint_proto.enforcement_literal()) {
829  enforcing_literals.push_back(mapping->Literal(enforcement_ref));
830  }
831  LinearExpression expr;
832  expr.vars.reserve(constraint_proto.linear().vars_size());
833  expr.coeffs.reserve(constraint_proto.linear().vars_size());
834  for (int i = 0; i < constraint_proto.linear().vars_size(); i++) {
835  int ref = constraint_proto.linear().vars(i);
836  IntegerValue coeff(constraint_proto.linear().coeffs(i));
837  if (!RefIsPositive(ref)) {
838  ref = PositiveRef(ref);
839  coeff = -coeff;
840  }
841  const IntegerVariable int_var = mapping->Integer(ref);
842  expr.vars.push_back(int_var);
843  expr.coeffs.push_back(coeff);
844  }
845  AppendEnforcedLinearExpression(enforcing_literals, expr, rhs_domain_min,
846  rhs_domain_max, model, relaxation);
847 }
848 
849 } // namespace sat
850 } // 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:1450
operations_research::sat::LinearRelaxation
Definition: linear_relaxation.h:28
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:488
min
int64 min
Definition: alldiff_cst.cc:138
operations_research::sat::IntegerTrail
Definition: integer.h:533
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:599
linear_constraint.h
operations_research::sat::IntegerTrail::LevelZeroUpperBound
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
Definition: integer.h:1338
operations_research::sat::IntegerTrail::LevelZeroLowerBound
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Definition: integer.h:1333
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:2101
operations_research::sat::LinExprUpperBound
IntegerValue LinExprUpperBound(const LinearExpression &expr, const IntegerTrail &integer_trail)
Definition: linear_constraint.cc:302
operations_research::sat::AppendLinMaxRelaxation
std::vector< IntegerVariable > AppendLinMaxRelaxation(IntegerVariable target, const std::vector< LinearExpression > &exprs, Model *model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:688
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:877
operations_research::sat::NegationOf
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:27
kint64min
static const int64 kint64min
Definition: integral_types.h:60
operations_research::sat::AppendCumulativeRelaxation
void AppendCumulativeRelaxation(const CpModelProto &model_proto, const ConstraintProto &ct, int linearization_level, Model *model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:580
operations_research::sat::IntegerTrail::AddIntegerVariable
IntegerVariable AddIntegerVariable(IntegerValue lower_bound, IntegerValue upper_bound)
Definition: integer.cc:603
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:1091
operations_research::sat::GetCoefficient
IntegerValue GetCoefficient(const IntegerVariable var, const LinearExpression &expr)
Definition: linear_constraint.cc:335
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:1395
operations_research::sat::NewIntegerVariable
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64 lb, int64 ub)
Definition: integer.h:1409
operations_research::sat::LinearConstraintBuilder
Definition: linear_constraint.h:87
operations_research::sat::IntegerEncoder::FullDomainEncoding
std::vector< ValueLiteralPair > FullDomainEncoding(IntegerVariable var) const
Definition: integer.cc:106
operations_research::sat::AppendMaxRelaxation
void AppendMaxRelaxation(IntegerVariable target, const std::vector< IntegerVariable > &vars, int linearization_level, Model *model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:614
operations_research::sat::SchedulingConstraintHelper
Definition: intervals.h:172
operations_research::sat::IntegerEncoder::GetOrCreateLiteralAssociatedToEquality
Literal GetOrCreateLiteralAssociatedToEquality(IntegerVariable var, IntegerValue value)
Definition: integer.cc:248
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:277
integer_expr.h
CHECK_EQ
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:697
operations_research::sat::LinearExpression
Definition: linear_constraint.h:173
operations_research::sat::NewIntegerVariableFromLiteral
std::function< IntegerVariable(Model *)> NewIntegerVariableFromLiteral(Literal lit)
Definition: integer.h:1427
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
ct
const Constraint * ct
Definition: demon_profiler.cc:42
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::IsFixed
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
Definition: integer.h:1462
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:632
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::kMinIntegerValue
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
stl_util.h
iterator_adaptors.h
operations_research::sat::LinearExpression::coeffs
std::vector< IntegerValue > coeffs
Definition: linear_constraint.h:175
delta
int64 delta
Definition: resource.cc:1684
operations_research::sat::IntegerTrail::IsFixed
bool IsFixed(IntegerVariable i) const
Definition: integer.h:1291
operations_research::sat::SpanOfIntervals
std::function< void(Model *)> SpanOfIntervals(IntervalVariable span, const std::vector< IntervalVariable > &intervals)
Definition: scheduling_constraints.cc:305
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:174
interval
IntervalVar * interval
Definition: resource.cc:98
operations_research::sat::IntegerTrail::LowerBound
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1283
operations_research::sat::AppendLinearConstraintRelaxation
void AppendLinearConstraintRelaxation(const ConstraintProto &constraint_proto, const int linearization_level, const Model &model, LinearRelaxation *relaxation)
Definition: linear_relaxation.cc:785
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:662
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:1570
operations_research::sat::IntegerEncoder
Definition: integer.h:276
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