14#ifndef OR_TOOLS_SAT_UTIL_H_
15#define OR_TOOLS_SAT_UTIL_H_
28#include "absl/base/macros.h"
29#include "absl/container/btree_set.h"
30#include "absl/container/inlined_vector.h"
31#include "absl/log/check.h"
32#include "absl/log/log_streamer.h"
33#include "absl/numeric/int128.h"
34#include "absl/random/bit_gen_ref.h"
35#include "absl/random/random.h"
36#include "absl/strings/str_cat.h"
37#include "absl/strings/string_view.h"
38#include "absl/types/span.h"
43#include "ortools/sat/sat_parameters.pb.h"
68template <
typename K =
int,
typename V =
int>
87 starts_.reserve(
size);
92 buffer_.reserve(num_terms);
101 template <
typename Keys,
typename Values>
113 int min_transpose_size = 0);
117 int Add(absl::Span<const V> values);
121 template <
typename L>
132 DCHECK_LT(
index, sizes_[key]);
133 const int start = starts_[key];
145 Add(absl::MakeSpan(begin,
end - begin));
150 static int InternalKey(K key);
152 std::vector<int> starts_;
153 std::vector<int> sizes_;
154 std::vector<V> buffer_;
167 data_.reset(
new T[
size]);
170 T*
data()
const {
return data_.get(); }
171 T*
begin()
const {
return data_.get(); }
172 T*
end()
const {
return data_.get() + size_; }
173 size_t size()
const {
return size_; }
174 bool empty()
const {
return size_ == 0; }
179 T
back()
const {
return data_[size_ - 1]; }
180 T&
back() {
return data_[size_ - 1]; }
189 std::unique_ptr<T[]> data_ =
nullptr;
197 return absl::StrCat(
"'",
name,
"':");
203std::string
FormatTable(std::vector<std::vector<std::string>>& table,
249 int64_t& x0, int64_t& y0);
275 const std::vector<std::vector<int>>&
graph, absl::BitGenRef random,
276 std::vector<int>* buffer);
291 int64_t base, absl::Span<const int64_t> coeffs,
292 absl::Span<const int64_t> lbs, absl::Span<const int64_t> ubs, int64_t rhs,
308 :
absl::BitGenRef(deterministic_random_) {
309 deterministic_random_.seed(params.random_seed());
310 if (params.use_absl_random()) {
311 absl_random_ = absl::BitGen(absl::SeedSeq({params.random_seed()}));
312 absl::BitGenRef::operator=(absl::BitGenRef(absl_random_));
327 absl::BitGen absl_random_;
338void RandomizeDecisionHeuristic(absl::BitGenRef random,
345int WeightedPick(absl::Span<const double>
input, absl::BitGenRef random);
367int MoveOneUnprocessedLiteralLast(
368 const absl::btree_set<LiteralIndex>& processed,
int relevant_prefix_size,
369 std::vector<Literal>* literals);
380 : max_complexity_per_add_(max_complexity_per_add) {
386 void Reset(int64_t
bound);
389 int64_t MaxIfAdded(int64_t candidate)
const;
392 void Add(int64_t
value);
397 void AddChoices(absl::Span<const int64_t> choices);
400 void AddMultiples(int64_t coeff, int64_t max_value);
406 int64_t
Bound()
const {
return bound_; }
410 void AddChoicesInternal(absl::Span<const int64_t> values);
413 const int max_complexity_per_add_;
416 int64_t current_max_;
417 std::vector<int64_t> sums_;
418 std::vector<bool> expanded_sums_;
419 std::vector<int64_t> filtered_values_;
434 reachable_.fill(std::numeric_limits<int64_t>::max());
436 new_reachable_[0] = 0;
442 void Add(
const int64_t positive_value) {
443 DCHECK_GT(positive_value, 0);
444 if (positive_value >= reachable_.back())
return;
450 for (
int base = 0; j < n && base < n; ++base) {
451 const int64_t candidate =
CapAdd(new_reachable_[base], positive_value);
452 while (j < n &&
i < n && reachable_[
i] < candidate) {
453 new_reachable_[j++] = reachable_[
i++];
457 while (
i < n && reachable_[
i] == candidate)
i++;
460 new_reachable_[j++] = candidate;
463 std::swap(reachable_, new_reachable_);
469 if (sum >= reachable_.back())
return true;
470 return std::binary_search(reachable_.begin(), reachable_.end(), sum);
473 const std::array<int64_t, n>&
reachable()
const {
return reachable_; }
477 std::array<int64_t, n> reachable_;
478 std::array<int64_t, n> new_reachable_;
499 bool infeasible =
false;
502 Result Solve(
const std::vector<Domain>& domains,
503 const std::vector<int64_t>& coeffs,
504 const std::vector<int64_t>& costs,
const Domain& rhs);
507 Result InternalSolve(int64_t num_values,
const Domain& rhs);
510 std::vector<Domain> domains_;
511 std::vector<int64_t> coeffs_;
512 std::vector<int64_t> costs_;
516 int64_t cost = std::numeric_limits<int64_t>::max();
519 std::vector<std::vector<State>> var_activity_states_;
527 : average_(initial_average) {}
531 void Reset(
double reset_value);
536 void AddData(
double new_record);
539 double average_ = 0.0;
540 int64_t num_records_ = 0;
550 : decaying_factor_(decaying_factor) {
551 DCHECK_GE(decaying_factor, 0.0);
552 DCHECK_LE(decaying_factor, 1.0);
561 void AddData(
double new_record);
564 double average_ = 0.0;
565 int64_t num_records_ = 0;
566 const double decaying_factor_;
579 explicit Percentile(
int record_limit) : record_limit_(record_limit) {}
581 void AddRecord(
double record);
587 double GetPercentile(
double percent);
590 std::deque<double> records_;
591 const int record_limit_;
603 std::vector<std::vector<int64_t>>* tuples);
623 absl::Span<const int64_t> domain_sizes,
624 std::vector<std::vector<int64_t>>* tuples);
631template <
typename Element,
typename Score>
634 explicit TopN(
int n) : n_(n) {}
641 void Add(Element e, Score score) {
642 if (heap_.size() < n_) {
643 const int index = elements_.size();
644 heap_.push_back({
index, score});
645 elements_.push_back(std::move(e));
646 if (heap_.size() == n_) {
648 std::make_heap(heap_.begin(), heap_.end());
651 if (score <= heap_.front().score)
return;
652 const int index_to_replace = heap_.front().index;
653 elements_[index_to_replace] = std::move(e);
656 std::pop_heap(heap_.begin(), heap_.end());
657 heap_.back() = {index_to_replace, score};
658 std::push_heap(heap_.begin(), heap_.end());
662 bool empty()
const {
return elements_.empty(); }
674 bool operator<(
const HeapElement& other)
const {
675 return score > other.score;
678 std::vector<HeapElement> heap_;
679 std::vector<Element> elements_;
687 if (std::isnan(
value))
return 0;
688 if (
value >=
static_cast<double>(std::numeric_limits<int64_t>::max())) {
689 return std::numeric_limits<int64_t>::max();
691 if (
value <=
static_cast<double>(std::numeric_limits<int64_t>::min())) {
692 return std::numeric_limits<int64_t>::min();
694 return static_cast<int64_t
>(
value);
699 return x <= absl::int128(std::numeric_limits<int64_t>::max()) &&
700 x > absl::int128(std::numeric_limits<int64_t>::min());
706template <
typename IntType,
bool ceil>
707IntType CeilOrFloorOfRatio(IntType numerator, IntType denominator) {
708 static_assert(std::numeric_limits<IntType>::is_integer,
709 "CeilOfRatio is only defined for integral types");
710 DCHECK_NE(0, denominator) <<
"Division by zero is not supported.";
711 DCHECK(numerator != std::numeric_limits<IntType>::min() || denominator != -1)
712 <<
"Dividing " << numerator <<
"by -1 is not supported: it would SIGFPE";
714 const IntType rounded_toward_zero = numerator / denominator;
715 const bool needs_round = (numerator % denominator) != 0;
716 const bool same_sign = (numerator >= 0) == (denominator >= 0);
719 return rounded_toward_zero +
static_cast<IntType
>(same_sign && needs_round);
721 return rounded_toward_zero -
722 static_cast<IntType
>(!same_sign && needs_round);
726template <
typename IntType>
727IntType
CeilOfRatio(IntType numerator, IntType denominator) {
728 return CeilOrFloorOfRatio<IntType, true>(numerator, denominator);
731template <
typename IntType>
732IntType FloorOfRatio(IntType numerator, IntType denominator) {
733 return CeilOrFloorOfRatio<IntType, false>(numerator, denominator);
736template <
typename K,
typename V>
737inline int CompactVectorVector<K, V>::Add(absl::Span<const V> values) {
739 starts_.push_back(buffer_.size());
740 sizes_.push_back(values.size());
741 buffer_.insert(buffer_.end(), values.begin(), values.end());
745template <
typename K,
typename V>
747 K key, absl::Span<const V> values) {
748 CHECK_LE(values.size(), sizes_[key]);
749 sizes_[key] = values.size();
750 if (values.empty())
return;
751 memcpy(&buffer_[starts_[key]], values.data(),
sizeof(V) * values.size());
754template <
typename K,
typename V>
757 const std::vector<L>& wrapped_values) {
759 starts_.push_back(buffer_.size());
760 sizes_.push_back(wrapped_values.size());
761 for (
const L wrapped_value : wrapped_values) {
762 buffer_.push_back(wrapped_value.Index().value());
768template <
typename K,
typename V>
769inline int CompactVectorVector<K, V>::InternalKey(K key) {
770 if constexpr (std::is_same_v<K, int>) {
777template <
typename K,
typename V>
778inline absl::Span<const V> CompactVectorVector<K, V>::operator[](K key)
const {
780 DCHECK_LT(key, starts_.size());
781 DCHECK_LT(key, sizes_.size());
782 const int k = InternalKey(key);
783 const size_t size =
static_cast<size_t>(sizes_[k]);
784 if (
size == 0)
return {};
785 return {&buffer_[starts_[k]],
size};
788template <
typename K,
typename V>
789inline absl::Span<V> CompactVectorVector<K, V>::operator[](K key) {
791 DCHECK_LT(key, starts_.size());
792 DCHECK_LT(key, sizes_.size());
793 const int k = InternalKey(key);
794 const size_t size =
static_cast<size_t>(sizes_[k]);
795 if (
size == 0)
return {};
796 return absl::MakeSpan(&buffer_[starts_[k]],
size);
799template <
typename K,
typename V>
800inline std::vector<absl::Span<const V>>
801CompactVectorVector<K, V>::AsVectorOfSpan()
const {
802 std::vector<absl::Span<const V>> result(starts_.size());
803 for (
int k = 0; k < starts_.size(); ++k) {
804 result[k] = (*this)[k];
809template <
typename K,
typename V>
810inline void CompactVectorVector<K, V>::clear() {
816template <
typename K,
typename V>
818 return starts_.size();
821template <
typename K,
typename V>
823 return starts_.empty();
826template <
typename K,
typename V>
827template <
typename Keys,
typename Values>
830 if (keys.empty())
return clear();
834 for (
const K key : keys) {
835 max_key = std::max(max_key, InternalKey(key) + 1);
839 sizes_.assign(max_key, 0);
840 for (
const K key : keys) {
841 sizes_[InternalKey(key)]++;
845 starts_.assign(max_key, 0);
846 for (
int k = 1; k < max_key; ++k) {
847 starts_[k] = starts_[k - 1] + sizes_[k - 1];
851 buffer_.resize(keys.size());
852 for (
int i = 0; i < keys.size(); ++i) {
853 buffer_[starts_[InternalKey(keys[i])]++] = values[i];
857 for (
int k = max_key - 1; k > 0; --k) {
858 starts_[k] = starts_[k - 1];
864template <
typename K,
typename V>
865inline void CompactVectorVector<K, V>::ResetFromTranspose(
866 const CompactVectorVector<V, K>& other,
int min_transpose_size) {
869 if (min_transpose_size > 0) {
870 starts_.assign(min_transpose_size, 0);
871 sizes_.assign(min_transpose_size, 0);
877 int max_key = min_transpose_size;
878 for (V v = 0; v < other.size(); ++v) {
879 for (
const K k : other[v]) {
880 max_key = std::max(max_key, InternalKey(k) + 1);
885 sizes_.assign(max_key, 0);
886 for (V v = 0; v < other.size(); ++v) {
887 for (
const K k : other[v]) {
888 sizes_[InternalKey(k)]++;
893 starts_.assign(max_key, 0);
894 for (
int k = 1; k < max_key; ++k) {
895 starts_[k] = starts_[k - 1] + sizes_[k - 1];
899 buffer_.resize(other.buffer_.size());
900 for (V v = 0; v < other.size(); ++v) {
901 for (
const K k : other[v]) {
902 buffer_[starts_[InternalKey(k)]++] = v;
907 for (
int k = max_key - 1; k > 0; --k) {
908 starts_[k] = starts_[k - 1];
Wrapper around TimeLimit to make it thread safe and add Stop() support.
void ResetFromFlatMapping(Keys keys, Values values)
void ResetFromTranspose(const CompactVectorVector< V, K > &other, int min_transpose_size=0)
Similar to ResetFromFlatMapping().
void clear()
Restore to empty vector<vector<>>.
absl::Span< V > operator[](K key)
void emplace_back(V const *begin, V const *end)
absl::Span< const V > operator[](K key) const
void ReplaceValuesBySmallerSet(K key, absl::Span< const V > values)
void reserve(int size, int num_terms)
std::vector< absl::Span< const V > > AsVectorOfSpan() const
void RemoveBySwap(K key, int index)
int AddLiterals(const std::vector< L > &wrapped_values)
size_t size() const
Size of the "key" space, always in [0, size()).
void reserve(int size)
Reserve memory if it is already known or tightly estimated.
int Add(absl::Span< const V > values)
double CurrentAverage() const
Returns exponential moving average for all the added data so far.
int64_t NumRecords() const
Returns the total number of added records so far.
ExponentialMovingAverage(double decaying_factor)
const std::array< int64_t, n > & reachable() const
int64_t LastValue() const
bool MightBeReachable(int64_t sum) const
void Add(const int64_t positive_value)
void ClearAndReserve(size_t size)
T operator[](int i) const
Manages incremental averages.
IncrementalAverage()=default
int64_t NumRecords() const
IncrementalAverage(double initial_average)
Initializes the average with 'initial_average' and number of records to 0.
double CurrentAverage() const
int64_t CurrentMax() const
MaxBoundedSubsetSum(int64_t bound, int max_complexity_per_add=50)
ModelRandomGenerator(const SatParameters ¶ms)
ModelRandomGenerator(Model *model)
The model "singleton" shared time limit.
ModelSharedTimeLimit(Model *model)
int64_t NumRecords() const
Returns number of stored records.
Percentile(int record_limit)
void Add(Element e, Score score)
std::vector< Element > * MutableUnorderedElements()
const std::vector< Element > & UnorderedElements() const
const std::string name
A name for logging purposes.
constexpr int64_t kTableAnyValue
void CompressTuples(absl::Span< const int64_t > domain_sizes, std::vector< std::vector< int64_t > > *tuples)
int64_t ProductWithModularInverse(int64_t coeff, int64_t mod, int64_t rhs)
bool SolveDiophantineEquationOfSizeTwo(int64_t &a, int64_t &b, int64_t &cte, int64_t &x0, int64_t &y0)
std::vector< std::vector< absl::InlinedVector< int64_t, 2 > > > FullyCompressTuples(absl::Span< const int64_t > domain_sizes, std::vector< std::vector< int64_t > > *tuples)
int64_t FloorSquareRoot(int64_t a)
The argument must be non-negative.
IntType CeilOfRatio(IntType numerator, IntType denominator)
int64_t CeilSquareRoot(int64_t a)
int64_t ModularInverse(int64_t x, int64_t m)
bool IsNegatableInt64(absl::int128 x)
Tells whether a int128 can be casted to a int64_t that can be negated.
int64_t SafeDoubleToInt64(double value)
std::string FormatCounter(int64_t num)
Prints a positive number with separators for easier reading (ex: 1'348'065).
int64_t ClosestMultiple(int64_t value, int64_t base)
int64_t PositiveMod(int64_t x, int64_t m)
Just returns x % m but with a result always in [0, m).
bool LinearInequalityCanBeReducedWithClosestMultiple(int64_t base, absl::Span< const int64_t > coeffs, absl::Span< const int64_t > lbs, absl::Span< const int64_t > ubs, int64_t rhs, int64_t *new_rhs)
std::vector< absl::Span< int > > AtMostOneDecomposition(const std::vector< std::vector< int > > &graph, absl::BitGenRef random, std::vector< int > *buffer)
std::string FormatName(absl::string_view name)
This is used to format our table first row entry.
std::string FormatTable(std::vector< std::vector< std::string > > &table, int spacing)
In SWIG mode, we don't want anything besides these top-level includes.
int64_t CapAdd(int64_t x, int64_t y)
std::mt19937_64 random_engine_t
static int input(yyscan_t yyscanner)
std::optional< int64_t > end
std::vector< int64_t > solution