33#ifndef OR_TOOLS_UTIL_TUPLE_SET_H_
34#define OR_TOOLS_UTIL_TUPLE_SET_H_
39#include "absl/container/flat_hash_map.h"
40#include "absl/container/flat_hash_set.h"
64 int Insert(
const std::vector<int>& tuple);
65 int Insert(
const std::vector<int64_t>& tuple);
67 int Insert2(int64_t v0, int64_t v1);
68 int Insert3(int64_t v0, int64_t v1, int64_t v2);
69 int Insert4(int64_t v0, int64_t v1, int64_t v2, int64_t v3);
71 void InsertAll(
const std::vector<std::vector<int64_t> >& tuples);
72 void InsertAll(
const std::vector<std::vector<int> >& tuples);
75 bool Contains(
const std::vector<int>& tuple)
const;
76 bool Contains(
const std::vector<int64_t>& tuple)
const;
83 int64_t
Value(
int tuple_index,
int pos_in_tuple)
const;
101 explicit Data(
int arity);
102 Data(
const Data& data);
104 void AddSharedOwner();
105 bool RemovedSharedOwner();
106 Data* CopyIfShared();
108 int Insert(
const std::vector<T>& tuple);
110 bool Contains(
const std::vector<T>& candidate)
const;
112 int64_t Fingerprint(
const std::vector<T>& tuple)
const;
116 const int64_t*
RawData()
const;
123 std::vector<int64_t> flat_tuples_;
127 absl::flat_hash_map<int64_t, std::vector<int> > tuple_fprint_to_index_;
133 IntTupleSet::Data* data;
134 IndexData(
int i, IntTupleSet::Data*
const d) :
index(i), data(d) {}
135 static bool Compare(
const IndexData&
a,
const IndexData&
b);
141 IndexValue(
int i, int64_t v) :
index(i),
value(v) {}
142 static bool Compare(
const IndexValue&
a,
const IndexValue&
b);
149inline IntTupleSet::Data::Data(
int arity) :
arity_(arity), num_owners_(0) {}
151inline IntTupleSet::Data::Data(
const Data& data)
154 flat_tuples_(data.flat_tuples_),
155 tuple_fprint_to_index_(data.tuple_fprint_to_index_) {}
157inline IntTupleSet::Data::~Data() {}
159inline void IntTupleSet::Data::AddSharedOwner() { num_owners_++; }
161inline bool IntTupleSet::Data::RemovedSharedOwner() {
162 return (--num_owners_ == 0);
165inline IntTupleSet::Data* IntTupleSet::Data::CopyIfShared() {
166 if (num_owners_ > 1) {
167 Data*
const new_data =
new Data(*
this);
168 RemovedSharedOwner();
169 new_data->AddSharedOwner();
176int IntTupleSet::Data::Insert(
const std::vector<T>& tuple) {
180 if (!Contains(tuple)) {
181 const int index = NumTuples();
182 const int offset = flat_tuples_.size();
183 flat_tuples_.resize(offset +
arity_);
185 for (
int i = 0; i <
arity_; ++i) {
186 flat_tuples_[offset + i] = tuple[i];
188 const int64_t fingerprint = Fingerprint(tuple);
189 tuple_fprint_to_index_[fingerprint].push_back(
index);
197bool IntTupleSet::Data::Contains(
const std::vector<T>& candidate)
const {
198 if (candidate.size() !=
arity_) {
201 const int64_t fingerprint = Fingerprint(candidate);
202 if (tuple_fprint_to_index_.contains(fingerprint)) {
203 const std::vector<int>& indices =
205 for (
int i = 0; i < indices.size(); ++i) {
206 const int tuple_index = indices[i];
207 for (
int j = 0; j <
arity_; ++j) {
208 if (candidate[j] != flat_tuples_[tuple_index *
arity_ + j]) {
219int64_t IntTupleSet::Data::Fingerprint(
const std::vector<T>& tuple)
const {
226 uint64_t x = tuple[0];
227 uint64_t y = uint64_t{0xe08c1d668b756f82};
228 uint64_t z = tuple[1];
233 uint64_t x = tuple[0];
234 uint64_t y = uint64_t{0xe08c1d668b756f82};
235 for (
int i = 1; i < tuple.size(); ++i) {
236 uint64_t z = tuple[i];
245inline int IntTupleSet::Data::NumTuples()
const {
246 return tuple_fprint_to_index_.size();
257inline int IntTupleSet::Data::Arity()
const {
return arity_; }
259inline const int64_t* IntTupleSet::Data::RawData()
const {
260 return flat_tuples_.data();
263inline void IntTupleSet::Data::Clear() {
264 flat_tuples_.clear();
265 tuple_fprint_to_index_.clear();
270 data_->AddSharedOwner();
274 data_->AddSharedOwner();
278 CHECK(data_ !=
nullptr);
279 if (data_->RemovedSharedOwner()) {
285 data_ = data_->CopyIfShared();
290 data_ = data_->CopyIfShared();
291 return data_->Insert(tuple);
295 data_ = data_->CopyIfShared();
296 return data_->Insert(tuple);
300 std::vector<int64_t> tuple(2);
307 std::vector<int64_t> tuple(3);
316 std::vector<int64_t> tuple(4);
325 return data_->Contains(tuple);
329 return data_->Contains(tuple);
333 const std::vector<std::vector<int> >& tuples) {
334 data_ = data_->CopyIfShared();
335 for (
int i = 0; i < tuples.size(); ++i) {
341 const std::vector<std::vector<int64_t> >& tuples) {
342 data_ = data_->CopyIfShared();
343 for (
int i = 0; i < tuples.size(); ++i) {
351 return data_->Value(
index, pos);
359 if (col < 0 || col >= data_->Arity()) {
362 absl::flat_hash_set<int64_t> values;
363 for (
int i = 0; i < data_->NumTuples(); ++i) {
364 values.insert(data_->Value(i,
col));
366 return values.size();
369inline bool IntTupleSet::IndexValue::Compare(
const IndexValue&
a,
370 const IndexValue&
b) {
371 return a.value <
b.value || (
a.value ==
b.value &&
a.index <
b.index);
375 std::vector<IndexValue> keys;
376 keys.reserve(data_->NumTuples());
380 std::sort(keys.begin(), keys.end(), IntTupleSet::IndexValue::Compare);
381 const int arity = data_->Arity();
383 for (
int i = 0; i < keys.size(); ++i) {
384 const int64_t* tuple_ptr = data_->RawData() + keys[i].index * arity;
385 sorted.
Insert(std::vector<int64_t>(tuple_ptr, tuple_ptr + arity));
390inline bool IntTupleSet::IndexData::Compare(
const IndexData&
a,
391 const IndexData&
b) {
392 const IntTupleSet::Data*
const data =
a.data;
393 const int arity = data->Arity();
394 for (
int i = 0; i < arity; ++i) {
395 const int64_t value1 = data->Value(
a.index, i);
396 const int64_t value2 = data->Value(
b.index, i);
397 if (value1 < value2) {
400 if (value1 > value2) {
408 std::vector<IndexData> keys;
409 keys.reserve(data_->NumTuples());
411 keys.push_back(IndexData(
index, data_));
413 std::sort(keys.begin(), keys.end(), IntTupleSet::IndexData::Compare);
414 const int arity = data_->Arity();
416 for (
int i = 0; i < keys.size(); ++i) {
417 std::vector<int64_t> tuple(arity);
418 const int64_t* tuple_ptr = data_->RawData() + keys[i].index * arity;
419 sorted.
Insert(std::vector<int64_t>(tuple_ptr, tuple_ptr + arity));
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
int Insert4(int64_t v0, int64_t v1, int64_t v2, int64_t v3)
IntTupleSet SortedLexicographically() const
int Insert2(int64_t v0, int64_t v1)
IntTupleSet SortedByColumn(int col) const
void InsertAll(const std::vector< std::vector< int64_t > > &tuples)
int64_t Value(int tuple_index, int pos_in_tuple) const
bool Contains(const std::vector< int > &tuple) const
int Insert(const std::vector< int > &tuple)
int NumDifferentValuesInColumn(int col) const
const int64_t * RawData() const
int Insert3(int64_t v0, int64_t v1, int64_t v2)
const Collection::value_type::second_type & FindOrDie(const Collection &collection, const typename Collection::value_type::first_type &key)
std::function< int64_t(const Model &)> Value(IntegerVariable v)
Collection of objects used to extend the Constraint Solver library.
static void mix(uint32_t &a, uint32_t &b, uint32_t &c)