@@ -523,6 +523,7 @@ class IntegerTrail final : public SatPropagator {
523523 // Returns the current value (if known) of an IntegerLiteral.
524524 bool IntegerLiteralIsTrue (IntegerLiteral l) const ;
525525 bool IntegerLiteralIsFalse (IntegerLiteral l) const ;
526+ bool IsTrueAtLevelZero (IntegerLiteral l) const ;
526527
527528 // Returns globally valid lower/upper bound on the given integer variable.
528529 IntegerValue LevelZeroLowerBound (IntegerVariable var) const ;
@@ -796,39 +797,38 @@ class IntegerTrail final : public SatPropagator {
796797 void AddAllGreaterThanConstantReason (absl::Span<AffineExpression> exprs,
797798 IntegerValue target_min,
798799 std::vector<int >* indices) const {
799- int64_t num_processed = 0 ;
800+ constexpr int64_t check_period = 1e6 ;
801+ int64_t limit_check = work_done_in_explain_lower_than_ + check_period;
800802 for (const AffineExpression& expr : exprs) {
801803 if (expr.IsConstant ()) {
802804 DCHECK_GE (expr.constant , target_min);
803805 continue ;
804806 }
805807 DCHECK_NE (expr.var , kNoIntegerVariable );
808+ const IntegerLiteral to_explain = expr.GreaterOrEqual (target_min);
809+ if (IsTrueAtLevelZero (to_explain)) continue ;
806810
807811 // On large routing problems, we can spend a lot of time in this loop.
808- // We check the time limit every 5 processed expressions.
809- if (++num_processed % 5 == 0 && time_limit_->LimitReached ()) return ;
812+ if (work_done_in_explain_lower_than_ > limit_check) {
813+ limit_check = work_done_in_explain_lower_than_ + check_period;
814+ if (time_limit_->LimitReached ()) return ;
815+ }
810816
811817 // Skip if we already have an explanation for expr >= target_min. Note
812818 // that we already do that while processing the returned indices, so this
813819 // mainly save a FindLowestTrailIndexThatExplainBound() call per skipped
814820 // indices, which can still be costly.
815821 {
816- const int index = tmp_var_to_trail_index_in_queue_[expr .var ];
822+ const int index = tmp_var_to_trail_index_in_queue_[to_explain .var ];
817823 if (index == std::numeric_limits<int >::max ()) continue ;
818- if (index > 0 &&
819- expr.ValueAt (integer_trail_[index].bound ) >= target_min) {
824+ if (index > 0 && integer_trail_[index].bound >= to_explain.bound ) {
820825 has_dependency_ = true ;
821826 continue ;
822827 }
823828 }
824829
825830 // We need to find the index that explain the bound.
826- // Note that this will skip if the condition is true at level zero.
827- const int index =
828- FindLowestTrailIndexThatExplainBound (expr.GreaterOrEqual (target_min));
829- if (index >= 0 ) {
830- indices->push_back (index);
831- }
831+ indices->push_back (FindLowestTrailIndexThatExplainBound (to_explain));
832832 }
833833 }
834834
@@ -885,8 +885,8 @@ class IntegerTrail final : public SatPropagator {
885885 int64_t conflict_id) const ;
886886
887887 // Returns the lowest trail index of a TrailEntry that can be used to explain
888- // the given IntegerLiteral. The literal must be currently true (CHECKed).
889- // Returns -1 if the explanation is trivial .
888+ // the given IntegerLiteral. The literal must be currently true but not true
889+ // at level zero (DCHECKed) .
890890 int FindLowestTrailIndexThatExplainBound (IntegerLiteral i_lit) const ;
891891
892892 // This must be called before Dependencies() or AppendLiteralsReason().
@@ -1033,6 +1033,8 @@ class IntegerTrail final : public SatPropagator {
10331033 std::vector<SparseBitset<IntegerVariable>*> watchers_;
10341034 std::vector<ReversibleInterface*> reversible_classes_;
10351035
1036+ mutable int64_t work_done_in_explain_lower_than_ = 0 ;
1037+
10361038 mutable Domain temp_domain_;
10371039 DelayedRootLevelDeduction* delayed_to_fix_;
10381040 IntegerDomains* domains_;
@@ -1417,6 +1419,10 @@ inline bool IntegerTrail::IntegerLiteralIsFalse(IntegerLiteral l) const {
14171419 return l.bound > UpperBound (l.var );
14181420}
14191421
1422+ inline bool IntegerTrail::IsTrueAtLevelZero (IntegerLiteral l) const {
1423+ return l.bound <= LevelZeroLowerBound (l.var );
1424+ }
1425+
14201426// The level zero bounds are stored at the beginning of the trail and they also
14211427// serves as sentinels. Their index match the variables index.
14221428inline IntegerValue IntegerTrail::LevelZeroLowerBound (
0 commit comments