@@ -72,7 +72,8 @@ ContinuousProber::ContinuousProber(const CpModelProto& model_proto,
7272 shared_bounds_manager_(model->Mutable<SharedBoundsManager>()),
7373 shared_stats_(model->Mutable<SharedStatistics>()),
7474 random_(*model->GetOrCreate<ModelRandomGenerator>()),
75- base_dtime_(parameters_.shaving_deterministic_time_in_probing_search()) {
75+ base_dtime_(parameters_.shaving_deterministic_time_in_probing_search()),
76+ shaving_success_rate_(/* average_window_size=*/ 100 ) {
7677 auto * mapping = model_->GetOrCreate <CpModelMapping>();
7778 absl::flat_hash_set<BooleanVariable> visited;
7879
@@ -140,11 +141,6 @@ SatSolver::Status ContinuousProber::Probe() {
140141
141142 while (!time_limit_->LimitReached ()) {
142143 const double kMaxProbingTimePerMethod = 0.1 ;
143- // Store current statistics to detect shaving without any improvement.
144- int64_t starting_shaving_literals =
145- counters_.shaving .num_new_literals_fixed ;
146- int64_t starting_shaving_bounds = counters_.shaving .num_new_bounds ;
147-
148144 std::optional<SatSolver::Status> status = ProbeIntegerVariables (
149145 time_limit_->GetElapsedDeterministicTime () + kMaxProbingTimePerMethod );
150146 if (status.has_value ()) return status.value ();
@@ -181,22 +177,6 @@ SatSolver::Status ContinuousProber::Probe() {
181177
182178 // Alternate between shaving and non-shaving phases.
183179 if (use_shaving_) {
184- if (counters_.shaving .num_new_literals_fixed >
185- starting_shaving_literals ||
186- counters_.shaving .num_new_bounds > starting_shaving_bounds) {
187- // We improved something. We reduce the multiplier by a factor of 2.
188- // TODO(user): We could not go below 1.0 and increase the base
189- // dtime.
190- limit_multiplier_ = std::max (1.0 , limit_multiplier_ / 2 );
191-
192- // Update reference counters.
193- starting_shaving_literals = counters_.shaving .num_new_literals_fixed ;
194- starting_shaving_bounds = counters_.shaving .num_new_bounds ;
195- } else if (limit_multiplier_ < 16.0 ) {
196- limit_multiplier_ *= 1.5 ; // Cap the maximum limit to 16 * dtime.
197- }
198-
199- // Alternating shaving and non-shaving iterations.
200180 use_shaving_ = false ;
201181 } else {
202182 use_shaving_ = base_dtime_ > 0.0 ;
@@ -533,6 +513,25 @@ bool ContinuousProber::IsOrbitRepresentative(int var) const {
533513 return var_to_representative_[var] == var;
534514}
535515
516+ void ContinuousProber::AdaptShavingMultiplier (bool success) {
517+ if (success) {
518+ shaving_success_rate_.Add (1.0 );
519+ } else {
520+ shaving_success_rate_.Add (0.0 );
521+ }
522+ // TODO(user): Try to wait until the window is full before adapting the
523+ // multiplier.
524+ if (--update_frequency_ <= 0 ) {
525+ update_frequency_ = kShavingUpdateFrequency ;
526+ const double rate = shaving_success_rate_.WindowAverage ();
527+ if (rate > 0.5 && limit_multiplier_ > 0.5 ) {
528+ limit_multiplier_ = std::max (0.5 , limit_multiplier_ * 0.95 );
529+ } else if (rate < 0.05 && limit_multiplier_ < 10.0 ) {
530+ limit_multiplier_ = std::min (20.0 , limit_multiplier_ * 1.1 );
531+ }
532+ }
533+ }
534+
536535SatSolver::Status ContinuousProber::ShaveLiteral (
537536 Literal literal, bool literal_is_an_integer_bound) {
538537 if (trail_->Assignment ().LiteralIsAssigned (literal)) {
@@ -548,6 +547,8 @@ SatSolver::Status ContinuousProber::ShaveLiteral(
548547 base_dtime_ * limit_multiplier_));
549548 const SatSolver::Status status =
550549 ResetAndSolveIntegerProblem ({literal}, model_);
550+ AdaptShavingMultiplier (status == SatSolver::ASSUMPTIONS_UNSAT ||
551+ status == SatSolver::FEASIBLE );
551552 time_limit_->ChangeDeterministicLimit (original_dtime_limit);
552553 if (ReportStatus (status)) return status;
553554
0 commit comments