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