21#include "absl/log/check.h"
22#include "absl/types/span.h"
29bool SupportsAvx512() {
return false; }
44 is_selected_.
assign(num_subsets,
false);
45 num_free_elements_.
assign(num_subsets, 0);
46 num_non_overcovered_elements_.
assign(num_subsets, 0);
47 is_redundant_.
assign(num_subsets,
false);
50 for (
const SubsetIndex subset : model_->
SubsetRange()) {
51 num_free_elements_[subset] = columns[subset].size();
52 num_non_overcovered_elements_[subset] = columns[subset].size();
55 coverage_.
assign(num_elements, 0);
60 num_uncovered_elements_ = num_elements;
61 supports_avx512_ = SupportsAvx512();
62 is_fully_updated_ =
true;
66 auto [cst, cvrg] = ComputeCostAndCoverage(is_selected_);
68 for (
const ElementIndex element : model_->
ElementRange()) {
69 CHECK_EQ(cvrg[element], coverage_[element]);
71 auto [num_uncvrd_elts, num_free_elts] =
72 ComputeNumUncoveredAndFreeElements(cvrg);
73 auto [num_non_ovrcvrd_elts, is_rdndnt] =
74 ComputeNumNonOvercoveredElementsAndIsRedundant(cvrg);
75 for (
const SubsetIndex subset : model_->
SubsetRange()) {
76 CHECK_EQ(num_free_elts[subset], num_free_elements_[subset]);
77 if (is_fully_updated_) {
78 CHECK_EQ(is_rdndnt[subset], is_redundant_[subset]);
79 CHECK_EQ(is_rdndnt[subset], num_non_ovrcvrd_elts[subset] == 0);
91 std::tie(cost_, coverage_) = ComputeCostAndCoverage(is_selected_);
92 std::tie(num_uncovered_elements_, num_free_elements_) =
93 ComputeNumUncoveredAndFreeElements(coverage_);
94 std::tie(num_non_overcovered_elements_, is_redundant_) =
95 ComputeNumNonOvercoveredElementsAndIsRedundant(coverage_);
96 is_fully_updated_ =
true;
100 std::tie(num_non_overcovered_elements_, is_redundant_) =
101 ComputeNumNonOvercoveredElementsAndIsRedundant(coverage_);
102 is_fully_updated_ =
true;
105std::tuple<Cost, ElementToIntVector> SetCoverInvariant::ComputeCostAndCoverage(
113 for (SubsetIndex subset(0);
bool b : choices) {
115 cst += subset_costs[subset];
116 for (
const ElementIndex element : columns[subset]) {
126 const absl::Span<const SubsetIndex> focus)
const {
128 for (
const SubsetIndex subset : focus) {
129 if (is_selected_[subset]) {
130 for (
const ElementIndex element : model_->
columns()[subset]) {
138std::tuple<BaseInt, SubsetToIntVector>
139SetCoverInvariant::ComputeNumUncoveredAndFreeElements(
148 for (
const SubsetIndex subset : model_->
SubsetRange()) {
149 num_free_elts[subset] = columns[subset].size();
153 for (
const ElementIndex element : model_->
ElementRange()) {
154 if (cvrg[element] >= 1) {
156 for (
const SubsetIndex subset : rows[element]) {
157 --num_free_elts[subset];
161 return {num_uncvrd_elts, num_free_elts};
164std::tuple<SubsetToIntVector, SubsetBoolVector>
165SetCoverInvariant::ComputeNumNonOvercoveredElementsAndIsRedundant(
173 for (
const SubsetIndex subset : model_->
SubsetRange()) {
174 num_cvrg_le_1_elts[subset] = columns[subset].size();
178 for (
const ElementIndex element : model_->
ElementRange()) {
179 if (cvrg[element] >= 2) {
180 for (
const SubsetIndex subset : rows[element]) {
181 --num_cvrg_le_1_elts[subset];
182 if (num_cvrg_le_1_elts[subset] == 0) {
183 is_rdndnt[subset] =
true;
188 return {num_cvrg_le_1_elts, is_rdndnt};
196 const SubsetIndex num_subsets(model_->
num_subsets());
198 for (
BaseInt i = 0; i < trace_.size(); ++i) {
199 const SubsetIndex subset(trace_[i].subset());
200 last_value_seen[subset] = trace_[i].decision();
203 for (
BaseInt i = 0; i < trace_.size(); ++i) {
204 const SubsetIndex subset(trace_[i].subset());
205 if (last_value_seen[subset]) {
206 last_value_seen[subset] =
false;
215 if (is_fully_updated_) {
216 return is_redundant_[subset];
218 if (is_selected_[subset]) {
219 for (
const ElementIndex element : model_->
columns()[subset]) {
220 if (coverage_[element] <= 1) {
225 for (
const ElementIndex element : model_->
columns()[subset]) {
226 if (coverage_[element] == 0) {
235 if (!is_selected_[subset]) {
236 Select(subset, incremental_full_update);
238 Deselect(subset, incremental_full_update);
243 bool incremental_full_update) {
244 if (incremental_full_update) {
247 is_fully_updated_ =
false;
249 DVLOG(1) <<
"Selecting subset " << subset;
250 DCHECK(!is_selected_[subset]);
252 trace_.push_back(SetCoverDecision(subset,
true));
253 is_selected_[subset] =
true;
255 cost_ += subset_costs[subset];
256 if (supports_avx512_) {
257 SelectAvx512(subset);
262 for (
const ElementIndex element : columns[subset]) {
263 if (coverage_[element] == 0) {
265 --num_uncovered_elements_;
266 for (
const SubsetIndex impacted_subset : rows[element]) {
267 --num_free_elements_[impacted_subset];
269 }
else if (incremental_full_update && coverage_[element] == 1) {
271 for (
const SubsetIndex impacted_subset : rows[element]) {
272 --num_non_overcovered_elements_[impacted_subset];
273 if (num_non_overcovered_elements_[impacted_subset] == 0) {
277 DCHECK(!is_redundant_[impacted_subset]);
278 if (is_selected_[impacted_subset]) {
279 new_removable_subsets_.push_back(impacted_subset);
281 is_redundant_[impacted_subset] =
true;
288 ++coverage_[element];
290 if (incremental_full_update) {
291 if (is_redundant_[subset]) {
292 new_removable_subsets_.push_back(subset);
294 new_non_removable_subsets_.push_back(subset);
301 bool incremental_full_update) {
302 if (incremental_full_update) {
305 is_fully_updated_ =
false;
307 DVLOG(1) <<
"Deselecting subset " << subset;
309 DCHECK(is_selected_[subset]);
310 DCHECK_EQ(num_free_elements_[subset], 0);
312 trace_.push_back(SetCoverDecision(subset,
false));
313 is_selected_[subset] =
false;
315 cost_ -= subset_costs[subset];
316 if (supports_avx512_) {
317 DeselectAvx512(subset);
322 for (
const ElementIndex element : columns[subset]) {
325 --coverage_[element];
326 if (coverage_[element] == 0) {
328 ++num_uncovered_elements_;
329 for (
const SubsetIndex impacted_subset : rows[element]) {
330 ++num_free_elements_[impacted_subset];
332 }
else if (incremental_full_update && coverage_[element] == 1) {
334 for (
const SubsetIndex impacted_subset : rows[element]) {
335 if (num_non_overcovered_elements_[impacted_subset] == 0) {
338 DCHECK(is_redundant_[impacted_subset]);
339 if (is_selected_[impacted_subset]) {
340 new_non_removable_subsets_.push_back(impacted_subset);
342 is_redundant_[impacted_subset] =
false;
344 ++num_non_overcovered_elements_[impacted_subset];
354void SetCoverInvariant::SelectAvx512(SubsetIndex) {
355 LOG(FATAL) <<
"SelectAvx512 is not implemented";
358void SetCoverInvariant::DeselectAvx512(SubsetIndex) {
359 LOG(FATAL) <<
"DeselectAvx512 is not implemented";
363 SetCoverSolutionResponse
message;
364 message.set_num_subsets(is_selected_.size());
366 for (
const SubsetIndex subset : model_->
SubsetRange()) {
367 if (is_selected_[subset]) {
368 message.add_subset(subset.value());
378 const SetCoverSolutionResponse&
message) {
379 is_selected_.
resize(SubsetIndex(
message.num_subsets()),
false);
380 for (
auto s :
message.subset()) {
381 is_selected_[SubsetIndex(s)] =
true;
385 CHECK_EQ(
cost, cost_);
A helper class used to store the decisions made during a search.
void Flip(SubsetIndex subset)
bool ComputeIsRedundant(SubsetIndex subset) const
SetCoverSolutionResponse ExportSolutionAsProto() const
Returns the current solution as a proto.
void Select(SubsetIndex subset)
void RecomputeInvariant()
Recomputes all the invariants for the current solution.
void LoadSolution(const SubsetBoolVector &solution)
Loads the solution and recomputes the data in the invariant.
void ImportSolutionFromProto(const SetCoverSolutionResponse &message)
Imports the solution from a proto.
bool CheckConsistency() const
void Deselect(SubsetIndex subset)
const ElementToIntVector & coverage() const
Returns vector containing number of subsets covering each element.
Cost cost() const
Returns the cost of current solution.
ElementToIntVector ComputeCoverageInFocus(absl::Span< const SubsetIndex > focus) const
void ClearRemovabilityInformation()
Clear the removability information.
util_intops::StrongIntRange< ElementIndex > ElementRange() const
const SparseRowView & rows() const
Row view of the set covering problem.
BaseInt num_elements() const
util_intops::StrongIntRange< SubsetIndex > SubsetRange() const
Access to the ranges of subsets and elements.
bool ComputeFeasibility() const
const SubsetCostVector & subset_costs() const
Vector of costs for each subset.
void CreateSparseRowView()
Creates the sparse ("dual") representation of the problem.
const SparseColumnView & columns() const
Column view of the set covering problem.
BaseInt num_subsets() const
void assign(size_type n, const value_type &val)
void resize(size_type new_size)
In SWIG mode, we don't want anything besides these top-level includes.
util_intops::StrongVector< SubsetIndex, BaseInt, IntAllocator > SubsetToIntVector
util_intops::StrongVector< ElementIndex, BaseInt, IntAllocator > ElementToIntVector
util_intops::StrongVector< SubsetIndex, bool > SubsetBoolVector
util_intops::StrongVector< SubsetIndex, SparseColumn > SparseColumnView
double Cost
Basic non-strict type for cost. The speed penalty for using double is ~2%.
util_intops::StrongVector< SubsetIndex, Cost, CostAllocator > SubsetCostVector
util_intops::StrongVector< ElementIndex, SparseRow > SparseRowView
trees with all degrees equal w the current value of w