61 : storage_(storage), time_limit_(
time_limit) {}
65 num_potential_subsets_ = 0;
66 num_potential_supersets_ = 0;
86 void SetWorkLimit(uint64_t work_limit) { work_limit_ = work_limit; }
102 const std::function<
void(
int subset,
int superset)>& process);
112 one_watcher_.clear();
113 is_in_superset_.resize(0);
130 const Storage& storage_;
143 bool CanBeSubset()
const {
return order <= 1; }
144 bool CanBeSuperset()
const {
return order >= 1; }
147 bool operator<(
const Candidate& other)
const {
148 return std::tie(size, order) < std::tie(other.size, other.order);
151 std::vector<Candidate> candidates_;
153 int num_potential_subsets_ = 0;
154 int num_potential_supersets_ = 0;
155 uint64_t work_done_ = 0;
156 uint64_t work_limit_ = std::numeric_limits<uint64_t>::max();
159 bool stop_with_current_subset_ =
false;
160 bool stop_with_current_superset_ =
false;
161 std::vector<uint64_t> signatures_;
162 std::vector<std::vector<int>> one_watcher_;
163 std::vector<int> superset_elements_;
164 Bitset64<int> is_in_superset_;
283 const std::function<
void(
int subset,
int superset)>& process) {
285 if (candidates_.size() <= 1)
return;
286 if (num_potential_subsets_ == 0)
return;
287 if (num_potential_supersets_ == 0)
return;
291 DCHECK(signatures_.empty());
292 DCHECK(one_watcher_.empty());
295 constexpr int64_t kCheckTimeLimitInterval = 1000;
296 int64_t next_time_limit_check = kCheckTimeLimitInterval;
300 std::stable_sort(candidates_.begin(), candidates_.end());
301 for (
const Candidate& candidate : candidates_) {
302 const auto& candidate_elements = storage_[candidate.index];
303 const int candidate_index = signatures_.size();
305 const auto [signature, max_element] =
307 signatures_.push_back(signature);
308 DCHECK_EQ(is_in_superset_.size(), one_watcher_.size());
309 if (max_element >= is_in_superset_.size()) {
310 is_in_superset_.resize(max_element + 1);
311 one_watcher_.resize(max_element + 1);
314 stop_with_current_superset_ =
false;
315 if (candidate.CanBeSuperset()) {
316 const Candidate& superset = candidate;
319 DCHECK(std::all_of(is_in_superset_.begin(), is_in_superset_.end(),
320 [](
bool b) { return !b; }));
323 work_done_ += 2 * superset.size;
324 if (work_done_ > work_limit_)
return Stop();
325 if (work_done_ > next_time_limit_check) {
326 if (time_limit_->LimitReached())
return Stop();
327 next_time_limit_check = work_done_ + kCheckTimeLimitInterval;
337 superset_elements_.assign(candidate_elements.begin(),
338 candidate_elements.end());
339 for (
const int e : superset_elements_) {
340 is_in_superset_.Set(e);
343 const uint64_t superset_signature = signatures_.back();
344 const auto is_in_superset_view = is_in_superset_.const_view();
345 for (
const int superset_e : superset_elements_) {
346 for (
int i = 0;
i < one_watcher_[superset_e].size(); ++
i) {
347 const int c_index = one_watcher_[superset_e][
i];
348 const Candidate& subset = candidates_[c_index];
349 DCHECK_LE(subset.size, superset.size);
352 if ((signatures_[c_index] & ~superset_signature) != 0)
continue;
355 bool is_included =
true;
356 work_done_ += subset.size;
357 if (work_done_ > work_limit_)
return Stop();
358 if (work_done_ > next_time_limit_check) {
359 if (time_limit_->LimitReached())
return Stop();
360 next_time_limit_check = work_done_ + kCheckTimeLimitInterval;
362 for (
const int subset_e : storage_[subset.index]) {
363 if (!is_in_superset_view[subset_e]) {
368 if (!is_included)
continue;
370 stop_with_current_subset_ =
false;
371 process(subset.index, superset.index);
374 if (work_done_ > work_limit_)
return Stop();
375 if (work_done_ > next_time_limit_check) {
376 if (time_limit_->LimitReached())
return Stop();
377 next_time_limit_check = work_done_ + kCheckTimeLimitInterval;
380 if (stop_with_current_subset_) {
382 std::swap(one_watcher_[superset_e][
i],
383 one_watcher_[superset_e].back());
384 one_watcher_[superset_e].pop_back();
387 if (stop_with_current_superset_)
break;
389 if (stop_with_current_superset_)
break;
393 for (
const int e : superset_elements_) {
394 is_in_superset_.ClearBucket(e);
402 if (candidate.CanBeSubset() && !stop_with_current_superset_) {
404 int best_choice = -1;
405 work_done_ += candidate.size;
406 if (work_done_ > work_limit_)
return Stop();
407 for (
const int e : candidate_elements) {
409 DCHECK_LT(e, one_watcher_.size());
410 if (best_choice == -1 ||
411 one_watcher_[e].size() < one_watcher_[best_choice].size()) {
415 DCHECK_NE(best_choice, -1);
416 one_watcher_[best_choice].push_back(candidate_index);
481 absl::Span<const int> superset,
int* next_index_to_try,
482 const std::function<
void(
int subset)>&
process) {
484 constexpr int64_t kCheckTimeLimitInterval = 1000;
485 int64_t next_time_limit_check = kCheckTimeLimitInterval;
489 const auto [superset_signature, max_element] =
491 if (max_element >= is_in_superset_.size()) {
492 is_in_superset_.resize(max_element + 1);
496 work_done_ += 2 * superset.size();
497 if (work_done_ > work_limit_)
return Stop();
498 if (work_done_ > next_time_limit_check) {
499 if (time_limit_->LimitReached())
return Stop();
500 next_time_limit_check = work_done_ + kCheckTimeLimitInterval;
504 DCHECK(std::all_of(is_in_superset_.begin(), is_in_superset_.end(),
505 [](
bool b) { return !b; }));
506 for (
const int e : superset) {
507 is_in_superset_.Set(e);
510 stop_with_current_superset_ =
false;
511 const auto is_in_superset_view = is_in_superset_.const_view();
512 for (; *next_index_to_try < superset.size(); ++*next_index_to_try) {
513 const int superset_e = superset[*next_index_to_try];
514 if (superset_e >= one_watcher_.size())
continue;
515 auto cached_span = one_watcher_[superset_e];
516 for (
int i = 0;
i < cached_span.size(); ++
i) {
521 const auto [subset_index, other_e, subset_signature] = cached_span[
i];
522 if ((subset_signature & ~superset_signature) != 0)
continue;
523 if (!is_in_superset_view[other_e])
continue;
526 const absl::Span<const int> subset = storage_[subset_index];
527 if (subset.size() > superset.size())
continue;
534 bool is_included =
true;
535 work_done_ += subset.size();
536 if (work_done_ > work_limit_)
return Stop();
537 if (work_done_ > next_time_limit_check) {
538 if (time_limit_->LimitReached())
return Stop();
539 next_time_limit_check = work_done_ + kCheckTimeLimitInterval;
541 for (
const int subset_e : subset) {
542 if (!is_in_superset_view[subset_e]) {
547 if (!is_included)
continue;
549 stop_with_current_subset_ =
false;
555 if (work_done_ > work_limit_)
return Stop();
556 if (work_done_ > next_time_limit_check) {
557 if (time_limit_->LimitReached())
return Stop();
558 next_time_limit_check = work_done_ + kCheckTimeLimitInterval;
561 if (stop_with_current_subset_) {
562 one_watcher_.RemoveBySwap(superset_e,
i);
563 cached_span.remove_suffix(1);
566 if (stop_with_current_superset_)
break;
568 if (stop_with_current_superset_)
break;
572 for (
const int e : superset) {
573 is_in_superset_.ClearBucket(e);