24#include "absl/base/casts.h"
25#include "absl/log/check.h"
26#include "absl/log/log.h"
27#include "absl/numeric/bits.h"
28#include "absl/random/distributions.h"
29#include "absl/random/random.h"
30#include "absl/types/span.h"
41static constexpr double kInfinity = std::numeric_limits<float>::infinity();
52 absl::Span<const SubsetIndex> focus) {
56 for (
const SubsetIndex subset : focus) {
57 choices[subset] =
true;
67 absl::Span<const SubsetIndex> focus) {
70 std::vector<SubsetIndex> shuffled(focus.begin(), focus.end());
71 std::shuffle(shuffled.begin(), shuffled.end(), absl::BitGen());
72 for (
const SubsetIndex subset : shuffled) {
73 if (
inv()->is_selected()[subset])
continue;
74 if (
inv()->num_free_elements()[subset] != 0) {
75 inv()->
Select(subset, CL::kFreeAndUncovered);
79 DCHECK(
inv()->CheckConsistency(CL::kFreeAndUncovered));
86 absl::Span<const SubsetIndex> focus) {
88 DCHECK(
inv()->CheckConsistency(CL::kCostAndCoverage));
91 std::vector<std::pair<float, SubsetIndex::ValueType>> subset_priorities;
92 DVLOG(1) <<
"focus.size(): " << focus.size();
93 subset_priorities.reserve(focus.size());
95 for (
const SubsetIndex subset : focus) {
96 if (!
inv()->is_selected()[subset] &&
97 inv()->num_free_elements()[subset] != 0) {
100 subset_priorities.push_back({priority, subset.value()});
112 std::vector<SubsetIndex> subsets_to_remove;
113 subsets_to_remove.reserve(focus.size());
114 while (!pq.
IsEmpty() ||
inv()->num_uncovered_elements() > 0) {
115 VLOG_EVERY_N_SEC(1, 5) <<
"Queue size: " << pq.
heap_size()
116 <<
", #uncovered elements: "
118 const SubsetIndex best_subset(pq.
TopIndex());
120 inv()->
Select(best_subset, CL::kFreeAndUncovered);
122 subset_seen[best_subset] =
true;
123 subsets_to_remove.push_back(best_subset);
124 for (
const ElementIndex element : colunms[best_subset]) {
125 for (
const SubsetIndex subset : rows[element]) {
126 if (subset_seen[subset])
continue;
127 subset_seen[subset] =
true;
128 const BaseInt marginal_impact(
inv()->num_free_elements()[subset]);
129 if (marginal_impact > 0) {
130 const float priority = marginal_impact / costs[subset];
131 pq.
Update({priority, subset.value()});
133 pq.
Remove(subset.value());
135 subsets_to_remove.push_back(subset);
138 for (
const SubsetIndex subset : subsets_to_remove) {
139 subset_seen[subset] =
false;
141 subsets_to_remove.clear();
142 DVLOG(1) <<
"Cost = " <<
inv()->
cost()
147 DCHECK(
inv()->CheckConsistency(CL::kFreeAndUncovered));
153class ComputationUsefulnessStats {
160 is_active_(is_active),
161 num_ratio_computations_(),
162 num_useless_computations_(),
165 BaseInt num_subsets = inv_->model()->num_subsets();
166 num_ratio_computations_.assign(num_subsets, 0);
167 num_useless_computations_.assign(num_subsets, 0);
173 void Update(SubsetIndex subset,
BaseInt new_num_free_elements) {
175 if (new_num_free_elements == num_free_elements_[subset]) {
176 ++num_useless_computations_[subset];
178 ++num_ratio_computations_[subset];
179 num_free_elements_[subset] = new_num_free_elements;
186 BaseInt num_subsets_considered = 0;
188 BaseInt num_wasted_ratio_updates = 0;
189 for (
const SubsetIndex subset : inv_->model()->SubsetRange()) {
190 if (num_ratio_computations_[subset] > 0) {
191 ++num_subsets_considered;
192 if (num_ratio_computations_[subset] > 1) {
193 num_ratio_updates += num_ratio_computations_[subset] - 1;
196 num_wasted_ratio_updates += num_useless_computations_[subset];
198 LOG(INFO) <<
"num_subsets_considered = " << num_subsets_considered;
199 LOG(INFO) <<
"num_ratio_updates = " << num_ratio_updates;
200 LOG(INFO) <<
"num_wasted_ratio_updates = " << num_wasted_ratio_updates;
206 const SetCoverInvariant* inv_;
245 if constexpr (
sizeof(
T) ==
sizeof(uint32_t)) {
246 return absl::bit_cast<uint32_t>(x);
248 static_assert(
sizeof(
T) ==
sizeof(uint64_t));
249 return absl::bit_cast<uint64_t>(x);
253inline uint32_t Bucket(uint32_t x, uint32_t shift, uint32_t radix) {
254 DCHECK_EQ(0, radix & (radix - 1));
257 return (x >> shift) & (radix - 1);
261int NumBitsToRepresent(T value) {
262 DCHECK_LE(absl::countl_zero(RawBits(value)),
sizeof(T) * CHAR_BIT);
263 return sizeof(
T) * CHAR_BIT - absl::countl_zero(RawBits(value));
266template <
typename Key,
typename Counter>
267void UpdateCounters(uint32_t radix,
int shift, std::vector<Key>& keys,
268 std::vector<Counter>& counts) {
269 std::fill(counts.begin(), counts.end(), 0);
270 DCHECK_EQ(counts[0], 0);
271 DCHECK_EQ(0, radix & (radix - 1));
272 const auto num_keys = keys.size();
273 for (int64_t i = 0;
i < num_keys; ++
i) {
274 ++counts[Bucket(keys[i], shift, radix)];
278 for (uint64_t i = 1;
i < radix; ++
i) {
279 counts[
i] += counts[
i - 1];
283template <
typename Key,
typename Payload,
typename Counter>
284void IncreasingCountingSort(uint32_t radix,
int shift, std::vector<Key>& keys,
285 std::vector<Payload>& payloads,
286 std::vector<Key>& scratch_keys,
287 std::vector<Payload>& scratch_payloads,
288 std::vector<Counter>& counts) {
289 DCHECK_EQ(0, radix & (radix - 1));
290 UpdateCounters(radix, shift, keys, counts);
291 const auto num_keys = keys.size();
293 for (int64_t i = num_keys - 1;
i >= 0; --
i) {
294 Counter
c = --counts[Bucket(keys[i], shift, radix)];
295 scratch_keys[
c] = keys[
i];
296 scratch_payloads[
c] = payloads[
i];
298 std::swap(keys, scratch_keys);
299 std::swap(payloads, scratch_payloads);
303template <
typename Key,
typename Payload>
304void RadixSort(
int radix_log, std::vector<Key>& keys,
305 std::vector<Payload>& payloads, Key , Key max_key) {
309 const int range_log = internal::NumBitsToRepresent(max_key);
310 DCHECK_EQ(internal::NumBitsToRepresent(0), 0);
311 DCHECK_LE(internal::NumBitsToRepresent(std::numeric_limits<Key>::max()),
312 std::numeric_limits<Key>::digits);
313 const int radix = 1 << radix_log;
314 std::vector<uint32_t> counters(radix, 0);
315 std::vector<Key> scratch_keys(keys.size());
316 std::vector<Payload> scratch_payloads(payloads.size());
317 for (
int shift = 0; shift < range_log; shift += radix_log) {
318 DCHECK_LE(1 << shift, max_key);
319 internal::IncreasingCountingSort(radix, shift, keys, payloads, scratch_keys,
320 scratch_payloads, counters);
326std::vector<ElementIndex> GetUncoveredElementsSortedByDegree(
328 const BaseInt num_elements = inv->model()->num_elements();
329 std::vector<ElementIndex> degree_sorted_elements;
330 degree_sorted_elements.reserve(num_elements);
331 std::vector<BaseInt> keys;
332 keys.reserve(num_elements);
335 for (
const ElementIndex element : inv->model()->ElementRange()) {
337 if (inv->coverage()[element] != 0)
continue;
338 degree_sorted_elements.push_back(element);
339 const BaseInt size = rows[element].size();
340 max_degree = std::max(max_degree, size);
341 keys.push_back(size);
343 RadixSort(11, keys, degree_sorted_elements, 1, max_degree);
346 for (
const auto key : keys) {
347 DCHECK_LE(prev_key, key);
351 return degree_sorted_elements;
360 return c1 * n2 - n1 * c2;
372 DVLOG(1) <<
"Entering ElementDegreeSolutionGenerator::NextSolution";
375 std::vector<ElementIndex> degree_sorted_elements =
376 GetUncoveredElementsSortedByDegree(
inv());
377 ComputationUsefulnessStats stats(
inv(),
false);
380 for (
const ElementIndex element : degree_sorted_elements) {
382 if (
inv()->coverage()[element] != 0)
continue;
383 SubsetIndex best_subset(-1);
384 Cost best_subset_cost = 0.0;
385 BaseInt best_subset_num_free_elts = 0;
386 for (
const SubsetIndex subset : rows[element]) {
387 if (!in_focus[subset])
continue;
389 stats.Update(subset, num_free_elements);
390 const Cost det = Determinant(costs[subset], num_free_elements,
391 best_subset_cost, best_subset_num_free_elts);
400 (det == 0 && num_free_elements > best_subset_num_free_elts)) {
401 best_subset = subset;
402 best_subset_cost = costs[subset];
403 best_subset_num_free_elts = num_free_elements;
406 if (best_subset.value() == -1) {
407 LOG(WARNING) <<
"Best subset not found. Algorithmic error or invalid "
411 DCHECK_NE(best_subset.value(), -1);
412 inv()->
Select(best_subset, CL::kFreeAndUncovered);
413 DVLOG(1) <<
"Cost = " <<
inv()->
cost()
418 DCHECK(
inv()->CheckConsistency(CL::kFreeAndUncovered));
431 DVLOG(1) <<
"Entering LazyElementDegreeSolutionGenerator::NextSolution";
432 DCHECK(
inv()->CheckConsistency(CL::kCostAndCoverage));
434 std::vector<ElementIndex> degree_sorted_elements =
435 GetUncoveredElementsSortedByDegree(
inv());
438 ComputationUsefulnessStats stats(
inv(),
false);
440 for (
const ElementIndex element : degree_sorted_elements) {
442 if (
inv()->coverage()[element] != 0)
continue;
443 SubsetIndex best_subset(-1);
444 Cost best_subset_cost = 0.0;
445 BaseInt best_subset_num_free_elts = 0;
446 for (
const SubsetIndex subset : rows[element]) {
447 if (!in_focus[subset])
continue;
448 const Cost filtering_det =
449 Determinant(costs[subset], columns[subset].size(), best_subset_cost,
450 best_subset_num_free_elts);
453 if (filtering_det > 0)
continue;
455 stats.Update(subset, num_free_elements);
456 const Cost det = Determinant(costs[subset], num_free_elements,
457 best_subset_cost, best_subset_num_free_elts);
460 (det == 0 && num_free_elements > best_subset_num_free_elts)) {
461 best_subset = subset;
462 best_subset_cost = costs[subset];
463 best_subset_num_free_elts = num_free_elements;
466 DCHECK_NE(best_subset, SubsetIndex(-1));
467 inv()->
Select(best_subset, CL::kCostAndCoverage);
468 DVLOG(1) <<
"Cost = " <<
inv()->
cost()
471 DCHECK(
inv()->CheckConsistency(CL::kCostAndCoverage));
481 DCHECK(
inv()->CheckConsistency(CL::kCostAndCoverage));
483 DVLOG(1) <<
"Entering SteepestSearch::NextSolution, num_iterations = "
487 if (
inv()->num_uncovered_elements() != 0) {
494 std::vector<std::pair<float, SubsetIndex::ValueType>> subset_priorities;
495 subset_priorities.reserve(in_focus.size());
497 const SubsetIndex subset = decision.subset();
498 if (in_focus[subset] &&
inv()->is_selected()[subset] &&
499 inv()->ComputeIsRedundant(subset)) {
500 const float delta_per_element = costs[subset];
501 subset_priorities.push_back({delta_per_element, subset.value()});
504 DVLOG(1) <<
"subset_priorities.size(): " << subset_priorities.size();
507 for (
int iteration = 0; iteration < num_iterations && !pq.
IsEmpty();
509 const SubsetIndex best_subset(pq.
TopIndex());
511 DCHECK(
inv()->is_selected()[best_subset]);
512 DCHECK(
inv()->ComputeIsRedundant(best_subset));
513 DCHECK_GT(costs[best_subset], 0.0);
514 inv()->
Deselect(best_subset, CL::kFreeAndUncovered);
515 for (
const SubsetIndex subset :
517 if (!
inv()->ComputeIsRedundant(subset)) {
518 pq.
Remove(subset.value());
521 DVLOG(1) <<
"Cost = " <<
inv()->
cost();
525 DCHECK_EQ(
inv()->num_uncovered_elements(), 0);
526 DCHECK(
inv()->CheckConsistency(CL::kFreeAndUncovered));
535 DCHECK(
inv()->CheckConsistency(CL::kCostAndCoverage));
536 DVLOG(1) <<
"Entering LazySteepestSearch::NextSolution, num_iterations = "
539 std::vector<Cost> selected_costs;
540 selected_costs.reserve(num_selected_subsets);
546 if (in_focus[decision.subset()]) {
547 selected_costs.push_back(costs[decision.subset()]);
550 std::vector<BaseInt> cost_permutation(selected_costs.size());
551 std::iota(cost_permutation.begin(), cost_permutation.end(), 0);
553 std::sort(cost_permutation.begin(), cost_permutation.end(),
555 if (selected_costs[i] == selected_costs[j]) {
558 return selected_costs[i] > selected_costs[j];
560 std::vector<SubsetIndex> cost_sorted_subsets;
561 cost_sorted_subsets.reserve(num_selected_subsets);
562 for (
const BaseInt i : cost_permutation) {
563 cost_sorted_subsets.push_back(inv()->trace()[i].subset());
565 for (
const SubsetIndex subset : cost_sorted_subsets) {
577 if (inv()->is_selected()[subset] && inv()->ComputeIsRedundant(subset)) {
578 inv()->Deselect(subset, CL::kCostAndCoverage);
581 inv()->CompressTrace();
582 DCHECK(inv()->CheckConsistency(CL::kCostAndCoverage));
592 augmented_costs_ = subset_costs;
593 utilities_ = subset_costs;
599 return absl::Bernoulli(absl::BitGen(), 0.5);
603void GuidedTabuSearch::UpdatePenalties(absl::Span<const SubsetIndex> focus) {
605 Cost max_utility = -1.0;
606 for (
const SubsetIndex subset : focus) {
607 if (inv()->is_selected()[subset]) {
608 max_utility = std::max(max_utility, utilities_[subset]);
611 const double epsilon_utility = epsilon_ * max_utility;
612 for (
const SubsetIndex subset : focus) {
613 if (inv()->is_selected()[subset]) {
614 const double utility = utilities_[subset];
615 if ((max_utility - utility <= epsilon_utility) && FlipCoin()) {
616 ++times_penalized_[subset];
617 const int times_penalized = times_penalized_[subset];
619 subset_costs[subset];
620 utilities_[subset] = cost / (1 + times_penalized);
621 augmented_costs_[subset] =
622 cost * (1 + penalty_factor_ * times_penalized);
631 DCHECK(
inv()->CheckConsistency(CL::kFreeAndUncovered));
632 DVLOG(1) <<
"Entering GuidedTabuSearch::NextSolution, num_iterations = "
635 Cost best_cost =
inv()->cost();
637 Cost augmented_cost =
638 std::accumulate(augmented_costs_.begin(), augmented_costs_.end(), 0.0);
640 for (
int iteration = 0; iteration < num_iterations; ++iteration) {
641 if (
inv()->trace().size() > 2 * trace_size) {
642 inv()->CompressTrace();
643 trace_size =
inv()->trace().size();
647 for (
const SubsetIndex subset : focus) {
648 const Cost delta = augmented_costs_[subset];
649 DVLOG(1) <<
"Subset, " << subset.value() <<
", at ,"
650 <<
inv()->is_selected()[subset] <<
", delta =, " << delta
651 <<
", best_delta =, " << best_delta;
652 if (
inv()->is_selected()[subset]) {
655 if (-delta < best_delta &&
657 inv()->ComputeIsRedundant(subset) &&
659 (!tabu_list_.Contains(subset) ||
660 inv()->
cost() - subset_costs[subset] < best_cost)) {
662 best_subset = subset;
666 if (delta < best_delta) {
669 if (!tabu_list_.Contains(subset)) {
671 best_subset = subset;
677 inv()->LoadSolution(best_choices);
680 DVLOG(1) <<
"Best subset, " << best_subset.value() <<
", at ,"
681 <<
inv()->is_selected()[best_subset] <<
", best_delta = ,"
684 UpdatePenalties(focus);
685 tabu_list_.Add(best_subset);
686 if (
inv()->is_selected()[best_subset]) {
687 inv()->Deselect(best_subset, CL::kFreeAndUncovered);
689 inv()->Select(best_subset, CL::kFreeAndUncovered);
693 std::accumulate(augmented_costs_.begin(), augmented_costs_.end(), 0.0);
695 DVLOG(1) <<
"Iteration, " << iteration <<
", current cost = ,"
696 <<
inv()->cost() <<
", best cost = ," << best_cost
697 <<
", penalized cost = ," << augmented_cost;
698 if (
inv()->
cost() < best_cost) {
699 VLOG(1) <<
"Updated best cost, " <<
"Iteration, " << iteration
700 <<
", current cost = ," <<
inv()->cost() <<
", best cost = ,"
701 << best_cost <<
", penalized cost = ," << augmented_cost;
702 best_cost =
inv()->cost();
703 best_choices =
inv()->is_selected();
706 inv()->LoadSolution(best_choices);
707 inv()->CompressTrace();
708 DCHECK(
inv()->CheckConsistency(CL::kFreeAndUncovered));
713void GuidedLocalSearch::Initialize() {
715 penalties_.assign(columns.size(), 0);
716 penalization_factor_ = alpha_ *
inv()->cost() * 1.0 / (columns.size());
718 const SubsetIndex subset = decision.subset();
719 if (
inv()->is_selected()[subset]) {
720 utility_heap_.Insert({
static_cast<float>(
model()->subset_costs()[subset] /
721 (1 + penalties_[subset])),
727Cost GuidedLocalSearch::ComputeDelta(SubsetIndex subset)
const {
728 const float delta = (penalization_factor_ * penalties_[subset] +
729 model()->subset_costs()[subset]);
730 if (inv()->is_selected()[subset] && inv()->ComputeIsRedundant(subset)) {
732 }
else if (!inv()->is_selected()[subset]) {
738bool GuidedLocalSearch::NextSolution(absl::Span<const SubsetIndex> focus) {
741 inv()->Recompute(CL::kRedundancy);
742 Cost best_cost =
inv()->cost();
745 for (
const SubsetIndex& subset : focus) {
746 const float delta = ComputeDelta(subset);
748 priority_heap_.Insert({delta, subset.value()});
752 for (
int iteration = 0;
753 !priority_heap_.IsEmpty() && iteration < num_iterations; ++iteration) {
756 const SubsetIndex best_subset(priority_heap_.TopIndex());
757 if (
inv()->is_selected()[best_subset]) {
758 utility_heap_.Insert({0, best_subset.value()});
759 inv()->Deselect(best_subset, CL::kRedundancy);
761 utility_heap_.Insert(
762 {
static_cast<float>(
model()->subset_costs()[best_subset] /
763 (1 + penalties_[best_subset])),
764 best_subset.value()});
765 inv()->Select(best_subset, CL::kRedundancy);
767 DCHECK(!utility_heap_.IsEmpty());
771 const SubsetIndex penalized_subset(utility_heap_.TopIndex());
773 ++penalties_[penalized_subset];
774 utility_heap_.Insert(
775 {
static_cast<float>(
model()->subset_costs()[penalized_subset] /
776 (1 + penalties_[penalized_subset])),
777 penalized_subset.value()});
778 DCHECK(!utility_heap_.IsEmpty());
781 for (
const SubsetIndex subset :
inv()->newly_removable_subsets()) {
782 const float delta_selected = (penalization_factor_ * penalties_[subset] +
783 model()->subset_costs()[subset]);
784 priority_heap_.Insert({delta_selected, subset.value()});
786 DCHECK(!priority_heap_.IsEmpty());
788 for (
const SubsetIndex subset : {penalized_subset, best_subset}) {
789 const float delta = ComputeDelta(subset);
791 priority_heap_.Insert({delta, subset.value()});
794 DCHECK(!priority_heap_.IsEmpty());
799 for (
const SubsetIndex subset :
inv()->newly_non_removable_subsets()) {
800 priority_heap_.Remove(subset.value());
803 if (
inv()->
cost() < best_cost) {
804 best_cost =
inv()->cost();
805 best_choices =
inv()->is_selected();
808 inv()->LoadSolution(best_choices);
811 for (
const SubsetIndex& subset : focus) {
812 if (
inv()->is_selected()[subset] &&
inv()->ComputeIsRedundant(subset))
813 inv()->Deselect(subset, CL::kRedundancy);
815 DCHECK_EQ(
inv()->num_uncovered_elements(), 0);
820void SampleSubsets(std::vector<SubsetIndex>* list,
BaseInt num_subsets) {
821 num_subsets = std::min<BaseInt>(num_subsets, list->size());
822 CHECK_GE(num_subsets, 0);
823 std::shuffle(list->begin(), list->end(), absl::BitGen());
824 list->resize(num_subsets);
836 num_subsets_to_choose =
837 std::min<BaseInt>(num_subsets_to_choose, focus.size());
838 CHECK_GE(num_subsets_to_choose, 0);
839 std::vector<SubsetIndex> chosen_indices;
840 for (
const SubsetIndex subset : focus) {
842 chosen_indices.push_back(subset);
845 SampleSubsets(&chosen_indices, num_subsets_to_choose);
847 for (
const SubsetIndex subset : chosen_indices) {
850 inv->
Deselect(subset, CL::kCostAndCoverage);
853 for (
const SubsetIndex connected_subset :
857 inv->
Deselect(connected_subset, CL::kCostAndCoverage);
862 if (num_deselected > num_subsets_to_choose)
break;
864 return chosen_indices;
874 absl::Span<const SubsetIndex> focus,
BaseInt max_num_subsets,
877 std::vector<SubsetIndex> sampled_subsets;
887 if (coverage[element] <= 1)
continue;
888 for (
const SubsetIndex subset : rows[element]) {
889 if (inv->
is_selected()[subset] && !subset_is_collected[subset]) {
890 subset_is_collected[subset] =
true;
898 for (
const SubsetIndex subset : focus) {
899 if (subset_is_collected[subset]) {
900 sampled_subsets.push_back(subset);
906 std::shuffle(sampled_subsets.begin(), sampled_subsets.end(), absl::BitGen());
907 sampled_subsets.resize(
908 std::min<BaseInt>(sampled_subsets.size(), max_num_subsets));
912 for (
const SubsetIndex subset : sampled_subsets) {
913 inv->
Deselect(subset, CL::kCostAndCoverage);
915 return sampled_subsets;
void Update(Aggregate element)
HeapIndex heap_size() const
bool NextSolution() final
bool NextSolution() final
bool NextSolution(absl::Span< const SubsetIndex > focus) final
bool NextSolution() final
bool NextSolution() final
bool NextSolution() final
void Recompute(ConsistencyLevel target_consistency)
const SubsetToIntVector & num_free_elements() const
const std::vector< SetCoverDecision > & trace() const
void LoadSolution(const SubsetBoolVector &solution)
bool Deselect(SubsetIndex subset, ConsistencyLevel consistency)
const SubsetBoolVector & is_selected() const
SetCoverModel * model() const
bool Select(SubsetIndex subset, ConsistencyLevel consistency)
const ElementToIntVector & coverage() const
BaseInt ComputeNumFreeElements(SubsetIndex subset) const
BaseInt num_uncovered_elements() const
util_intops::StrongIntRange< ElementIndex > ElementRange() const
const SparseRowView & rows() const
const SubsetCostVector & subset_costs() const
const SparseColumnView & columns() const
BaseInt num_subsets() const
std::vector< SubsetIndex > all_subsets() const
SetCoverInvariant::ConsistencyLevel consistency_level_
BaseInt num_subsets() const
int64_t max_iterations() const
SetCoverModel * model() const
SetCoverInvariant * inv() const
bool CheckInvariantConsistency() const
bool NextSolution() final
bool NextSolution() final
constexpr Fractional kInfinity
dual_gradient T(y - `dual_solution`) class DiagonalTrustRegionProblemFromQp
constexpr SubsetIndex kNotFound(-1)
static constexpr double kInfinity
util_intops::StrongVector< SubsetIndex, Cost > SubsetCostVector
SetCoverInvariant::ConsistencyLevel CL
std::vector< SubsetIndex > ClearRandomSubsets(BaseInt num_subsets, SetCoverInvariant *inv)
util_intops::StrongVector< SubsetIndex, BaseInt > SubsetToIntVector
static constexpr Cost kMaxPossibleCost
util_intops::StrongVector< ElementIndex, BaseInt > ElementToIntVector
util_intops::StrongVector< SubsetIndex, bool > SubsetBoolVector
void RadixSort(absl::Span< T > values, int num_bits=sizeof(T) *8)
util_intops::StrongVector< SubsetIndex, SparseColumn > SparseColumnView
std::vector< SubsetIndex > ClearMostCoveredElements(BaseInt max_num_subsets, SetCoverInvariant *inv)
num_free_elements_[subset]
util_intops::StrongVector< ElementIndex, SparseRow > SparseRowView
trees with all degrees equal w the current value of int max_iterations