14#ifndef ORTOOLS_SAT_UTIL_H_
15#define ORTOOLS_SAT_UTIL_H_
30#include "absl/base/attributes.h"
31#include "absl/container/btree_set.h"
32#include "absl/log/check.h"
33#include "absl/log/log_streamer.h"
34#include "absl/numeric/int128.h"
35#include "absl/random/bit_gen_ref.h"
36#include "absl/random/random.h"
37#include "absl/strings/str_cat.h"
38#include "absl/strings/string_view.h"
39#include "absl/types/span.h"
54template <
class Container,
class Pred>
56 auto it = std::remove_if(c.begin(), c.end(), pred);
76template <
typename K =
int,
typename V =
int>
98 starts_.reserve(
size);
112 template <
typename Keys,
typename Values>
114 int minimum_num_nodes = 0);
119 template <
typename Collection>
131 int min_transpose_size = 0);
138 template <
typename ValueMapper,
typename Container>
140 int min_transpose_size = 0);
144 int Add(absl::Span<const V> values);
150 template <
typename L>
161 DCHECK_LT(index, sizes_[key]);
162 const int start = starts_[key];
163 std::swap(buffer_[start + index], buffer_[start + sizes_[key] - 1]);
182 static int InternalKey(K key);
184 std::vector<int> starts_;
185 std::vector<int> sizes_;
186 std::vector<V> buffer_;
191template <
typename K =
int,
typename V =
int>
196 template <
typename ValueMapper,
typename Container>
198 int min_transpose_size = 0) {
201 next_.assign(rows_.size(), K(-1));
202 marked_.ClearAndResize(V(
input.size()));
203 merged_.ClearAndResize(K(rows_.size()));
206 int size()
const {
return rows_.size(); }
217 if (key >= rows_.size())
return {};
218 CHECK(!merged_[key]);
224 absl::Span<V> data = rows_[key];
225 for (
const V v : data) {
226 if (marked_[v])
continue;
228 tmp_result_.push_back(v);
229 data[new_size++] = v;
231 rows_.Shrink(key, new_size);
233 if (new_size == 0 && previous >= 0) {
235 next_[InternalKey(previous)] = next_[InternalKey(key)];
241 key = next_[InternalKey(key)];
245 for (
const V v : tmp_result_) marked_.Clear(v);
254 CHECK(!merged_[to_merge]);
255 DCHECK_GE(to_merge, 0);
256 DCHECK_GE(representative, 0);
257 DCHECK_LT(to_merge, rows_.size());
258 DCHECK_LT(representative, rows_.size());
259 if (to_merge == representative)
return;
260 merged_.Set(to_merge);
267 K last_list = representative;
268 while (next_[InternalKey(last_list)] >= 0) {
269 last_list = next_[InternalKey(last_list)];
270 DCHECK_NE(last_list, to_merge);
272 next_[InternalKey(last_list)] = to_merge;
276 next_[InternalKey(key)] = -1;
277 rows_.Shrink(key, 0);
282 int InternalKey(K key)
const;
286 std::vector<V> tmp_result_;
296 std::vector<K> next_;
310 data_.reset(
new T[size_]);
311 std::copy(span.begin(), span.end(), data_.get());
316 data_.reset(
new T[
size]);
319 T*
data()
const {
return data_.get(); }
320 T*
begin()
const {
return data_.get(); }
321 T*
end()
const {
return data_.get() + size_; }
322 size_t size()
const {
return size_; }
323 bool empty()
const {
return size_ == 0; }
328 T
back()
const {
return data_[size_ - 1]; }
329 T&
back() {
return data_[size_ - 1]; }
338 std::unique_ptr<T[]> data_ =
nullptr;
343 return absl::StrCat(
"'", name,
"':");
349std::string
FormatTable(std::vector<std::vector<std::string>>& table,
395 int64_t& x0, int64_t& y0);
427 const std::vector<std::vector<int>>& graph, absl::BitGenRef random,
428 std::vector<int>* buffer);
443 int64_t
base, absl::Span<const int64_t> coeffs,
444 absl::Span<const int64_t> lbs, absl::Span<const int64_t> ubs, int64_t rhs,
460 :
absl::BitGenRef(deterministic_random_) {
463 absl_random_ = absl::BitGen(absl::SeedSeq({params.random_seed()}));
464 absl::BitGenRef::operator=(absl::BitGenRef(absl_random_));
469 :
absl::BitGenRef(deterministic_random_) {
470 absl::BitGenRef::operator=(bit_gen_ref);
485 absl::BitGen absl_random_;
496void RandomizeDecisionHeuristic(absl::BitGenRef random,
497 SatParameters* parameters);
503int WeightedPick(absl::Span<const double>
input, absl::BitGenRef random);
525int MoveOneUnprocessedLiteralLast(
526 const absl::btree_set<LiteralIndex>& processed,
int relevant_prefix_size,
527 std::vector<Literal>* literals);
540std::vector<int> FindMostDiverseSubset(
int k,
int n,
541 absl::Span<const int64_t> distances,
542 std::vector<int64_t>& buffer,
543 int always_pick_mask = 0);
558std::vector<std::pair<int, int>> HeuristicallySplitLongLinear(
559 absl::Span<const int64_t> coeffs);
570 : max_complexity_per_add_(max_complexity_per_add) {
576 void Reset(int64_t bound);
579 void Add(int64_t value);
584 void AddChoices(absl::Span<const int64_t> choices);
587 void AddMultiples(int64_t coeff, int64_t max_value);
593 int64_t
Bound()
const {
return bound_; }
597 void AddChoicesInternal(absl::Span<const int64_t> values);
600 const int max_complexity_per_add_;
603 int64_t current_max_;
604 std::vector<int64_t> sums_;
605 std::vector<bool> expanded_sums_;
606 std::vector<int64_t> filtered_values_;
619 : reachable_(new int64_t[n]), new_reachable_(new int64_t[n]) {
624 for (
int i = 0;
i < n; ++
i) {
625 reachable_[
i] = std::numeric_limits<int64_t>::max();
628 new_reachable_[0] = 0;
634 void Add(
const int64_t positive_value) {
635 DCHECK_GT(positive_value, 0);
636 const int64_t*
reachable = reachable_.get();
637 if (positive_value >=
reachable[n - 1])
return;
643 int64_t* new_reachable = new_reachable_.get();
645 const int64_t candidate =
CapAdd(new_reachable[
base], positive_value);
646 while (j < n &&
i < n &&
reachable[
i] < candidate) {
654 new_reachable[j++] = candidate;
657 std::swap(reachable_, new_reachable_);
663 if (sum >= reachable_[n - 1])
return true;
664 return std::binary_search(&reachable_[0], &reachable_[0] + n, sum);
670 return absl::MakeSpan(reachable_.get(), n);
674 std::unique_ptr<int64_t[]> reachable_;
675 std::unique_ptr<int64_t[]> new_reachable_;
693 absl::Span<const int64_t>
Compute(absl::Span<const int64_t> elements,
695 bool abort_if_maximum_reached =
false);
698 absl::Span<const int64_t>
SortedSums()
const {
return sums_; }
701 std::vector<int64_t> sums_;
702 std::vector<int64_t> new_sums_;
714 int64_t
MaxSubsetSum(absl::Span<const int64_t> elements, int64_t bin_size);
748 absl::Span<const int64_t> coeffs,
749 absl::Span<const int64_t> costs,
const Domain& rhs);
752 Result InternalSolve(int64_t num_values,
const Domain& rhs);
755 std::vector<Domain> domains_;
756 std::vector<int64_t> coeffs_;
757 std::vector<int64_t> costs_;
761 int64_t cost = std::numeric_limits<int64_t>::max();
764 std::vector<std::vector<State>> var_activity_states_;
772 : average_(initial_average) {}
776 void Reset(
double reset_value);
781 void AddData(
double new_record);
784 double average_ = 0.0;
785 int64_t num_records_ = 0;
795 : decaying_factor_(decaying_factor) {
796 DCHECK_GE(decaying_factor, 0.0);
797 DCHECK_LE(decaying_factor, 1.0);
806 void AddData(
double new_record);
809 double average_ = 0.0;
810 int64_t num_records_ = 0;
811 const double decaying_factor_;
824 explicit Percentile(
int record_limit) : record_limit_(record_limit) {}
826 void AddRecord(
double record);
832 double GetPercentile(
double percent);
835 std::deque<double> records_;
836 const int record_limit_;
844template <
typename Element,
typename Score>
847 explicit TopN(
int n) : n_(n) {}
854 void Add(Element e, Score score) {
855 if (heap_.size() < n_) {
856 const int index = elements_.size();
857 heap_.push_back({index, score});
858 elements_.push_back(std::move(e));
859 if (heap_.size() == n_) {
861 std::make_heap(heap_.begin(), heap_.end());
864 if (score <= heap_.front().score)
return;
865 const int index_to_replace = heap_.front().index;
866 elements_[index_to_replace] = std::move(e);
869 std::pop_heap(heap_.begin(), heap_.end());
870 heap_.back() = {index_to_replace, score};
871 std::push_heap(heap_.begin(), heap_.end());
875 bool empty()
const {
return elements_.empty(); }
887 bool operator<(
const HeapElement& other)
const {
888 return score > other.score;
891 std::vector<HeapElement> heap_;
892 std::vector<Element> elements_;
899 absl::Span<const Literal> superset) {
900 if (subset_size >= superset.size())
return false;
901 int budget = superset.size() - subset_size;
902 for (
const Literal l : superset) {
905 if (budget < 0)
return false;
915inline int64_t SafeDoubleToInt64(
double value) {
916 if (std::isnan(value))
return 0;
917 if (value >=
static_cast<double>(std::numeric_limits<int64_t>::max())) {
918 return std::numeric_limits<int64_t>::max();
920 if (value <=
static_cast<double>(std::numeric_limits<int64_t>::min())) {
921 return std::numeric_limits<int64_t>::min();
923 return static_cast<int64_t
>(value);
928 return x <= absl::int128(std::numeric_limits<int64_t>::max()) &&
929 x > absl::int128(std::numeric_limits<int64_t>::min());
932template <
typename K,
typename V>
933inline int CompactVectorVector<K, V>::Add(absl::Span<const V> values) {
934 const int index = size();
935 starts_.push_back(buffer_.size());
936 sizes_.push_back(values.size());
937 buffer_.insert(buffer_.end(), values.begin(), values.end());
941template <
typename K,
typename V>
944 buffer_.push_back(value);
947template <
typename K,
typename V>
949 absl::Span<const V> values) {
950 sizes_.back() += values.size();
951 buffer_.insert(buffer_.end(), values.begin(), values.end());
954template <
typename K,
typename V>
956 K key, absl::Span<const V> values) {
957 CHECK_LE(values.size(), sizes_[key]);
958 sizes_[key] = values.size();
959 if (values.empty())
return;
960 memcpy(&buffer_[starts_[key]], values.data(),
sizeof(V) * values.size());
963template <
typename K,
typename V>
966 const std::vector<L>& wrapped_values) {
968 starts_.push_back(buffer_.size());
969 sizes_.push_back(wrapped_values.size());
970 for (
const L wrapped_value : wrapped_values) {
971 buffer_.push_back(wrapped_value.Index().value());
977template <
typename K,
typename V>
978inline int CompactVectorVector<K, V>::InternalKey(K key) {
979 if constexpr (std::is_same_v<K, int>) {
986template <
typename K,
typename V>
987inline void CompactVectorVector<K, V>::Shrink(K key,
int new_size) {
988 const int k = InternalKey(key);
989 DCHECK_LE(new_size, sizes_[k]);
990 sizes_[k] = new_size;
993template <
typename K,
typename V>
996 DCHECK_LT(key, starts_.size());
997 DCHECK_LT(key, sizes_.size());
998 const int k = InternalKey(key);
999 const size_t size =
static_cast<size_t>(sizes_.data()[k]);
1000 if (
size == 0)
return {};
1001 return {&buffer_.data()[starts_.data()[k]], size};
1004template <
typename K,
typename V>
1005inline absl::Span<V> CompactVectorVector<K, V>::operator[](K key) {
1007 DCHECK_LT(key, starts_.size());
1008 DCHECK_LT(key, sizes_.size());
1009 const int k = InternalKey(key);
1010 const size_t size =
static_cast<size_t>(sizes_.data()[k]);
1011 if (
size == 0)
return {};
1012 return absl::MakeSpan(&buffer_.data()[starts_.data()[k]], size);
1015template <
typename K,
typename V>
1016inline std::vector<absl::Span<const V>>
1017CompactVectorVector<K, V>::AsVectorOfSpan()
const {
1018 std::vector<absl::Span<const V>> result(starts_.size());
1019 for (
int k = 0; k < starts_.size(); ++k) {
1020 result[k] = (*this)[k];
1025template <
typename K,
typename V>
1026inline void CompactVectorVector<K, V>::clear() {
1032template <
typename K,
typename V>
1034 return starts_.size();
1037template <
typename K,
typename V>
1039 return starts_.empty();
1042template <
typename K,
typename V>
1043template <
typename Keys,
typename Values>
1045 Keys keys, Values values,
int minimum_num_nodes) {
1047 int max_key = minimum_num_nodes;
1048 for (
const K key : keys) {
1049 max_key = std::max(max_key, InternalKey(key) + 1);
1054 sizes_.assign(minimum_num_nodes, 0);
1055 starts_.assign(minimum_num_nodes, 0);
1060 sizes_.assign(max_key, 0);
1061 for (
const K key : keys) {
1062 sizes_[InternalKey(key)]++;
1066 starts_.assign(max_key, 0);
1067 for (
int k = 1; k < max_key; ++k) {
1068 starts_[k] = starts_[k - 1] + sizes_[k - 1];
1072 buffer_.resize(keys.size());
1073 for (
int i = 0;
i < keys.size(); ++
i) {
1074 buffer_[starts_[InternalKey(keys[i])]++] = values[
i];
1078 for (
int k = max_key - 1; k > 0; --k) {
1079 starts_[k] = starts_[k - 1];
1085template <
typename K,
typename V>
1086template <
typename Collection>
1087inline void CompactVectorVector<K, V>::ResetFromPairs(
const Collection& pairs,
1088 int minimum_num_nodes) {
1090 int max_key = minimum_num_nodes;
1091 for (
const auto& [key, _] : pairs) {
1092 max_key = std::max(max_key, InternalKey(key) + 1);
1095 if (pairs.empty()) {
1097 sizes_.assign(minimum_num_nodes, 0);
1098 starts_.assign(minimum_num_nodes, 0);
1103 sizes_.assign(max_key, 0);
1104 for (
const auto& [key, _] : pairs) {
1105 sizes_[InternalKey(key)]++;
1109 starts_.assign(max_key, 0);
1110 for (
int k = 1; k < max_key; ++k) {
1111 starts_[k] = starts_[k - 1] + sizes_[k - 1];
1115 buffer_.resize(pairs.size());
1116 for (
int i = 0;
i < pairs.size(); ++
i) {
1117 const auto& [key, value] = pairs[
i];
1118 buffer_[starts_[InternalKey(key)]++] = value;
1122 for (
int k = max_key - 1; k > 0; --k) {
1123 starts_[k] = starts_[k - 1];
1129template <
typename K,
typename V>
1130template <
typename ValueMapper,
typename Container>
1131void CompactVectorVector<K, V>::ResetFromTransposeMap(
const Container& other,
1132 int min_transpose_size) {
1134 if (other.size() == 0) {
1136 if (min_transpose_size > 0) {
1137 starts_.assign(min_transpose_size, 0);
1138 sizes_.assign(min_transpose_size, 0);
1144 int max_key = min_transpose_size;
1145 int num_entries = 0;
1146 for (V v(0); v < other.size(); ++v) {
1147 num_entries += other[v].size();
1148 for (
const auto k : other[v]) {
1149 max_key = std::max(max_key, InternalKey(mapper(k)) + 1);
1154 sizes_.assign(max_key, 0);
1155 for (V v(0); v < other.size(); ++v) {
1156 for (
const auto k : other[v]) {
1157 sizes_[InternalKey(mapper(k))]++;
1162 starts_.assign(max_key, 0);
1163 for (
int k = 1; k < max_key; ++k) {
1164 starts_[k] = starts_[k - 1] + sizes_[k - 1];
1168 buffer_.resize(num_entries);
1169 for (V v(0); v < other.size(); ++v) {
1170 for (
const auto k : other[v]) {
1171 buffer_[starts_[InternalKey(mapper(k))]++] = v;
1176 for (
int k = max_key - 1; k > 0; --k) {
1177 starts_[k] = starts_[k - 1];
1183template <
typename K,
typename V>
1184inline void CompactVectorVector<K, V>::ResetFromTranspose(
1185 const CompactVectorVector<V, K>& other,
int min_transpose_size) {
1187 K operator()(K k)
const {
return k; }
1189 ResetFromTransposeMap<NoOpMapper, CompactVectorVector<V, K>>(
1190 other, min_transpose_size);
1217class DagTopologicalSortIterator {
1223 : graph_(size,
std::vector<int>{}) {}
1258 friend bool operator==(
const Iterator& a,
const Iterator&
b) {
1259 return &a.graph_ == &
b.graph_ && a.ordering_index_ ==
b.ordering_index_;
1266 reference
operator*()
const {
return permutation_; }
1272 explicit Iterator(
const std::vector<std::vector<int>>& graph
1273 ABSL_ATTRIBUTE_LIFETIME_BOUND,
1275 : graph_(graph), ordering_index_(-1) {}
1278 explicit Iterator(
const std::vector<std::vector<int>>& graph
1279 ABSL_ATTRIBUTE_LIFETIME_BOUND);
1282 void Unset(
int pos);
1285 void Set(
int pos,
int k);
1288 const std::vector<std::vector<int>>& graph_;
1293 std::vector<int> missing_parent_numbers_;
1296 std::vector<int> permutation_;
1299 std::vector<int> element_original_position_;
1303 int64_t ordering_index_;
1306 Iterator
begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1307 return Iterator(graph_);
1309 Iterator
end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
1310 return Iterator(graph_,
true);
1313 void Reset(
int size) { graph_.assign(size, {}); }
1318 DCHECK_LT(from, graph_.size());
1320 DCHECK_LT(
to, graph_.size());
1321 graph_[from].push_back(
to);
1326 std::vector<std::vector<int>> graph_;
1348inline DagTopologicalSortIterator::Iterator&
1349DagTopologicalSortIterator::Iterator::operator++() {
1350 CHECK_GE(ordering_index_, 0) <<
"Iteration past end";
1354 ordering_index_ = -1;
1359 for (
int pos = size_ - 2; pos >= 0; --pos) {
1369 const int k = element_original_position_[pos] + 1;
1375 if (k == permutation_.size())
continue;
1378 for (++pos; pos < size_; ++pos) {
1384 CHECK_LT(pos, permutation_.size())
1385 <<
"Unexpected cycle detected during iteration";
1396 ordering_index_ = -1;
1400inline DagTopologicalSortIterator::Iterator::Iterator(
1401 const std::vector<std::vector<int>>& graph)
1403 size_(graph.size()),
1404 missing_parent_numbers_(size_, 0),
1405 element_original_position_(size_, 0),
1406 ordering_index_(0) {
1413 for (
const auto& children : graph_) {
1414 for (
const int child : children) {
1415 missing_parent_numbers_[child]++;
1419 for (
int i = 0;
i < size_; ++
i) {
1420 if (missing_parent_numbers_[
i] == 0) {
1421 permutation_.push_back(
i);
1424 for (
int pos = 0; pos < size_; ++pos) {
1428 if (pos >= permutation_.size()) {
1429 ordering_index_ = -1;
1445inline void DagTopologicalSortIterator::Iterator::Unset(
int pos) {
1446 const int n = permutation_[pos];
1449 for (
const int c : graph_[n]) {
1450 if (missing_parent_numbers_[c] == 0) permutation_.pop_back();
1451 ++missing_parent_numbers_[
c];
1453 std::swap(permutation_[element_original_position_[pos]], permutation_[pos]);
1455 element_original_position_[pos] = pos;
1464inline void DagTopologicalSortIterator::Iterator::Set(
int pos,
int k) {
1465 int n = permutation_[k];
1468 for (
int c : graph_[n]) {
1469 --missing_parent_numbers_[
c];
1470 if (missing_parent_numbers_[c] == 0) permutation_.push_back(c);
1473 std::swap(permutation_[k], permutation_[pos]);
1475 element_original_position_[pos] = k;
1478template <
typename K,
typename V>
1479inline int MergeableOccurrenceList<K, V>::InternalKey(K key)
const {
1481 DCHECK_LT(key, rows_.size());
1482 if constexpr (std::is_same_v<K, int>) {
SharedTimeLimit(TimeLimit *time_limit)
Result Solve(absl::Span< const Domain > domains, absl::Span< const int64_t > coeffs, absl::Span< const int64_t > costs, const Domain &rhs)
void ResetFromTranspose(const CompactVectorVector< V, K > &other, int min_transpose_size=0)
void ResetFromPairs(const Collection &pairs, int minimum_num_nodes=0)
void ResetFromFlatMapping(Keys keys, Values values, int minimum_num_nodes=0)
void reserve(int size, int num_entries)
absl::Span< V > operator[](K key)
void emplace_back(V const *begin, V const *end)
size_t num_entries() const
void ReplaceValuesBySmallerSet(K key, absl::Span< const V > values)
void Shrink(K key, int new_size)
std::vector< absl::Span< const V > > AsVectorOfSpan() const
void RemoveBySwap(K key, int index)
int AddLiterals(const std::vector< L > &wrapped_values)
void AppendToLastVector(const V &value)
int Add(absl::Span< const V > values)
void ResetFromTransposeMap(const Container &other, int min_transpose_size=0)
const std::vector< int > value_type
ptrdiff_t difference_type
std::input_iterator_tag iterator_category
pointer operator->() const
friend bool operator==(const Iterator &a, const Iterator &b)
DagTopologicalSortIterator()=default
void AddArc(int from, int to)
double CurrentAverage() const
int64_t NumRecords() const
ExponentialMovingAverage(double decaying_factor)
int64_t LastValue() const
absl::Span< const int64_t > reachable()
bool MightBeReachable(int64_t sum) const
void Add(const int64_t positive_value)
FixedCapacityVector(absl::Span< const T > span)
void ClearAndReserve(size_t size)
FixedCapacityVector()=default
T operator[](int i) const
void Reset(double reset_value)
IncrementalAverage()=default
int64_t NumRecords() const
IncrementalAverage(double initial_average)
double CurrentAverage() const
double ComplexityEstimate(int num_elements, int64_t bin_size)
int64_t MaxSubsetSum(absl::Span< const int64_t > elements, int64_t bin_size)
int64_t CurrentMax() const
void Reset(int64_t bound)
MaxBoundedSubsetSum(int64_t bound, int max_complexity_per_add=50)
void RemoveFromFutureOutput(V value)
MergeableOccurrenceList()=default
void ResetFromTransposeMap(const Container &input, int min_transpose_size=0)
absl::Span< const V > operator[](K key)
void MergeInto(K to_merge, K representative)
ModelRandomGenerator(const absl::BitGenRef &bit_gen_ref)
ModelRandomGenerator(const SatParameters ¶ms)
ModelRandomGenerator(Model *model)
ModelSharedTimeLimit(Model *model)
int64_t NumRecords() const
Percentile(int record_limit)
bool use_absl_random() const
::int32_t random_seed() const
absl::Span< const int64_t > Compute(absl::Span< const int64_t > elements, int64_t maximum_sum, bool abort_if_maximum_reached=false)
absl::Span< const int64_t > SortedSums() const
void Add(Element e, Score score)
std::vector< Element > * MutableUnorderedElements()
const std::vector< Element > & UnorderedElements() const
void OpenSourceEraseIf(Container &c, Pred pred)
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)
int64_t FloorSquareRoot(int64_t a)
int64_t CeilSquareRoot(int64_t a)
int64_t ModularInverse(int64_t x, int64_t m)
bool IsNegatableInt64(absl::int128 x)
int64_t SafeDoubleToInt64(double value)
bool DiophantineEquationOfSizeTwoHasSolutionInDomain(const Domain &x, int64_t a, const Domain &y, int64_t b, int64_t cte)
bool IsStrictlyIncluded(Bitset64< LiteralIndex >::ConstView in_subset, int subset_size, absl::Span< const Literal > superset)
int64_t ClosestMultiple(int64_t value, int64_t base)
int64_t PositiveMod(int64_t x, int64_t 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)
LinearExpr operator*(LinearExpr expr, int64_t factor)
std::string FormatName(absl::string_view name)
std::string FormatTable(std::vector< std::vector< std::string > > &table, int spacing)
int64_t CapAdd(int64_t x, int64_t y)
std::mt19937_64 random_engine_t
ClosedInterval::Iterator end(ClosedInterval interval)
ClosedInterval::Iterator begin(ClosedInterval interval)
trees with all degrees equal to
static int input(yyscan_t yyscanner)
std::vector< int64_t > solution