60 num_potential_subsets_ = 0;
61 num_potential_supersets_ = 0;
81 void SetWorkLimit(uint64_t work_limit) { work_limit_ = work_limit; }
97 const std::function<
void(
int subset,
int superset)>& process);
112 one_watcher_.clear();
113 is_in_superset_.clear();
129 const Storage& storage_;
140 bool CanBeSubset()
const {
return order <= 1; }
141 bool CanBeSuperset()
const {
return order >= 1; }
144 bool operator<(
const Candidate& other)
const {
145 return std::tie(size, order) < std::tie(other.size, other.order);
148 std::vector<Candidate> candidates_;
150 int num_potential_subsets_ = 0;
151 int num_potential_supersets_ = 0;
152 uint64_t work_done_ = 0;
153 uint64_t work_limit_ = std::numeric_limits<uint64_t>::max();
157 bool stop_with_current_subset_;
158 bool stop_with_current_superset_;
159 std::vector<uint64_t> signatures_;
160 std::vector<std::vector<int>> one_watcher_;
161 std::vector<int> superset_elements_;
162 std::vector<bool> is_in_superset_;
207 const std::function<
void(
int subset,
int superset)>& process) {
209 if (candidates_.size() <= 1)
return;
210 if (num_potential_subsets_ == 0)
return;
211 if (num_potential_supersets_ == 0)
return;
215 DCHECK(is_in_superset_.empty());
216 DCHECK(signatures_.empty());
217 DCHECK(one_watcher_.empty());
221 std::stable_sort(candidates_.begin(), candidates_.end());
222 for (
const Candidate& candidate : candidates_) {
223 const auto& candidate_elements = storage_[candidate.index];
224 const int candidate_index = signatures_.size();
228 uint64_t signature = 0;
230 for (
const int e : candidate_elements) {
232 max_element = std::max(max_element, e);
233 signature |= (int64_t{1} << (e & 63));
235 DCHECK_EQ(is_in_superset_.size(), one_watcher_.size());
236 if (max_element >= is_in_superset_.size()) {
237 is_in_superset_.resize(max_element + 1,
false);
238 one_watcher_.resize(max_element + 1);
240 signatures_.push_back(signature);
242 stop_with_current_superset_ =
false;
243 if (candidate.CanBeSuperset()) {
244 const Candidate& superset = candidate;
247 DCHECK(std::all_of(is_in_superset_.begin(), is_in_superset_.end(),
248 [](
bool b) { return !b; }));
251 work_done_ += 2 * superset.size;
252 if (work_done_ > work_limit_)
return Stop();
261 superset_elements_.assign(candidate_elements.begin(),
262 candidate_elements.end());
263 for (
const int e : superset_elements_) {
264 is_in_superset_[e] =
true;
267 const uint64_t superset_signature = signatures_.back();
268 for (
const int superset_e : superset_elements_) {
269 for (
int i = 0;
i < one_watcher_[superset_e].size(); ++
i) {
270 const int c_index = one_watcher_[superset_e][
i];
271 const Candidate& subset = candidates_[c_index];
272 DCHECK_LE(subset.size, superset.size);
275 if ((signatures_[c_index] & ~superset_signature) != 0)
continue;
278 bool is_included =
true;
279 work_done_ += subset.size;
280 if (work_done_ > work_limit_)
return Stop();
281 for (
const int subset_e : storage_[subset.index]) {
282 if (!is_in_superset_[subset_e]) {
287 if (!is_included)
continue;
289 stop_with_current_subset_ =
false;
290 process(subset.index, superset.index);
293 if (work_done_ > work_limit_)
return Stop();
295 if (stop_with_current_subset_) {
297 std::swap(one_watcher_[superset_e][
i],
298 one_watcher_[superset_e].back());
299 one_watcher_[superset_e].pop_back();
302 if (stop_with_current_superset_)
break;
304 if (stop_with_current_superset_)
break;
308 for (
const int e : superset_elements_) {
309 is_in_superset_[e] =
false;
317 if (candidate.CanBeSubset() && !stop_with_current_superset_) {
319 int best_choice = -1;
320 work_done_ += candidate.size;
321 if (work_done_ > work_limit_)
return Stop();
322 for (
const int e : candidate_elements) {
324 DCHECK_LT(e, one_watcher_.size());
325 if (best_choice == -1 ||
326 one_watcher_[e].
size() < one_watcher_[best_choice].
size()) {
330 DCHECK_NE(best_choice, -1);
331 one_watcher_[best_choice].push_back(candidate_index);