14#ifndef OR_TOOLS_SAT_INCLUSION_H_
15#define OR_TOOLS_SAT_INCLUSION_H_
28#include "absl/types/span.h"
43 int Add(absl::Span<const T> data) {
45 starts_.push_back(buffer_.size());
46 sizes_.push_back(data.size());
47 buffer_.insert(buffer_.end(), data.begin(), data.end());
56 const size_t size =
static_cast<size_t>(sizes_[
index]);
57 if (
size == 0)
return {};
67 size_t size()
const {
return starts_.size(); }
70 std::vector<int> starts_;
71 std::vector<int> sizes_;
72 std::vector<T> buffer_;
92template <
class Storage>
99 num_potential_subsets_ = 0;
100 num_potential_supersets_ = 0;
136 const std::function<
void(
int subset,
int superset)>& process);
141 const std::vector<bool>
IsInSuperset()
const {
return is_in_superset_; }
151 one_watcher_.clear();
152 is_in_superset_.clear();
168 const Storage& storage_;
179 bool CanBeSubset()
const {
return order <= 1; }
180 bool CanBeSuperset()
const {
return order >= 1; }
183 bool operator<(
const Candidate& other)
const {
184 return std::tie(size, order) < std::tie(other.size, other.order);
187 std::vector<Candidate> candidates_;
189 int num_potential_subsets_ = 0;
190 int num_potential_supersets_ = 0;
191 uint64_t work_done_ = 0;
196 bool stop_with_current_subset_;
197 bool stop_with_current_superset_;
198 std::vector<uint64_t> signatures_;
199 std::vector<std::vector<int>> one_watcher_;
200 std::vector<bool> is_in_superset_;
204template <
typename Storage>
207template <
typename Storage>
211 const int num_elements = storage_[
index].size();
212 if (num_elements == 0)
return;
214 ++num_potential_subsets_;
215 ++num_potential_supersets_;
216 candidates_.push_back({
index, num_elements, 1});
219template <
typename Storage>
223 const int num_elements = storage_[
index].size();
224 if (num_elements == 0)
return;
226 ++num_potential_subsets_;
227 candidates_.push_back({
index, num_elements, 0});
230template <
typename Storage>
234 const int num_elements = storage_[
index].size();
235 if (num_elements == 0)
return;
239 ++num_potential_supersets_;
240 candidates_.push_back({
index, num_elements, 2});
243template <
typename Storage>
245 const std::function<
void(
int subset,
int superset)>& process) {
247 if (candidates_.size() <= 1)
return;
248 if (num_potential_subsets_ == 0)
return;
249 if (num_potential_supersets_ == 0)
return;
253 DCHECK(is_in_superset_.empty());
254 DCHECK(signatures_.empty());
255 DCHECK(one_watcher_.empty());
259 std::stable_sort(candidates_.begin(), candidates_.end());
260 for (
const Candidate& candidate : candidates_) {
261 const auto& candidate_elements = storage_[candidate.index];
262 const int candidate_index = signatures_.size();
266 uint64_t signature = 0;
268 for (
const int e : candidate_elements) {
270 max_element =
std::max(max_element, e);
271 signature |= (int64_t{1} << (e & 63));
273 DCHECK_EQ(is_in_superset_.size(), one_watcher_.size());
274 if (max_element >= is_in_superset_.size()) {
275 is_in_superset_.resize(max_element + 1,
false);
276 one_watcher_.resize(max_element + 1);
278 signatures_.push_back(signature);
280 stop_with_current_superset_ =
false;
281 if (candidate.CanBeSuperset()) {
282 const Candidate& superset = candidate;
283 const auto& superset_elements = candidate_elements;
286 DCHECK(std::all_of(is_in_superset_.begin(), is_in_superset_.end(),
287 [](
bool b) { return !b; }));
290 work_done_ += 2 * superset.size;
291 if (work_done_ > work_limit_)
return Stop();
292 for (
const int e : superset_elements) {
293 is_in_superset_[e] =
true;
296 const uint64_t superset_signature = signatures_.back();
297 for (
const int superset_e : superset_elements) {
298 for (
int i = 0; i < one_watcher_[superset_e].size(); ++i) {
299 const int c_index = one_watcher_[superset_e][i];
300 const Candidate& subset = candidates_[c_index];
304 if ((signatures_[c_index] & ~superset_signature) != 0)
continue;
307 bool is_included =
true;
308 work_done_ += subset.size;
309 if (work_done_ > work_limit_)
return Stop();
310 for (
const int subset_e : storage_[subset.index]) {
311 if (!is_in_superset_[subset_e]) {
316 if (!is_included)
continue;
318 stop_with_current_subset_ =
false;
319 process(subset.index, superset.index);
322 if (work_done_ > work_limit_)
return Stop();
324 if (stop_with_current_subset_) {
327 one_watcher_[superset_e].back());
328 one_watcher_[superset_e].pop_back();
331 if (stop_with_current_superset_)
break;
333 if (stop_with_current_superset_)
break;
337 for (
const int e : superset_elements) {
338 is_in_superset_[e] =
false;
346 if (candidate.CanBeSubset() && !stop_with_current_superset_) {
348 int best_choice = -1;
349 work_done_ += candidate.size;
350 if (work_done_ > work_limit_)
return Stop();
351 for (
const int e : candidate_elements) {
354 if (best_choice == -1 ||
355 one_watcher_[e].size() < one_watcher_[best_choice].size()) {
360 one_watcher_[best_choice].push_back(candidate_index);
#define DCHECK_LE(val1, val2)
#define DCHECK_NE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
absl::Span< const T > operator[](int index) const
int Add(absl::Span< const T > data)
int num_potential_supersets() const
uint64_t work_done() const
void AddPotentialSubset(int index)
int num_potential_subsets() const
void SetWorkLimit(uint64_t work_limit)
void StopProcessingCurrentSubset()
void AddPotentialSet(int index)
void AddPotentialSuperset(int index)
void StopProcessingCurrentSuperset()
void IncreaseWorkDone(uint64_t increase)
const std::vector< bool > IsInSuperset() const
InclusionDetector(const Storage &storage)
void DetectInclusions(const std::function< void(int subset, int superset)> &process)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
InclusionDetector(const Storage &storage) -> InclusionDetector< Storage >
Collection of objects used to extend the Constraint Solver library.