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