Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
linear_programming_constraint.h
Go to the documentation of this file.
1// Copyright 2010-2024 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 <optional>
22#include <string>
23#include <utility>
24#include <vector>
25
26#include "absl/container/flat_hash_map.h"
27#include "absl/numeric/int128.h"
28#include "absl/strings/string_view.h"
29#include "absl/types/span.h"
31#include "ortools/glop/parameters.pb.h"
37#include "ortools/sat/cp_model.pb.h"
39#include "ortools/sat/cuts.h"
41#include "ortools/sat/integer.h"
45#include "ortools/sat/model.h"
47#include "ortools/sat/sat_parameters.pb.h"
49#include "ortools/sat/util.h"
51#include "ortools/util/rev.h"
54
55namespace operations_research {
56namespace sat {
57
58// Simple class to combine linear expression efficiently. First in a sparse
59// way that switch to dense when the number of non-zeros grows.
61 public:
62 // This must be called with the correct size before any other functions are
63 // used.
64 void ClearAndResize(int size);
65
66 // Does vector[col] += value and return false in case of overflow.
67 bool Add(glop::ColIndex col, IntegerValue value);
68
69 // Similar to Add() but for multiplier * terms.
70 //
71 // Returns false if we encountered any integer overflow. If the template bool
72 // is false, we do not check for a bit of extra speed.
73 template <bool check_overflow = true>
74 bool AddLinearExpressionMultiple(IntegerValue multiplier,
75 absl::Span<const glop::ColIndex> cols,
76 absl::Span<const IntegerValue> coeffs);
77
78 // This is not const only because non_zeros is sorted. Note that sorting the
79 // non-zeros make the result deterministic whether or not we were in sparse
80 // mode.
81 //
82 // TODO(user): Ideally we should convert to IntegerVariable as late as
83 // possible. Prefer to use GetTerms().
85 absl::Span<const IntegerVariable> integer_variables,
86 IntegerValue upper_bound,
87 std::optional<std::pair<IntegerVariable, IntegerValue>> extra_term =
88 std::nullopt);
89
90 void ConvertToCutData(absl::int128 rhs,
91 absl::Span<const IntegerVariable> integer_variables,
92 absl::Span<const double> lp_solution,
93 IntegerTrail* integer_trail, CutData* result);
94
95 // Similar to ConvertToLinearConstraint().
96 std::vector<std::pair<glop::ColIndex, IntegerValue>> GetTerms();
97
98 // We only provide the const [].
99 IntegerValue operator[](glop::ColIndex col) const {
100 return dense_vector_[col];
101 }
102
103 bool IsSparse() const { return is_sparse_; }
104
105 private:
106 // If is_sparse is true we maintain the non_zeros positions and bool vector
107 // of dense_vector_. Otherwise we don't. Note that we automatically switch
108 // from sparse to dense as needed.
109 bool is_sparse_ = true;
110 std::vector<glop::ColIndex> non_zeros_;
112
113 // The dense representation of the vector.
115};
116
117// A SAT constraint that enforces a set of linear inequality constraints on
118// integer variables using an LP solver.
119//
120// The propagator uses glop's revised simplex for feasibility and propagation.
121// It uses the Reduced Cost Strengthening technique, a classic in mixed integer
122// programming, for instance see the thesis of Tobias Achterberg,
123// "Constraint Integer Programming", sections 7.7 and 8.8, algorithm 7.11.
124// http://nbn-resolving.de/urn:nbn:de:0297-zib-11129
125//
126// Per-constraint bounds propagation is NOT done by this constraint,
127// it should be done by redundant constraints, as reduced cost propagation
128// may miss some filtering.
129//
130// Note that this constraint works with double floating-point numbers, so one
131// could be worried that it may filter too much in case of precision issues.
132// However, by default, we interpret the LP result by recomputing everything
133// in integer arithmetic, so we are exact.
134class LinearProgrammingDispatcher;
135
138 public:
139 typedef glop::RowIndex ConstraintIndex;
140
141 // Each linear programming constraint works on a fixed set of variables.
142 // We expect the set of variable to be sorted in increasing order.
144 absl::Span<const IntegerVariable> vars);
145
146 // Add a new linear constraint to this LP.
148
149 // Set the coefficient of the variable in the objective. Calling it twice will
150 // overwrite the previous value.
151 void SetObjectiveCoefficient(IntegerVariable ivar, IntegerValue coeff);
152
153 // The main objective variable should be equal to the linear sum of
154 // the arguments passed to SetObjectiveCoefficient().
155 void SetMainObjectiveVariable(IntegerVariable ivar) { objective_cp_ = ivar; }
156 IntegerVariable ObjectiveVariable() const { return objective_cp_; }
157
158 // Register a new cut generator with this constraint.
159 void AddCutGenerator(CutGenerator generator);
160
161 // Returns the LP value and reduced cost of a variable in the current
162 // solution. These functions should only be called when HasSolution() is true.
163 //
164 // Note that this solution is always an OPTIMAL solution of an LP above or
165 // at the current decision level. We "erase" it when we backtrack over it.
166 bool HasSolution() const { return lp_solution_is_set_; }
167 double GetSolutionValue(IntegerVariable variable) const;
168 double GetSolutionReducedCost(IntegerVariable variable) const;
169 bool SolutionIsInteger() const { return lp_solution_is_integer_; }
170
171 // Returns a valid lp lower bound for the current branch, and indicates if
172 // the latest LP solve in that branch was solved to optimality or not.
173 // During normal operation, we will always propagate the LP, so this should
174 // not refer to an optimality status lower in that branch.
175 bool AtOptimal() const { return lp_at_optimal_; }
176 double ObjectiveLpLowerBound() const { return lp_objective_lower_bound_; }
177
178 // PropagatorInterface API.
179 bool Propagate() override;
180 bool IncrementalPropagate(const std::vector<int>& watch_indices) override;
181 void RegisterWith(Model* model);
182
183 // ReversibleInterface API.
184 void SetLevel(int level) override;
185
186 int NumVariables() const {
187 return static_cast<int>(integer_variables_.size());
188 }
189 const std::vector<IntegerVariable>& integer_variables() const {
190 return integer_variables_;
191 }
192 std::string DimensionString() const { return lp_data_.GetDimensionString(); }
193
194 // Returns a IntegerLiteral guided by the underlying LP constraints.
195 //
196 // This computes the mean of reduced costs over successive calls,
197 // and tries to fix the variable which has the highest reduced cost.
198 // Tie-breaking is done using the variable natural order.
200
201 // Average number of nonbasic variables with zero reduced costs.
202 double average_degeneracy() const {
203 return average_degeneracy_.CurrentAverage();
204 }
205
206 // Stats.
208 return total_num_simplex_iterations_;
209 }
211 return total_num_cut_propagations_;
212 }
214 return total_num_eq_propagations_;
215 }
216 int64_t num_solves() const { return num_solves_; }
217 int64_t num_adjusts() const { return num_adjusts_; }
218 int64_t num_cut_overflows() const { return num_cut_overflows_; }
219 int64_t num_bad_cuts() const { return num_bad_cuts_; }
220 int64_t num_scaling_issues() const { return num_scaling_issues_; }
221
222 // This can serve as a timestamp to know if a saved basis is out of date.
223 int64_t num_lp_changes() const { return num_lp_changes_; }
224
225 const std::vector<int64_t>& num_solves_by_status() const {
226 return num_solves_by_status_;
227 }
228
230 return constraint_manager_;
231 }
232
233 // Important: this is only temporarily valid.
235 if (optimal_constraints_.empty()) return nullptr;
236 return optimal_constraints_.back().get();
237 }
238
239 const std::vector<std::unique_ptr<IntegerSumLE128>>& OptimalConstraints()
240 const {
241 return optimal_constraints_;
242 }
243
244 // This api allows to temporarily disable the LP propagator which can be
245 // costly during probing or other heavy propagation phase.
246 void EnablePropagation(bool enable) {
247 enabled_ = enable;
248 watcher_->CallOnNextPropagate(watcher_id_);
249 }
250 bool PropagationIsEnabled() const { return enabled_; }
251
252 const glop::BasisState& GetBasisState() const { return state_; }
253 void LoadBasisState(const glop::BasisState& state) {
254 state_ = state;
255 simplex_.LoadStateForNextSolve(state_);
256 }
257
258 private:
259 // Helper method to fill reduced cost / dual ray reason in 'integer_reason'.
260 // Generates a set of IntegerLiterals explaining why the best solution can not
261 // be improved using reduced costs. This is used to generate explanations for
262 // both infeasibility and bounds deductions.
263 void FillReducedCostReasonIn(const glop::DenseRow& reduced_costs,
264 std::vector<IntegerLiteral>* integer_reason);
265
266 // Reinitialize the LP from a potentially new set of constraints.
267 // This fills all data structure and properly rescale the underlying LP.
268 //
269 // Returns false if the problem is UNSAT (it can happen when presolve is off
270 // and some LP constraint are trivially false).
271 bool CreateLpFromConstraintManager();
272
273 // Solve the LP, returns false if something went wrong in the LP solver.
274 bool SolveLp();
275
276 // Analyzes the result of an LP Solution. Returns false on conflict.
277 bool AnalyzeLp();
278
279 // Does some basic preprocessing of a cut candidate. Returns false if we
280 // should abort processing this candidate.
281 bool PreprocessCut(IntegerVariable first_slack, CutData* cut);
282
283 // Add a "MIR" cut obtained by first taking the linear combination of the
284 // row of the matrix according to "integer_multipliers" and then trying
285 // some integer rounding heuristic.
286 //
287 // Return true if a new cut was added to the cut manager.
288 bool AddCutFromConstraints(
289 absl::string_view name,
290 absl::Span<const std::pair<glop::RowIndex, IntegerValue>>
291 integer_multipliers);
292
293 // Second half of AddCutFromConstraints().
294 bool PostprocessAndAddCut(const std::string& name, const std::string& info,
295 IntegerVariable first_slack, const CutData& cut);
296
297 // Computes and adds the corresponding type of cuts.
298 // This can currently only be called at the root node.
299 void AddObjectiveCut();
300 void AddCGCuts();
301 void AddMirCuts();
302 void AddZeroHalfCuts();
303
304 // Updates the bounds of the LP variables from the CP bounds.
305 void UpdateBoundsOfLpVariables();
306
307 // Use the dual optimal lp values to compute an EXACT lower bound on the
308 // objective. Fills its reason and perform reduced cost strenghtening.
309 // Returns false in case of conflict.
310 bool PropagateExactLpReason();
311
312 // Same as FillDualRayReason() but perform the computation EXACTLY. Returns
313 // false in the case that the problem is not provably infeasible with exact
314 // computations, true otherwise.
315 bool PropagateExactDualRay();
316
317 // Called by PropagateExactLpReason() and PropagateExactDualRay() to finish
318 // propagation.
319 bool PropagateLpConstraint(LinearConstraint ct);
320
321 // Returns number of non basic variables with zero reduced costs.
322 int64_t CalculateDegeneracy();
323
324 // From a set of row multipliers (at LP scale), scale them back to the CP
325 // world and then make them integer (eventually multiplying them by a new
326 // scaling factor returned in *scaling).
327 //
328 // Note that this will loose some precision, but our subsequent computation
329 // will still be exact as it will work for any set of multiplier.
330 std::vector<std::pair<glop::RowIndex, IntegerValue>> ScaleLpMultiplier(
331 bool take_objective_into_account, bool ignore_trivial_constraints,
332 const std::vector<std::pair<glop::RowIndex, double>>& lp_multipliers,
333 IntegerValue* scaling,
334 int64_t overflow_cap = std::numeric_limits<int64_t>::max()) const;
335
336 // Can we have an overflow if we scale each coefficients with
337 // std::round(std::ldexp(coeff, power)) ?
338 bool ScalingCanOverflow(
339 int power, bool take_objective_into_account,
340 absl::Span<const std::pair<glop::RowIndex, double>> multipliers,
341 int64_t overflow_cap) const;
342
343 // Computes from an integer linear combination of the integer rows of the LP a
344 // new constraint of the form "sum terms <= upper_bound". All computation are
345 // exact here.
346 //
347 // Returns false if we encountered any integer overflow. If the template bool
348 // is false, we do not check for a bit of extra speed.
349 template <bool check_overflow = true>
350 bool ComputeNewLinearConstraint(
351 absl::Span<const std::pair<glop::RowIndex, IntegerValue>>
352 integer_multipliers,
353 ScatteredIntegerVector* scattered_vector,
354 IntegerValue* upper_bound) const;
355
356 // Simple heuristic to try to minimize |upper_bound - ImpliedLB(terms)|. This
357 // should make the new constraint tighter and correct a bit the imprecision
358 // introduced by rounding the floating points values.
359 void AdjustNewLinearConstraint(
360 std::vector<std::pair<glop::RowIndex, IntegerValue>>* integer_multipliers,
361 ScatteredIntegerVector* scattered_vector,
362 IntegerValue* upper_bound) const;
363
364 // Shortcut for an integer linear expression type.
365 using LinearExpression = std::vector<std::pair<glop::ColIndex, IntegerValue>>;
366
367 // Converts a dense representation of a linear constraint to a sparse one
368 // expressed in terms of IntegerVariable.
369 void ConvertToLinearConstraint(
371 dense_vector,
372 IntegerValue upper_bound, LinearConstraint* result);
373
374 // Compute the implied lower bound of the given linear expression using the
375 // current variable bound.
376 absl::int128 GetImpliedLowerBound(const LinearConstraint& terms) const;
377
378 // Fills the deductions vector with reduced cost deductions that can be made
379 // from the current state of the LP solver. The given delta should be the
380 // difference between the cp objective upper bound and lower bound given by
381 // the lp.
382 void ReducedCostStrengtheningDeductions(double cp_objective_delta);
383
384 // Returns the variable value on the same scale as the CP variable value.
385 glop::Fractional GetVariableValueAtCpScale(glop::ColIndex var);
386
387 // Gets an LP variable that mirrors a CP variable.
388 // The variable should be a positive reference.
389 glop::ColIndex GetMirrorVariable(IntegerVariable positive_variable);
390
391 // This must be called on an OPTIMAL LP and will update the data for
392 // LPReducedCostAverageDecision().
393 void UpdateAverageReducedCosts();
394
395 // Callback underlying LPReducedCostAverageBranching().
396 IntegerLiteral LPReducedCostAverageDecision();
397
398 // Updates the simplex iteration limit for the next visit.
399 // As per current algorithm, we use a limit which is dependent on size of the
400 // problem and drop it significantly if degeneracy is detected. We use
401 // DUAL_FEASIBLE status as a signal to correct the prediction. The next limit
402 // is capped by 'min_iter' and 'max_iter'. Note that this is enabled only for
403 // linearization level 2 and above.
404 void UpdateSimplexIterationLimit(int64_t min_iter, int64_t max_iter);
405
406 // Returns the col/coeff of integer_lp_[row].
407 absl::Span<const glop::ColIndex> IntegerLpRowCols(glop::RowIndex row) const;
408 absl::Span<const IntegerValue> IntegerLpRowCoeffs(glop::RowIndex row) const;
409
410 // This epsilon is related to the precision of the value/reduced_cost returned
411 // by the LP once they have been scaled back into the CP domain. So for large
412 // domain or cost coefficient, we may have some issues.
413 static constexpr double kCpEpsilon = 1e-4;
414
415 // Same but at the LP scale.
416 static constexpr double kLpEpsilon = 1e-6;
417
418 // Anything coming from the LP with a magnitude below that will be assumed to
419 // be zero.
420 static constexpr double kZeroTolerance = 1e-12;
421
422 // Class responsible for managing all possible constraints that may be part
423 // of the LP.
424 LinearConstraintManager constraint_manager_;
425
426 // We do not want to add too many cut during each generation round.
427 TopNCuts top_n_cuts_ = TopNCuts(10);
428
429 // Initial problem in integer form.
430 // We always sort the inner vectors by increasing glop::ColIndex.
431 struct LinearConstraintInternal {
432 IntegerValue lb;
433 IntegerValue ub;
434
435 // Point in integer_lp_cols_/integer_lp_coeffs_ for the actual data.
436 int start_in_buffer;
437 int num_terms;
438
439 bool lb_is_trivial = false;
440 bool ub_is_trivial = false;
441 };
442 std::vector<glop::ColIndex> integer_lp_cols_;
443 std::vector<IntegerValue> integer_lp_coeffs_;
444
445 std::vector<glop::ColIndex> tmp_cols_;
446 std::vector<IntegerValue> tmp_coeffs_;
447
448 LinearExpression integer_objective_;
449 IntegerValue integer_objective_offset_ = IntegerValue(0);
450 IntegerValue objective_infinity_norm_ = IntegerValue(0);
452 integer_lp_;
454
455 // Underlying LP solver API.
456 glop::GlopParameters simplex_params_;
457 glop::BasisState state_;
458 glop::LinearProgram lp_data_;
459 glop::RevisedSimplex simplex_;
460 int64_t next_simplex_iter_ = 500;
461
462 // For the scaling.
463 glop::LpScalingHelper scaler_;
464
465 // Temporary data for cuts.
466 ZeroHalfCutHelper zero_half_cut_helper_;
467 CoverCutHelper cover_cut_helper_;
468 IntegerRoundingCutHelper integer_rounding_cut_helper_;
469
470 bool problem_proven_infeasible_by_cuts_ = false;
471 CutData base_ct_;
472
473 ScatteredIntegerVector tmp_scattered_vector_;
474
475 std::vector<double> tmp_lp_values_;
476 std::vector<IntegerValue> tmp_var_lbs_;
477 std::vector<IntegerValue> tmp_var_ubs_;
478 std::vector<glop::RowIndex> tmp_slack_rows_;
479 std::vector<std::pair<glop::ColIndex, IntegerValue>> tmp_terms_;
480
481 // Used by AddCGCuts().
482 std::vector<std::pair<glop::RowIndex, double>> tmp_lp_multipliers_;
483 std::vector<std::pair<glop::RowIndex, IntegerValue>> tmp_integer_multipliers_;
484
485 // Used by ScaleLpMultiplier().
486 mutable std::vector<std::pair<glop::RowIndex, double>> tmp_cp_multipliers_;
487
488 // Structures used for mirroring IntegerVariables inside the underlying LP
489 // solver: an integer variable var is mirrored by mirror_lp_variable_[var].
490 // Note that these indices are dense in [0, mirror_lp_variable_.size()] so
491 // they can be used as vector indices.
492 //
493 // TODO(user): This should be util_intops::StrongVector<glop::ColIndex,
494 // IntegerVariable> Except if we have too many LinearProgrammingConstraint.
495 std::vector<IntegerVariable> integer_variables_;
496 absl::flat_hash_map<IntegerVariable, glop::ColIndex> mirror_lp_variable_;
497
498 // We need to remember what to optimize if an objective is given, because
499 // then we will switch the objective between feasibility and optimization.
500 bool objective_is_defined_ = false;
501 IntegerVariable objective_cp_;
502
503 // Singletons from Model.
504 //
505 // TODO(user): ObjectiveDefinition and SharedResponseManager are only needed
506 // to report the objective bounds during propagation, find a better way to
507 // avoid some of these dependencies?
508 const SatParameters& parameters_;
509 Model* model_;
510 TimeLimit* time_limit_;
511 IntegerTrail* integer_trail_;
512 Trail* trail_;
513 GenericLiteralWatcher* watcher_;
514 IntegerEncoder* integer_encoder_;
515 ProductDetector* product_detector_;
516 ObjectiveDefinition* objective_definition_;
517 SharedStatistics* shared_stats_;
518 SharedResponseManager* shared_response_manager_;
519 ModelRandomGenerator* random_;
520
521 int watcher_id_;
522
523 BoolRLTCutHelper rlt_cut_helper_;
524
525 // Used while deriving cuts.
526 ImpliedBoundsProcessor implied_bounds_processor_;
527
528 // The dispatcher for all LP propagators of the model, allows to find which
529 // LinearProgrammingConstraint has a given IntegerVariable.
530 LinearProgrammingDispatcher* dispatcher_;
531
532 std::vector<IntegerLiteral> integer_reason_;
533 std::vector<IntegerLiteral> deductions_;
534 std::vector<IntegerLiteral> deductions_reason_;
535
536 // Repository of IntegerSumLE128 that needs to be kept around for the lazy
537 // reasons. Those are new integer constraint that are created each time we
538 // solve the LP to a dual-feasible solution. Propagating these constraints
539 // both improve the objective lower bound but also perform reduced cost
540 // fixing.
541 int rev_optimal_constraints_size_ = 0;
542 std::vector<std::unique_ptr<IntegerSumLE128>> optimal_constraints_;
543 std::vector<int64_t> cumulative_optimal_constraint_sizes_;
544
545 // Last OPTIMAL solution found by a call to the underlying LP solver.
546 // On IncrementalPropagate(), if the bound updates do not invalidate this
547 // solution, Propagate() will not find domain reductions, no need to call it.
548 int lp_solution_level_ = 0;
549 bool lp_solution_is_set_ = false;
550 bool lp_solution_is_integer_ = false;
551 std::vector<double> lp_solution_;
552 std::vector<double> lp_reduced_cost_;
553
554 // Last objective lower bound found by the LP Solver.
555 // We erase this on backtrack.
556 int previous_level_ = 0;
557 bool lp_at_optimal_ = false;
558 double lp_objective_lower_bound_;
559
560 // If non-empty, this is the last known optimal lp solution at root-node. If
561 // the variable bounds changed, or cuts where added, it is possible that this
562 // solution is no longer optimal though.
563 std::vector<double> level_zero_lp_solution_;
564
565 // True if the last time we solved the exact same LP at level zero, no cuts
566 // and no lazy constraints where added.
567 bool lp_at_level_zero_is_final_ = false;
568
569 // Same as lp_solution_ but this vector is indexed by IntegerVariable.
570 ModelLpValues& expanded_lp_solution_;
571
572 // Linear constraints cannot be created or modified after this is registered.
573 bool lp_constraint_is_registered_ = false;
574
575 std::vector<CutGenerator> cut_generators_;
576
577 // Store some statistics for HeuristicLPReducedCostAverage().
578 bool compute_reduced_cost_averages_ = false;
579 int num_calls_since_reduced_cost_averages_reset_ = 0;
580 std::vector<double> sum_cost_up_;
581 std::vector<double> sum_cost_down_;
582 std::vector<int> num_cost_up_;
583 std::vector<int> num_cost_down_;
584 std::vector<double> rc_scores_;
585
586 // All the entries before rev_rc_start_ in the sorted positions correspond
587 // to fixed variables and can be ignored.
588 int rev_rc_start_ = 0;
589 RevRepository<int> rc_rev_int_repository_;
590 std::vector<std::pair<double, int>> positions_by_decreasing_rc_score_;
591
592 // Defined as average number of nonbasic variables with zero reduced costs.
593 IncrementalAverage average_degeneracy_;
594 bool is_degenerate_ = false;
595
596 // Sum of all simplex iterations performed by this class. This is useful to
597 // test the incrementality and compare to other solvers.
598 int64_t total_num_simplex_iterations_ = 0;
599
600 // As we form candidate form cuts, sometimes we can propagate level zero
601 // bounds with them.
602 FirstFewValues<10> reachable_;
603 int64_t total_num_cut_propagations_ = 0;
604 int64_t total_num_eq_propagations_ = 0;
605
606 // The number of times we changed the LP.
607 int64_t num_lp_changes_ = 0;
608
609 // Some stats on the LP statuses encountered.
610 int64_t num_solves_ = 0;
611 mutable int64_t num_adjusts_ = 0;
612 mutable int64_t num_cut_overflows_ = 0;
613 mutable int64_t num_bad_cuts_ = 0;
614 mutable int64_t num_scaling_issues_ = 0;
615 std::vector<int64_t> num_solves_by_status_;
616
617 // We might temporarily disable the LP propagation.
618 bool enabled_ = true;
619};
620
621// A class that stores which LP propagator is associated to each variable.
622// We need to give the hash_map a name so it can be used as a singleton in our
623// model.
624//
625// Important: only positive variable do appear here.
627 : public absl::flat_hash_map<IntegerVariable,
628 LinearProgrammingConstraint*> {};
629
630// A class that stores the collection of all LP constraints in a model.
632 : public std::vector<LinearProgrammingConstraint*> {
633 public:
635 : std::vector<LinearProgrammingConstraint*>() {
637 ->callbacks.push_back([this](CpSolverResponse* response) {
638 int64_t num_lp_iters = 0;
639 for (const LinearProgrammingConstraint* lp : *this) {
640 num_lp_iters += lp->total_num_simplex_iterations();
641 }
642 response->set_num_lp_iterations(num_lp_iters);
643 });
644 }
645};
646
647} // namespace sat
648} // namespace operations_research
649
650#endif // OR_TOOLS_SAT_LINEAR_PROGRAMMING_CONSTRAINT_H_
IntegerValue size
std::string GetDimensionString() const
A short string with the problem dimension.
Definition lp_data.cc:434
Entry point of the revised simplex algorithm implementation.
void LoadStateForNextSolve(const BasisState &state)
Uses the given state as a warm-start for the next Solve() call.
void CallOnNextPropagate(int id)
Add the given propagator to its queue.
Definition integer.cc:2108
A class that stores the collection of all LP constraints in a model.
int64_t num_lp_changes() const
This can serve as a timestamp to know if a saved basis is out of date.
const std::vector< std::unique_ptr< IntegerSumLE128 > > & OptimalConstraints() const
IntegerSumLE128 * LatestOptimalConstraintOrNull() const
Important: this is only temporarily valid.
void SetLevel(int level) override
ReversibleInterface API.
void AddCutGenerator(CutGenerator generator)
Register a new cut generator with this constraint.
void AddLinearConstraint(LinearConstraint ct)
Add a new linear constraint to this LP.
void SetObjectiveCoefficient(IntegerVariable ivar, IntegerValue coeff)
bool IncrementalPropagate(const std::vector< int > &watch_indices) override
LinearProgrammingConstraint(Model *model, absl::Span< const IntegerVariable > vars)
const std::vector< IntegerVariable > & integer_variables() const
double average_degeneracy() const
Average number of nonbasic variables with zero reduced costs.
Base class for CP like propagators.
Definition integer.h:1414
bool AddLinearExpressionMultiple(IntegerValue multiplier, absl::Span< const glop::ColIndex > cols, absl::Span< const IntegerValue > coeffs)
bool Add(glop::ColIndex col, IntegerValue value)
Does vector[col] += value and return false in case of overflow.
LinearConstraint ConvertToLinearConstraint(absl::Span< const IntegerVariable > integer_variables, IntegerValue upper_bound, std::optional< std::pair< IntegerVariable, IntegerValue > > extra_term=std::nullopt)
void ConvertToCutData(absl::int128 rhs, absl::Span< const IntegerVariable > integer_variables, absl::Span< const double > lp_solution, IntegerTrail *integer_trail, CutData *result)
std::vector< std::pair< glop::ColIndex, IntegerValue > > GetTerms()
Similar to ConvertToLinearConstraint().
IntegerValue operator[](glop::ColIndex col) const
We only provide the const [].
const std::string name
A name for logging purposes.
const Constraint * ct
int64_t value
IntVar * var
double upper_bound
GRBmodel * model
ColIndex col
Definition markowitz.cc:187
RowIndex row
Definition markowitz.cc:186
In SWIG mode, we don't want anything besides these top-level includes.
STL namespace.
std::vector< std::function< void(CpSolverResponse *)> > callbacks
Our cut are always of the form linear_expression <= rhs.
Definition cuts.h:110