diff --git a/ortools/set_cover/set_cover_invariant.cc b/ortools/set_cover/set_cover_invariant.cc index fbb340e478..36f7653dec 100644 --- a/ortools/set_cover/set_cover_invariant.cc +++ b/ortools/set_cover/set_cover_invariant.cc @@ -131,6 +131,25 @@ void SetCoverInvariant::LoadSolution(const SubsetBoolVector& solution) { consistency_level_ = CL::kCostAndCoverage; } +void SetCoverInvariant::LoadTraceAndCoverage( + const std::vector& trace, + const ElementToIntVector& coverage) { + ClearRemovabilityInformation(); + is_selected_.assign(model_->num_subsets(), false); + trace_ = trace; + coverage_ = coverage; + cost_ = 0.0; + for (const SetCoverDecision& decision : trace) { + if (decision.decision()) { + const SubsetIndex subset(decision.subset()); + is_selected_[subset] = true; + cost_ += model_->subset_costs()[subset]; + } + } + consistency_level_ = CL::kCostAndCoverage; + DCHECK(CheckConsistency(CL::kCostAndCoverage)); +} + bool SetCoverInvariant::NeedToRecompute(ConsistencyLevel cheched_consistency, ConsistencyLevel target_consistency) { return consistency_level_ < cheched_consistency && diff --git a/ortools/set_cover/set_cover_invariant.h b/ortools/set_cover/set_cover_invariant.h index 08ad3d7be7..37e0b8e338 100644 --- a/ortools/set_cover/set_cover_invariant.h +++ b/ortools/set_cover/set_cover_invariant.h @@ -165,6 +165,15 @@ class SetCoverInvariant { // Loads the solution and recomputes the data in the invariant. void LoadSolution(const SubsetBoolVector& solution); + // Loads the trace and the coverage. When both the trace and the coverage are + // loaded, the invariant is consistent at level kCostAndCoverage. + // It's also faster than to load a solution and recompute the cost and + // coverage. The trace and the coverage are expected to be consistent, + // otherwise the behavior is undefined (i.e. the invariant is not consistent, + // unless the code is run in DEBUG mode). + void LoadTraceAndCoverage(const std::vector& trace, + const ElementToIntVector& coverage); + // Checks the consistency of the invariant at the given consistency level. bool CheckConsistency(ConsistencyLevel consistency) const; diff --git a/ortools/set_cover/set_cover_test.cc b/ortools/set_cover/set_cover_test.cc index ec52c47298..b9a9c272b2 100644 --- a/ortools/set_cover/set_cover_test.cc +++ b/ortools/set_cover/set_cover_test.cc @@ -96,6 +96,7 @@ class KnightsCover { const SetCoverInvariant::ConsistencyLevel consistency, int row, int col, int radius, SetCoverInvariant* inv) const { std::vector cleared_subsets; + cleared_subsets.reserve((2 * radius + 1) * (2 * radius + 1)); for (int r = row - radius; r <= row + radius; ++r) { for (int c = col - radius; c <= col + radius; ++c) { if (!IsOnBoard(r, c)) continue; @@ -408,7 +409,8 @@ TEST(SetCoverTest, KnightsCoverElementDegreeRadiusClear) { SetCoverModel model = knights.model(); SetCoverInvariant inv(&model); Cost best_cost = std::numeric_limits::max(); - SubsetBoolVector best_choices; + std::vector best_trace; + ElementToIntVector best_coverage; int iteration = 0; for (int radius = 7; radius >= 1; --radius) { for (int row = 0; row < BoardSize; ++row) { @@ -422,11 +424,13 @@ TEST(SetCoverTest, KnightsCoverElementDegreeRadiusClear) { if (inv.cost() < best_cost) { best_cost = inv.cost(); - best_choices = inv.is_selected(); + inv.CompressTrace(); + best_trace = inv.trace(); + best_coverage = inv.coverage(); LOG(INFO) << "Best cost: " << best_cost << " at iteration = " << iteration; } else { - inv.LoadSolution(best_choices); + inv.LoadTraceAndCoverage(best_trace, best_coverage); } knights.ClearSubsetWithinRadius(CL::kCostAndCoverage, row, col, radius, &inv); @@ -434,8 +438,8 @@ TEST(SetCoverTest, KnightsCoverElementDegreeRadiusClear) { } } } - inv.LoadSolution(best_choices); - knights.DisplaySolution(best_choices); + inv.LoadTraceAndCoverage(best_trace, best_coverage); + knights.DisplaySolution(inv.is_selected()); LOG(INFO) << "RadiusClear cost: " << best_cost; // The best solution found until 2023-08 has a cost of 350. // http://www.contestcen.com/kn50.htm