33#ifndef OR_TOOLS_UTIL_TUPLE_SET_H_
34#define OR_TOOLS_UTIL_TUPLE_SET_H_
40#include "absl/container/flat_hash_map.h"
41#include "absl/container/flat_hash_set.h"
62 int Insert(
const std::vector<int>& tuple);
63 int Insert(
const std::vector<int64_t>& tuple);
65 int Insert2(int64_t v0, int64_t v1);
66 int Insert3(int64_t v0, int64_t v1, int64_t v2);
67 int Insert4(int64_t v0, int64_t v1, int64_t v2, int64_t v3);
69 void InsertAll(
const std::vector<std::vector<int64_t> >& tuples);
70 void InsertAll(
const std::vector<std::vector<int> >& tuples);
73 bool Contains(
const std::vector<int>& tuple)
const;
74 bool Contains(
const std::vector<int64_t>& tuple)
const;
81 int64_t
Value(
int tuple_index,
int pos_in_tuple)
const;
99 explicit Data(
int arity);
100 Data(
const Data& data);
102 void AddSharedOwner();
103 bool RemovedSharedOwner();
104 Data* CopyIfShared();
106 int Insert(
const std::vector<T>& tuple);
108 bool Contains(
const std::vector<T>& candidate)
const;
110 int64_t Fingerprint(
const std::vector<T>& tuple)
const;
111 int NumTuples()
const;
112 int64_t Value(
int index,
int pos)
const;
114 const int64_t* RawData()
const;
121 std::vector<int64_t> flat_tuples_;
125 absl::flat_hash_map<int64_t, std::vector<int> > tuple_fprint_to_index_;
131 IntTupleSet::Data* data;
132 IndexData(
int i, IntTupleSet::Data*
const d) :
index(i), data(d) {}
133 static bool Compare(
const IndexData&
a,
const IndexData&
b);
139 IndexValue(
int i, int64_t v) :
index(i),
value(v) {}
140 static bool Compare(
const IndexValue&
a,
const IndexValue&
b);
147inline IntTupleSet::Data::Data(
int arity) :
arity_(arity), num_owners_(0) {}
149inline IntTupleSet::Data::Data(
const Data& data)
152 flat_tuples_(data.flat_tuples_),
153 tuple_fprint_to_index_(data.tuple_fprint_to_index_) {}
155inline IntTupleSet::Data::~Data() {}
157inline void IntTupleSet::Data::AddSharedOwner() { num_owners_++; }
159inline bool IntTupleSet::Data::RemovedSharedOwner() {
160 return (--num_owners_ == 0);
163inline IntTupleSet::Data* IntTupleSet::Data::CopyIfShared() {
164 if (num_owners_ > 1) {
165 Data*
const new_data =
new Data(*
this);
166 RemovedSharedOwner();
167 new_data->AddSharedOwner();
174int IntTupleSet::Data::Insert(
const std::vector<T>& tuple) {
175 DCHECK(
arity_ == 0 || flat_tuples_.size() %
arity_ == 0);
176 CHECK_EQ(
arity_, tuple.size());
177 DCHECK_EQ(1, num_owners_);
180 const int offset = flat_tuples_.size();
181 flat_tuples_.resize(offset +
arity_);
184 flat_tuples_[offset +
i] = tuple[
i];
186 const int64_t fingerprint = Fingerprint(tuple);
187 tuple_fprint_to_index_[fingerprint].push_back(
index);
195bool IntTupleSet::Data::Contains(
const std::vector<T>& candidate)
const {
196 if (candidate.size() !=
arity_) {
199 const int64_t fingerprint = Fingerprint(candidate);
200 if (tuple_fprint_to_index_.contains(fingerprint)) {
201 const std::vector<int>& indices = tuple_fprint_to_index_.at(fingerprint);
202 for (
int i = 0;
i < indices.size(); ++
i) {
203 const int tuple_index = indices[
i];
204 for (
int j = 0; j <
arity_; ++j) {
205 if (candidate[j] != flat_tuples_[tuple_index *
arity_ + j]) {
216int64_t IntTupleSet::Data::Fingerprint(
const std::vector<T>& tuple)
const {
223 uint64_t
x = tuple[0];
224 uint64_t
y = uint64_t{0xe08c1d668b756f82};
225 uint64_t z = tuple[1];
230 uint64_t
x = tuple[0];
231 uint64_t
y = uint64_t{0xe08c1d668b756f82};
232 for (
int i = 1;
i < tuple.size(); ++
i) {
233 uint64_t z = tuple[
i];
242inline int IntTupleSet::Data::NumTuples()
const {
243 return tuple_fprint_to_index_.size();
246inline int64_t IntTupleSet::Data::Value(
int index,
int pos)
const {
254inline int IntTupleSet::Data::Arity()
const {
return arity_; }
256inline const int64_t* IntTupleSet::Data::RawData()
const {
257 return flat_tuples_.data();
260inline void IntTupleSet::Data::Clear() {
261 flat_tuples_.clear();
262 tuple_fprint_to_index_.clear();
267 data_->AddSharedOwner();
271 data_->AddSharedOwner();
275 CHECK(data_ !=
nullptr);
276 if (data_->RemovedSharedOwner()) {
282 data_ = data_->CopyIfShared();
287 data_ = data_->CopyIfShared();
288 return data_->Insert(tuple);
292 data_ = data_->CopyIfShared();
293 return data_->Insert(tuple);
297 std::vector<int64_t> tuple(2);
304 std::vector<int64_t> tuple(3);
313 std::vector<int64_t> tuple(4);
322 return data_->Contains(tuple);
326 return data_->Contains(tuple);
330 const std::vector<std::vector<int> >& tuples) {
331 data_ = data_->CopyIfShared();
332 for (
int i = 0; i < tuples.size(); ++i) {
338 const std::vector<std::vector<int64_t> >& tuples) {
339 data_ = data_->CopyIfShared();
340 for (
int i = 0; i < tuples.size(); ++i) {
348 return data_->Value(
index, pos);
359 absl::flat_hash_set<int64_t> values;
360 for (
int i = 0; i < data_->NumTuples(); ++i) {
361 values.insert(data_->Value(i,
col));
363 return values.size();
366inline bool IntTupleSet::IndexValue::Compare(
const IndexValue&
a,
367 const IndexValue&
b) {
368 return a.value <
b.value || (
a.value ==
b.value &&
a.index <
b.index);
372 std::vector<IndexValue> keys;
373 keys.reserve(data_->NumTuples());
377 std::sort(keys.begin(), keys.end(), IntTupleSet::IndexValue::Compare);
378 const int arity = data_->Arity();
380 for (
int i = 0; i < keys.size(); ++i) {
381 const int64_t* tuple_ptr = data_->RawData() + keys[i].index * arity;
382 sorted.
Insert(std::vector<int64_t>(tuple_ptr, tuple_ptr + arity));
387inline bool IntTupleSet::IndexData::Compare(
const IndexData&
a,
388 const IndexData&
b) {
389 const IntTupleSet::Data*
const data =
a.data;
390 const int arity = data->Arity();
391 for (
int i = 0; i < arity; ++i) {
392 const int64_t value1 = data->Value(
a.index, i);
393 const int64_t value2 = data->Value(
b.index, i);
394 if (value1 < value2) {
397 if (value1 > value2) {
405 std::vector<IndexData> keys;
406 keys.reserve(data_->NumTuples());
408 keys.push_back(IndexData(
index, data_));
410 std::sort(keys.begin(), keys.end(), IntTupleSet::IndexData::Compare);
411 const int arity = data_->Arity();
413 for (
int i = 0; i < keys.size(); ++i) {
414 std::vector<int64_t> tuple(arity);
415 const int64_t* tuple_ptr = data_->RawData() + keys[i].index * arity;
416 sorted.
Insert(std::vector<int64_t>(tuple_ptr, tuple_ptr + arity));
--— Main IntTupleSet class --—
int Insert3(int64_t v0, int64_t v1, int64_t v2)
int Insert4(int64_t v0, int64_t v1, int64_t v2, int64_t v3)
IntTupleSet(int arity)
Creates an empty tuple set with a fixed length for all tuples.
int64_t Value(int tuple_index, int pos_in_tuple) const
int NumTuples() const
Returns the number of tuples.
bool Contains(const std::vector< int > &tuple) const
Checks if the tuple is in the set.
int Insert(const std::vector< int > &tuple)
int Insert2(int64_t v0, int64_t v1)
Arity fixed version of Insert removing the need for a vector for the user.
int NumDifferentValuesInColumn(int col) const
Returns the number of different values in the given column.
IntTupleSet SortedLexicographically() const
Returns a copy of the tuple set lexicographically sorted.
int Arity() const
Returns the arity of the set.
void InsertAll(const std::vector< std::vector< int64_t > > &tuples)
Inserts the tuples.
IntTupleSet SortedByColumn(int col) const
const int64_t * RawData() const
Access the raw data, see IntTupleSet::Data::flat_tuples_.
In SWIG mode, we don't want anything besides these top-level includes.
static void mix(uint64_t &a, uint64_t &b, uint64_t &c)
64 bit version.