OR-Tools  9.2
linear_programming_constraint.h
Go to the documentation of this file.
1 // Copyright 2010-2021 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 
14 #ifndef OR_TOOLS_SAT_LINEAR_PROGRAMMING_CONSTRAINT_H_
15 #define OR_TOOLS_SAT_LINEAR_PROGRAMMING_CONSTRAINT_H_
16 
17 #include <cstdint>
18 #include <limits>
19 #include <utility>
20 #include <vector>
21 
22 #include "absl/container/flat_hash_map.h"
23 #include "ortools/base/int_type.h"
29 #include "ortools/sat/cuts.h"
31 #include "ortools/sat/integer.h"
35 #include "ortools/sat/model.h"
36 #include "ortools/sat/util.h"
38 #include "ortools/util/rev.h"
40 
41 namespace operations_research {
42 namespace sat {
43 
44 // Stores for each IntegerVariable its temporary LP solution.
45 //
46 // This is shared between all LinearProgrammingConstraint because in the corner
47 // case where we have many different LinearProgrammingConstraint and a lot of
48 // variable, we could theoretically use up a quadratic amount of memory
49 // otherwise.
50 //
51 // TODO(user): find a better way?
53  : public absl::StrongVector<IntegerVariable, double> {
55 };
56 
57 // Helper struct to combine info generated from solving LP.
58 struct LPSolveInfo {
60  double lp_objective = -std::numeric_limits<double>::infinity();
62 };
63 
64 // Simple class to combine linear expression efficiently. First in a sparse
65 // way that switch to dense when the number of non-zeros grows.
67  public:
68  // This must be called with the correct size before any other functions are
69  // used.
70  void ClearAndResize(int size);
71 
72  // Does vector[col] += value and return false in case of overflow.
73  bool Add(glop::ColIndex col, IntegerValue value);
74 
75  // Similar to Add() but for multiplier * terms.
76  // Returns false in case of overflow.
78  IntegerValue multiplier,
79  const std::vector<std::pair<glop::ColIndex, IntegerValue>>& terms);
80 
81  // This is not const only because non_zeros is sorted. Note that sorting the
82  // non-zeros make the result deterministic whether or not we were in sparse
83  // mode.
84  //
85  // TODO(user): Ideally we should convert to IntegerVariable as late as
86  // possible. Prefer to use GetTerms().
88  const std::vector<IntegerVariable>& integer_variables,
89  IntegerValue upper_bound, LinearConstraint* result);
90 
91  // Similar to ConvertToLinearConstraint().
92  std::vector<std::pair<glop::ColIndex, IntegerValue>> GetTerms();
93 
94  // We only provide the const [].
95  IntegerValue operator[](glop::ColIndex col) const {
96  return dense_vector_[col];
97  }
98 
99  const bool IsSparse() const { return is_sparse_; }
100 
101  private:
102  // If is_sparse is true we maintain the non_zeros positions and bool vector
103  // of dense_vector_. Otherwise we don't. Note that we automatically switch
104  // from sparse to dense as needed.
105  bool is_sparse_ = true;
106  std::vector<glop::ColIndex> non_zeros_;
108 
109  // The dense representation of the vector.
111 };
112 
113 // A SAT constraint that enforces a set of linear inequality constraints on
114 // integer variables using an LP solver.
115 //
116 // The propagator uses glop's revised simplex for feasibility and propagation.
117 // It uses the Reduced Cost Strengthening technique, a classic in mixed integer
118 // programming, for instance see the thesis of Tobias Achterberg,
119 // "Constraint Integer Programming", sections 7.7 and 8.8, algorithm 7.11.
120 // http://nbn-resolving.de/urn:nbn:de:0297-zib-11129
121 //
122 // Per-constraint bounds propagation is NOT done by this constraint,
123 // it should be done by redundant constraints, as reduced cost propagation
124 // may miss some filtering.
125 //
126 // Note that this constraint works with double floating-point numbers, so one
127 // could be worried that it may filter too much in case of precision issues.
128 // However, by default, we interpret the LP result by recomputing everything
129 // in integer arithmetic, so we are exact.
130 class LinearProgrammingDispatcher;
133  public:
134  typedef glop::RowIndex ConstraintIndex;
135 
137 
138  // Add a new linear constraint to this LP.
140 
141  // Set the coefficient of the variable in the objective. Calling it twice will
142  // overwrite the previous value.
143  void SetObjectiveCoefficient(IntegerVariable ivar, IntegerValue coeff);
144 
145  // The main objective variable should be equal to the linear sum of
146  // the arguments passed to SetObjectiveCoefficient().
147  void SetMainObjectiveVariable(IntegerVariable ivar) { objective_cp_ = ivar; }
148  IntegerVariable ObjectiveVariable() const { return objective_cp_; }
149 
150  // Register a new cut generator with this constraint.
151  void AddCutGenerator(CutGenerator generator);
152 
153  // Returns the LP value and reduced cost of a variable in the current
154  // solution. These functions should only be called when HasSolution() is true.
155  //
156  // Note that this solution is always an OPTIMAL solution of an LP above or
157  // at the current decision level. We "erase" it when we backtrack over it.
158  bool HasSolution() const { return lp_solution_is_set_; }
159  double SolutionObjectiveValue() const { return lp_objective_; }
160  double GetSolutionValue(IntegerVariable variable) const;
161  double GetSolutionReducedCost(IntegerVariable variable) const;
162  bool SolutionIsInteger() const { return lp_solution_is_integer_; }
163 
164  // PropagatorInterface API.
165  bool Propagate() override;
166  bool IncrementalPropagate(const std::vector<int>& watch_indices) override;
167  void RegisterWith(Model* model);
168 
169  // ReversibleInterface API.
170  void SetLevel(int level) override;
171 
172  int NumVariables() const { return integer_variables_.size(); }
173  const std::vector<IntegerVariable>& integer_variables() const {
174  return integer_variables_;
175  }
176  std::string DimensionString() const { return lp_data_.GetDimensionString(); }
177 
178  // Returns a IntegerLiteral guided by the underlying LP constraints.
179  //
180  // This looks at all unassigned 0-1 variables, takes the one with
181  // a support value closest to 0.5, and tries to assign it to 1.
182  // If all 0-1 variables have an integer support, returns kNoLiteralIndex.
183  // Tie-breaking is done using the variable natural order.
184  //
185  // TODO(user): This fixes to 1, but for some problems fixing to 0
186  // or to the std::round(support value) might work better. When this is the
187  // case, change behaviour automatically?
189 
190  // Returns a IntegerLiteral guided by the underlying LP constraints.
191  //
192  // This computes the mean of reduced costs over successive calls,
193  // and tries to fix the variable which has the highest reduced cost.
194  // Tie-breaking is done using the variable natural order.
195  // Only works for 0/1 variables.
196  //
197  // TODO(user): Try to get better pseudocosts than averaging every time
198  // the heuristic is called. MIP solvers initialize this with strong branching,
199  // then keep track of the pseudocosts when doing tree search. Also, this
200  // version only branches on var >= 1 and keeps track of reduced costs from var
201  // = 1 to var = 0. This works better than the conventional MIP where the
202  // chosen variable will be argmax_var min(pseudocost_var(0->1),
203  // pseudocost_var(1->0)), probably because we are doing DFS search where MIP
204  // does BFS. This might depend on the model, more trials are necessary. We
205  // could also do exponential smoothing instead of decaying every N calls, i.e.
206  // pseudo = a * pseudo + (1-a) reduced.
208 
209  // Returns a IntegerLiteral guided by the underlying LP constraints.
210  //
211  // This computes the mean of reduced costs over successive calls,
212  // and tries to fix the variable which has the highest reduced cost.
213  // Tie-breaking is done using the variable natural order.
215 
216  // Average number of nonbasic variables with zero reduced costs.
217  double average_degeneracy() const {
218  return average_degeneracy_.CurrentAverage();
219  }
220 
222  return total_num_simplex_iterations_;
223  }
224 
225  // Returns some statistics about this LP.
226  std::string Statistics() const;
227 
228  // Important: this is only temporarily valid.
230  if (optimal_constraints_.empty()) return nullptr;
231  return optimal_constraints_.back().get();
232  }
233 
234  const std::vector<std::unique_ptr<IntegerSumLE>>& OptimalConstraints() const {
235  return optimal_constraints_;
236  }
237 
238  private:
239  // Helper methods for branching. Returns true if branching on the given
240  // variable helps with more propagation or finds a conflict.
241  bool BranchOnVar(IntegerVariable var);
242  LPSolveInfo SolveLpForBranching();
243 
244  // Helper method to fill reduced cost / dual ray reason in 'integer_reason'.
245  // Generates a set of IntegerLiterals explaining why the best solution can not
246  // be improved using reduced costs. This is used to generate explanations for
247  // both infeasibility and bounds deductions.
248  void FillReducedCostReasonIn(const glop::DenseRow& reduced_costs,
249  std::vector<IntegerLiteral>* integer_reason);
250 
251  // Reinitialize the LP from a potentially new set of constraints.
252  // This fills all data structure and properly rescale the underlying LP.
253  //
254  // Returns false if the problem is UNSAT (it can happen when presolve is off
255  // and some LP constraint are trivially false).
256  bool CreateLpFromConstraintManager();
257 
258  // Solve the LP, returns false if something went wrong in the LP solver.
259  bool SolveLp();
260 
261  // Add a "MIR" cut obtained by first taking the linear combination of the
262  // row of the matrix according to "integer_multipliers" and then trying
263  // some integer rounding heuristic.
264  //
265  // Return true if a new cut was added to the cut manager.
266  bool AddCutFromConstraints(
267  const std::string& name,
268  const std::vector<std::pair<glop::RowIndex, IntegerValue>>&
269  integer_multipliers);
270 
271  // Second half of AddCutFromConstraints().
272  bool PostprocessAndAddCut(
273  const std::string& name, const std::string& info,
274  IntegerVariable first_new_var, IntegerVariable first_slack,
275  const std::vector<ImpliedBoundsProcessor::SlackInfo>& ib_slack_infos,
276  LinearConstraint* cut);
277 
278  // Computes and adds the corresponding type of cuts.
279  // This can currently only be called at the root node.
280  void AddObjectiveCut();
281  void AddCGCuts();
282  void AddMirCuts();
283  void AddZeroHalfCuts();
284 
285  // Updates the bounds of the LP variables from the CP bounds.
286  void UpdateBoundsOfLpVariables();
287 
288  // Use the dual optimal lp values to compute an EXACT lower bound on the
289  // objective. Fills its reason and perform reduced cost strenghtening.
290  // Returns false in case of conflict.
291  bool ExactLpReasonning();
292 
293  // Same as FillDualRayReason() but perform the computation EXACTLY. Returns
294  // false in the case that the problem is not provably infeasible with exact
295  // computations, true otherwise.
296  bool FillExactDualRayReason();
297 
298  // Returns number of non basic variables with zero reduced costs.
299  int64_t CalculateDegeneracy();
300 
301  // From a set of row multipliers (at LP scale), scale them back to the CP
302  // world and then make them integer (eventually multiplying them by a new
303  // scaling factor returned in *scaling).
304  //
305  // Note that this will loose some precision, but our subsequent computation
306  // will still be exact as it will work for any set of multiplier.
307  std::vector<std::pair<glop::RowIndex, IntegerValue>> ScaleLpMultiplier(
308  bool take_objective_into_account,
309  const std::vector<std::pair<glop::RowIndex, double>>& lp_multipliers,
310  glop::Fractional* scaling, int max_pow = 62) const;
311 
312  // Computes from an integer linear combination of the integer rows of the LP a
313  // new constraint of the form "sum terms <= upper_bound". All computation are
314  // exact here.
315  //
316  // Returns false if we encountered any integer overflow.
317  bool ComputeNewLinearConstraint(
318  const std::vector<std::pair<glop::RowIndex, IntegerValue>>&
319  integer_multipliers,
320  ScatteredIntegerVector* scattered_vector,
321  IntegerValue* upper_bound) const;
322 
323  // Simple heuristic to try to minimize |upper_bound - ImpliedLB(terms)|. This
324  // should make the new constraint tighter and correct a bit the imprecision
325  // introduced by rounding the floating points values.
326  void AdjustNewLinearConstraint(
327  std::vector<std::pair<glop::RowIndex, IntegerValue>>* integer_multipliers,
328  ScatteredIntegerVector* scattered_vector,
329  IntegerValue* upper_bound) const;
330 
331  // Shortcut for an integer linear expression type.
332  using LinearExpression = std::vector<std::pair<glop::ColIndex, IntegerValue>>;
333 
334  // Converts a dense representation of a linear constraint to a sparse one
335  // expressed in terms of IntegerVariable.
336  void ConvertToLinearConstraint(
338  IntegerValue upper_bound, LinearConstraint* result);
339 
340  // Compute the implied lower bound of the given linear expression using the
341  // current variable bound. Return kMinIntegerValue in case of overflow.
342  IntegerValue GetImpliedLowerBound(const LinearConstraint& terms) const;
343 
344  // Tests for possible overflow in the propagation of the given linear
345  // constraint.
346  bool PossibleOverflow(const LinearConstraint& constraint);
347 
348  // Reduce the coefficient of the constraint so that we cannot have overflow
349  // in the propagation of the given linear constraint. Note that we may loose
350  // some strength by doing so.
351  //
352  // We make sure that any partial sum involving any variable value in their
353  // domain do not exceed 2 ^ max_pow.
354  void PreventOverflow(LinearConstraint* constraint, int max_pow = 62);
355 
356  // Fills integer_reason_ with the reason for the implied lower bound of the
357  // given linear expression. We relax the reason if we have some slack.
358  void SetImpliedLowerBoundReason(const LinearConstraint& terms,
359  IntegerValue slack);
360 
361  // Fills the deductions vector with reduced cost deductions that can be made
362  // from the current state of the LP solver. The given delta should be the
363  // difference between the cp objective upper bound and lower bound given by
364  // the lp.
365  void ReducedCostStrengtheningDeductions(double cp_objective_delta);
366 
367  // Returns the variable value on the same scale as the CP variable value.
368  glop::Fractional GetVariableValueAtCpScale(glop::ColIndex var);
369 
370  // Gets or creates an LP variable that mirrors a CP variable.
371  // The variable should be a positive reference.
372  glop::ColIndex GetOrCreateMirrorVariable(IntegerVariable positive_variable);
373 
374  // This must be called on an OPTIMAL LP and will update the data for
375  // LPReducedCostAverageDecision().
376  void UpdateAverageReducedCosts();
377 
378  // Callback underlying LPReducedCostAverageBranching().
379  IntegerLiteral LPReducedCostAverageDecision();
380 
381  // Updates the simplex iteration limit for the next visit.
382  // As per current algorithm, we use a limit which is dependent on size of the
383  // problem and drop it significantly if degeneracy is detected. We use
384  // DUAL_FEASIBLE status as a signal to correct the prediction. The next limit
385  // is capped by 'min_iter' and 'max_iter'. Note that this is enabled only for
386  // linearization level 2 and above.
387  void UpdateSimplexIterationLimit(const int64_t min_iter,
388  const int64_t max_iter);
389 
390  // This epsilon is related to the precision of the value/reduced_cost returned
391  // by the LP once they have been scaled back into the CP domain. So for large
392  // domain or cost coefficient, we may have some issues.
393  static constexpr double kCpEpsilon = 1e-4;
394 
395  // Same but at the LP scale.
396  static constexpr double kLpEpsilon = 1e-6;
397 
398  // Anything coming from the LP with a magnitude below that will be assumed to
399  // be zero.
400  static constexpr double kZeroTolerance = 1e-12;
401 
402  // Class responsible for managing all possible constraints that may be part
403  // of the LP.
404  LinearConstraintManager constraint_manager_;
405 
406  // Initial problem in integer form.
407  // We always sort the inner vectors by increasing glop::ColIndex.
408  struct LinearConstraintInternal {
409  IntegerValue lb;
410  IntegerValue ub;
411  LinearExpression terms;
412  };
413  LinearExpression integer_objective_;
414  IntegerValue integer_objective_offset_ = IntegerValue(0);
415  IntegerValue objective_infinity_norm_ = IntegerValue(0);
418 
419  // Underlying LP solver API.
420  glop::LinearProgram lp_data_;
421  glop::RevisedSimplex simplex_;
422  int64_t next_simplex_iter_ = 500;
423 
424  // For the scaling.
425  glop::LpScalingHelper scaler_;
426 
427  // Temporary data for cuts.
428  ZeroHalfCutHelper zero_half_cut_helper_;
429  CoverCutHelper cover_cut_helper_;
430  IntegerRoundingCutHelper integer_rounding_cut_helper_;
431  LinearConstraint cut_;
432 
433  ScatteredIntegerVector tmp_scattered_vector_;
434 
435  std::vector<double> tmp_lp_values_;
436  std::vector<IntegerValue> tmp_var_lbs_;
437  std::vector<IntegerValue> tmp_var_ubs_;
438  std::vector<glop::RowIndex> tmp_slack_rows_;
439  std::vector<IntegerValue> tmp_slack_bounds_;
440 
441  // Used by ScaleLpMultiplier().
442  mutable std::vector<std::pair<glop::RowIndex, double>> tmp_cp_multipliers_;
443 
444  // Structures used for mirroring IntegerVariables inside the underlying LP
445  // solver: an integer variable var is mirrored by mirror_lp_variable_[var].
446  // Note that these indices are dense in [0, mirror_lp_variable_.size()] so
447  // they can be used as vector indices.
448  //
449  // TODO(user): This should be absl::StrongVector<glop::ColIndex,
450  // IntegerVariable>.
451  std::vector<IntegerVariable> integer_variables_;
452  absl::flat_hash_map<IntegerVariable, glop::ColIndex> mirror_lp_variable_;
453 
454  // We need to remember what to optimize if an objective is given, because
455  // then we will switch the objective between feasibility and optimization.
456  bool objective_is_defined_ = false;
457  IntegerVariable objective_cp_;
458 
459  // Singletons from Model.
460  const SatParameters& parameters_;
461  Model* model_;
462  TimeLimit* time_limit_;
463  IntegerTrail* integer_trail_;
464  Trail* trail_;
465  IntegerEncoder* integer_encoder_;
466  ModelRandomGenerator* random_;
467 
468  // Used while deriving cuts.
469  ImpliedBoundsProcessor implied_bounds_processor_;
470 
471  // The dispatcher for all LP propagators of the model, allows to find which
472  // LinearProgrammingConstraint has a given IntegerVariable.
473  LinearProgrammingDispatcher* dispatcher_;
474 
475  std::vector<IntegerLiteral> integer_reason_;
476  std::vector<IntegerLiteral> deductions_;
477  std::vector<IntegerLiteral> deductions_reason_;
478 
479  // Repository of IntegerSumLE that needs to be kept around for the lazy
480  // reasons. Those are new integer constraint that are created each time we
481  // solve the LP to a dual-feasible solution. Propagating these constraints
482  // both improve the objective lower bound but also perform reduced cost
483  // fixing.
484  int rev_optimal_constraints_size_ = 0;
485  std::vector<std::unique_ptr<IntegerSumLE>> optimal_constraints_;
486 
487  // Last OPTIMAL solution found by a call to the underlying LP solver.
488  // On IncrementalPropagate(), if the bound updates do not invalidate this
489  // solution, Propagate() will not find domain reductions, no need to call it.
490  int lp_solution_level_ = 0;
491  bool lp_solution_is_set_ = false;
492  bool lp_solution_is_integer_ = false;
493  double lp_objective_;
494  std::vector<double> lp_solution_;
495  std::vector<double> lp_reduced_cost_;
496 
497  // If non-empty, this is the last known optimal lp solution at root-node. If
498  // the variable bounds changed, or cuts where added, it is possible that this
499  // solution is no longer optimal though.
500  std::vector<double> level_zero_lp_solution_;
501 
502  // True if the last time we solved the exact same LP at level zero, no cuts
503  // and no lazy constraints where added.
504  bool lp_at_level_zero_is_final_ = false;
505 
506  // Same as lp_solution_ but this vector is indexed differently.
507  LinearProgrammingConstraintLpSolution& expanded_lp_solution_;
508 
509  // Linear constraints cannot be created or modified after this is registered.
510  bool lp_constraint_is_registered_ = false;
511 
512  std::vector<CutGenerator> cut_generators_;
513 
514  // Store some statistics for HeuristicLPReducedCostAverage().
515  bool compute_reduced_cost_averages_ = false;
516  int num_calls_since_reduced_cost_averages_reset_ = 0;
517  std::vector<double> sum_cost_up_;
518  std::vector<double> sum_cost_down_;
519  std::vector<int> num_cost_up_;
520  std::vector<int> num_cost_down_;
521  std::vector<double> rc_scores_;
522 
523  // All the entries before rev_rc_start_ in the sorted positions correspond
524  // to fixed variables and can be ignored.
525  int rev_rc_start_ = 0;
526  RevRepository<int> rc_rev_int_repository_;
527  std::vector<std::pair<double, int>> positions_by_decreasing_rc_score_;
528 
529  // Defined as average number of nonbasic variables with zero reduced costs.
530  IncrementalAverage average_degeneracy_;
531  bool is_degenerate_ = false;
532 
533  // Used by the strong branching heuristic.
534  int branching_frequency_ = 1;
535  int64_t count_since_last_branching_ = 0;
536 
537  // Sum of all simplex iterations performed by this class. This is useful to
538  // test the incrementality and compare to other solvers.
539  int64_t total_num_simplex_iterations_ = 0;
540 
541  // Some stats on the LP statuses encountered.
542  int64_t num_solves_ = 0;
543  std::vector<int64_t> num_solves_by_status_;
544 };
545 
546 // A class that stores which LP propagator is associated to each variable.
547 // We need to give the hash_map a name so it can be used as a singleton in our
548 // model.
549 //
550 // Important: only positive variable do appear here.
552  : public absl::flat_hash_map<IntegerVariable,
553  LinearProgrammingConstraint*> {
554  public:
556 };
557 
558 // A class that stores the collection of all LP constraints in a model.
560  : public std::vector<LinearProgrammingConstraint*> {
561  public:
563 };
564 
565 // Cut generator for the circuit constraint, where in any feasible solution, the
566 // arcs that are present (variable at 1) must form a circuit through all the
567 // nodes of the graph. Self arc are forbidden in this case.
568 //
569 // In more generality, this currently enforce the resulting graph to be strongly
570 // connected. Note that we already assume basic constraint to be in the lp, so
571 // we do not add any cuts for components of size 1.
573  int num_nodes, const std::vector<int>& tails, const std::vector<int>& heads,
574  const std::vector<Literal>& literals, Model* model);
575 
576 // Almost the same as CreateStronglyConnectedGraphCutGenerator() but for each
577 // components, computes the demand needed to serves it, and depending on whether
578 // it contains the depot (node zero) or not, compute the minimum number of
579 // vehicle that needs to cross the component border.
580 CutGenerator CreateCVRPCutGenerator(int num_nodes,
581  const std::vector<int>& tails,
582  const std::vector<int>& heads,
583  const std::vector<Literal>& literals,
584  const std::vector<int64_t>& demands,
585  int64_t capacity, Model* model);
586 } // namespace sat
587 } // namespace operations_research
588 
589 #endif // OR_TOOLS_SAT_LINEAR_PROGRAMMING_CONSTRAINT_H_
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
const std::vector< IntegerVariable > & integer_variables() const
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
const std::string name
std::function< IntegerLiteral()> HeuristicLpMostInfeasibleBinary(Model *model)
ColIndex col
Definition: markowitz.cc:183
GRBmodel * model
CutGenerator CreateCVRPCutGenerator(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, const std::vector< int64_t > &demands, int64_t capacity, Model *model)
const std::vector< std::unique_ptr< IntegerSumLE > > & OptimalConstraints() const
std::vector< std::pair< glop::ColIndex, IntegerValue > > GetTerms()
double upper_bound
std::string GetDimensionString() const
Definition: lp_data.cc:425
CutGenerator CreateStronglyConnectedGraphCutGenerator(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< Literal > &literals, Model *model)
std::function< IntegerLiteral()> HeuristicLpReducedCostBinary(Model *model)
int64_t capacity
bool IncrementalPropagate(const std::vector< int > &watch_indices) override
void SetObjectiveCoefficient(IntegerVariable ivar, IntegerValue coeff)
Collection of objects used to extend the Constraint Solver library.
bool Add(glop::ColIndex col, IntegerValue value)
IntVar * var
Definition: expr_array.cc:1874
void ConvertToLinearConstraint(const std::vector< IntegerVariable > &integer_variables, IntegerValue upper_bound, LinearConstraint *result)
bool AddLinearExpressionMultiple(IntegerValue multiplier, const std::vector< std::pair< glop::ColIndex, IntegerValue >> &terms)
int64_t value
const Constraint * ct