Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
util.h
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#ifndef ORTOOLS_SAT_UTIL_H_
15#define ORTOOLS_SAT_UTIL_H_
16
17#include <algorithm>
18#include <cmath>
19#include <cstddef>
20#include <cstdint>
21#include <deque>
22#include <iterator>
23#include <limits>
24#include <memory>
25#include <string>
26#include <type_traits>
27#include <utility>
28#include <vector>
29
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"
41#include "ortools/sat/model.h"
48
49namespace operations_research {
50namespace sat {
51
52// Removes all elements for which `pred` returns true.
53// This implementation provides std::erase_if for C++17.
54template <class Container, class Pred>
55void OpenSourceEraseIf(Container& c, Pred pred) {
56 auto it = std::remove_if(c.begin(), c.end(), pred);
57 c.erase(it, c.end());
58}
59
60// A simple class with always IdentityMap[t] == t.
61// This is to avoid allocating vector with std::iota() in some Apis.
62template <typename T>
64 public:
65 T operator[](T t) const { return t; }
66};
67
68// Small utility class to store a vector<vector<>> where one can only append new
69// vector and never change previously added ones. This allows to store a static
70// key -> value(s) mapping.
71//
72// This is a lot more compact memorywise and thus faster than vector<vector<>>.
73// Note that we implement a really small subset of the vector<vector<>> API.
74//
75// We support int and StrongType for key K and any copyable type for value V.
76template <typename K = int, typename V = int>
78 public:
79 using value_type = V;
80
81 // Size of the "key" space, always in [0, size()).
82 size_t size() const;
83 bool empty() const;
84 size_t num_entries() const { return buffer_.size(); }
85
86 // Getters, either via [] or via a wrapping to be compatible with older api.
87 //
88 // Warning: Spans are only valid until the next modification!
89 absl::Span<V> operator[](K key);
90 absl::Span<const V> operator[](K key) const;
91 std::vector<absl::Span<const V>> AsVectorOfSpan() const;
92
93 // Restore to empty vector<vector<>>.
94 void clear();
95
96 // Reserve memory if it is already known or tightly estimated.
97 void reserve(int size) {
98 starts_.reserve(size);
99 sizes_.reserve(size);
100 }
101 void reserve(int size, int num_entries) {
102 reserve(size);
103 buffer_.reserve(num_entries);
104 }
105
106 // Given a flat mapping (keys[i] -> values[i]) with two parallel vectors, not
107 // necessarily sorted by key, regroup the same key so that
108 // CompactVectorVector[key] list all values in the order in which they appear.
109 //
110 // We only check keys.size(), so this can be used with IdentityMap() as
111 // second argument.
112 template <typename Keys, typename Values>
113 void ResetFromFlatMapping(Keys keys, Values values,
114 int minimum_num_nodes = 0);
115
116 // Same as above but for any collections of std::pair<K, V>, or, more
117 // generally, any iterable collection of objects that have a `first` and a
118 // `second` members.
119 template <typename Collection>
120 void ResetFromPairs(const Collection& pairs, int minimum_num_nodes = 0);
121
122 // Initialize this vector from the transpose of another.
123 // IMPORTANT: This cannot be called with the vector itself.
124 //
125 // If min_transpose_size is given, then the transpose will have at least this
126 // size even if some of the last keys do not appear in other.
127 //
128 // If this is called twice in a row, then it has the side effect of sorting
129 // all inner vectors by values !
131 int min_transpose_size = 0);
132
133 // Same as above, but more generic:
134 // - `other` can be anything that accepts `other.size()` and `other[i]`, with
135 // `other[i]` returning something we can iterate over in a for-loop.
136 // - The mapper type `ValueMapper` is a functor that takes an element that we
137 // get by iterating over `other[i]` and returns a value of type `K`.
138 template <typename ValueMapper, typename Container>
139 void ResetFromTransposeMap(const Container& other,
140 int min_transpose_size = 0);
141
142 // Append a new entry.
143 // Returns the previous size() as this is convenient for how we use it.
144 int Add(absl::Span<const V> values);
145 void AppendToLastVector(const V& value);
146 void AppendToLastVector(absl::Span<const V> values);
147
148 // Hacky: same as Add() but for sat::Literal or any type from which we can get
149 // a value type V via L.Index().value().
150 template <typename L>
151 int AddLiterals(const std::vector<L>& wrapped_values);
152
153 // We lied when we said this is a pure read-only class :)
154 // It is possible to shrink inner vectors with not much cost.
155 //
156 // Removes the element at index from this[key] by swapping it with
157 // this[key].back() and then decreasing this key size. It is an error to
158 // call this on an empty inner vector.
159 void RemoveBySwap(K key, int index) {
160 DCHECK_GE(index, 0);
161 DCHECK_LT(index, sizes_[key]);
162 const int start = starts_[key];
163 std::swap(buffer_[start + index], buffer_[start + sizes_[key] - 1]);
164 sizes_[key]--;
165 }
166
167 // Replace the values at the given key.
168 // This will crash if there are more values than before.
169 void ReplaceValuesBySmallerSet(K key, absl::Span<const V> values);
170
171 // Shrinks the inner vector size of the given key.
172 void Shrink(K key, int new_size);
173
174 // Interface so this can be used as an output of
175 // FindStronglyConnectedComponents().
176 void emplace_back(V const* begin, V const* end) {
177 Add(absl::MakeSpan(begin, end - begin));
178 }
179
180 private:
181 // Convert int and StrongInt to normal int.
182 static int InternalKey(K key);
183
184 std::vector<int> starts_;
185 std::vector<int> sizes_;
186 std::vector<V> buffer_;
187};
188
189// Similar to a CompactVectorVector<K, V> but allow to merge rows.
190// This however lead to a slower [] operator.
191template <typename K = int, typename V = int>
193 public:
195
196 template <typename ValueMapper, typename Container>
197 void ResetFromTransposeMap(const Container& input,
198 int min_transpose_size = 0) {
200 min_transpose_size);
201 next_.assign(rows_.size(), K(-1));
202 marked_.ClearAndResize(V(input.size()));
203 merged_.ClearAndResize(K(rows_.size()));
204 }
205
206 int size() const { return rows_.size(); }
207
208 // Any value here will never appear in the result of operator[] anymore.
209 void RemoveFromFutureOutput(V value) { marked_.Set(value); }
210
211 // Returns a "set" of values V for the given key.
212 // There will never be duplicates.
213 //
214 // Warning: the span is only valid until the next call to [].
215 // This is not const because it lazily merges lists.
216 absl::Span<const V> operator[](K key) {
217 if (key >= rows_.size()) return {};
218 CHECK(!merged_[key]);
219
220 tmp_result_.clear();
221 K previous(-1);
222 while (key >= 0) {
223 int new_size = 0;
224 absl::Span<V> data = rows_[key];
225 for (const V v : data) {
226 if (marked_[v]) continue;
227 marked_.Set(v);
228 tmp_result_.push_back(v);
229 data[new_size++] = v;
230 }
231 rows_.Shrink(key, new_size);
232
233 if (new_size == 0 && previous >= 0) {
234 // Bypass on next scan and keep previous.
235 next_[InternalKey(previous)] = next_[InternalKey(key)];
236 } else {
237 previous = key;
238 }
239
240 // Follow the linked list.
241 key = next_[InternalKey(key)];
242 }
243
244 // Sparse clear marked.
245 for (const V v : tmp_result_) marked_.Clear(v);
246 return tmp_result_;
247 }
248
249 // Merge this[key] into this[representative].
250 // If key == representative, this does nothing.
251 //
252 // And otherwise key should never be accessed anymore.
253 void MergeInto(K to_merge, K representative) {
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);
261
262 // Find the end of the representative list to happen to_merge there.
263 //
264 // TODO(user): this might be slow ? It can be made O(1) if we keep the index
265 // of the end of each linked list. But in practice we currently loop over
266 // the list right after, so the complexity is dominated anyway.
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);
271 }
272 next_[InternalKey(last_list)] = to_merge;
273 }
274
275 void ClearList(K key) {
276 next_[InternalKey(key)] = -1;
277 rows_.Shrink(key, 0);
278 }
279
280 private:
281 // Convert int and StrongInt to normal int.
282 int InternalKey(K key) const;
283
284 // Used by operator[] who return a Span<> into tmp_result_.
285 // The bitset is used to remove duplicates when merging lists.
286 std::vector<V> tmp_result_;
287 Bitset64<V> marked_;
288 Bitset64<K> merged_;
289
290 // Each "row" contains a set of values (we lazily remove duplicate).
292
293 // Disjoint linked lists of rows.
294 // Basically we starts at rows_[key] and continue at rows_[next_[key]].
295 // -1 means no next.
296 std::vector<K> next_;
297};
298
299// We often have a vector with fixed capacity reserved outside the hot loops.
300// Using this class instead save the capacity but most importantly link a lot
301// less code for the push_back() calls which allow more inlining.
302//
303// TODO(user): Add more functions and unit-test.
304template <typename T>
306 public:
308 explicit FixedCapacityVector(absl::Span<const T> span) {
309 size_ = span.size();
310 data_.reset(new T[size_]);
311 std::copy(span.begin(), span.end(), data_.get());
312 }
313
314 void ClearAndReserve(size_t size) {
315 size_ = 0;
316 data_.reset(new T[size]);
317 }
318
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; }
324
325 T operator[](int i) const { return data_[i]; }
326 T& operator[](int i) { return data_[i]; }
327
328 T back() const { return data_[size_ - 1]; }
329 T& back() { return data_[size_ - 1]; }
330
331 void clear() { size_ = 0; }
332 void resize(size_t size) { size_ = size; }
333 void pop_back() { --size_; }
334 void push_back(T t) { data_[size_++] = t; }
335
336 private:
337 int size_ = 0;
338 std::unique_ptr<T[]> data_ = nullptr;
339};
340
341// This is used to format our table first row entry.
342inline std::string FormatName(absl::string_view name) {
343 return absl::StrCat("'", name, "':");
344}
345
346// Display tabular data by auto-computing cell width. Note that we right align
347// everything but the first row/col that is assumed to be the table name and is
348// left aligned.
349std::string FormatTable(std::vector<std::vector<std::string>>& table,
350 int spacing = 2);
351
352// Returns a in [0, m) such that a * x = 1 modulo m.
353// If gcd(x, m) != 1, there is no inverse, and it returns 0.
354//
355// This DCHECK that x is in [0, m).
356// This is integer overflow safe.
357//
358// Note(user): I didn't find this in a easily usable standard library.
359int64_t ModularInverse(int64_t x, int64_t m);
360
361// Just returns x % m but with a result always in [0, m).
362int64_t PositiveMod(int64_t x, int64_t m);
363
364// If we know that X * coeff % mod = rhs % mod, this returns c such that
365// PositiveMod(X, mod) = c.
366//
367// This requires coeff != 0, mod !=0 and gcd(coeff, mod) == 1.
368// The result will be in [0, mod) but there is no other condition on the sign or
369// magnitude of a and b.
370//
371// This is overflow safe, and when rhs == 0 or abs(mod) == 1, it returns 0.
372int64_t ProductWithModularInverse(int64_t coeff, int64_t mod, int64_t rhs);
373
374// Returns true if the equation a * X + b * Y = cte has some integer solutions.
375// For now, we check that a and b are different from 0 and from int64_t min.
376//
377// There is actually always a solution if cte % gcd(|a|, |b|) == 0. And because
378// a, b and cte fit on an int64_t, if there is a solution, there is one with X
379// and Y fitting on an int64_t.
380//
381// We will divide everything by gcd(a, b) first, so it is why we take reference
382// and the equation can change.
383//
384// If there are solutions, we return one of them (x0, y0).
385// From any such solution, the set of all solutions is given for Z integer by:
386// X = x0 + b * Z;
387// Y = y0 - a * Z;
388//
389// Given a domain for X and Y, it is possible to compute the "exact" domain of Z
390// with our Domain functions. Note however that this will only compute solution
391// where both x-x0 and y-y0 do fit on an int64_t:
392// DomainOf(x).SubtractionWith(x0).InverseMultiplicationBy(b).IntersectionWith(
393// DomainOf(y).SubtractionWith(y0).InverseMultiplicationBy(-a))
394bool SolveDiophantineEquationOfSizeTwo(int64_t& a, int64_t& b, int64_t& cte,
395 int64_t& x0, int64_t& y0);
396
397// Returns true if the equation a * X + b * Y = cte has some integer solutions
398// in the domain of X and Y.
400 const Domain& y, int64_t b,
401 int64_t cte);
402
403// The argument must be non-negative.
404int64_t FloorSquareRoot(int64_t a);
405int64_t CeilSquareRoot(int64_t a);
406
407// Converts a double to int64_t and cap large magnitudes at kint64min/max.
408// We also arbitrarily returns 0 for NaNs.
409//
410// Note(user): This is similar to SaturatingFloatToInt(), but we use our own
411// since we need to open source it and the code is simple enough.
412int64_t SafeDoubleToInt64(double value);
413
414// Returns the multiple of base closest to value. If there is a tie, we return
415// the one closest to zero. This way we have ClosestMultiple(x) =
416// -ClosestMultiple(-x) which is important for how this is used.
417int64_t ClosestMultiple(int64_t value, int64_t base);
418
419// Assuming n "literal" in [0, n), and a graph such that graph[i] list the
420// literal in [0, n) implied to false when the literal with index i is true,
421// this returns an heuristic decomposition of the literals into disjoint at most
422// ones.
423//
424// Note(user): Symmetrize the matrix if not already, maybe rephrase in term
425// of undirected graph, and clique decomposition.
426std::vector<absl::Span<int>> AtMostOneDecomposition(
427 const std::vector<std::vector<int>>& graph, absl::BitGenRef random,
428 std::vector<int>* buffer);
429
430// Given a linear equation "sum coeff_i * X_i <= rhs. We can rewrite it using
431// ClosestMultiple() as "base * new_terms + error <= rhs" where error can be
432// bounded using the provided bounds on each variables. This will return true if
433// the error can be ignored and this equation is completely equivalent to
434// new_terms <= new_rhs.
435//
436// This is useful for cases like 9'999 X + 10'0001 Y <= 155'000 where we have
437// weird coefficient (maybe due to scaling). With a base of 10K, this is
438// equivalent to X + Y <= 15.
439//
440// Preconditions: All coeffs are assumed to be positive. You can easily negate
441// all the negative coeffs and corresponding bounds before calling this.
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,
445 int64_t* new_rhs);
446
447// The model "singleton" random engine used in the solver.
448//
449// In test, we usually set use_absl_random() so that the sequence is changed at
450// each invocation. This way, clients do not really on the wrong assumption that
451// a particular optimal solution will be returned if they are many equivalent
452// ones.
453class ModelRandomGenerator : public absl::BitGenRef {
454 public:
455 // We seed the strategy at creation only. This should be enough for our use
456 // case since the SatParameters is set first before the solver is created. We
457 // also never really need to change the seed afterwards, it is just used to
458 // diversify solves with identical parameters on different Model objects.
459 explicit ModelRandomGenerator(const SatParameters& params)
460 : absl::BitGenRef(deterministic_random_) {
461 deterministic_random_.seed(params.random_seed());
462 if (params.use_absl_random()) {
463 absl_random_ = absl::BitGen(absl::SeedSeq({params.random_seed()}));
464 absl::BitGenRef::operator=(absl::BitGenRef(absl_random_));
465 }
466 }
467
468 explicit ModelRandomGenerator(const absl::BitGenRef& bit_gen_ref)
469 : absl::BitGenRef(deterministic_random_) {
470 absl::BitGenRef::operator=(bit_gen_ref);
471 }
472
474 : ModelRandomGenerator(*model->GetOrCreate<SatParameters>()) {}
475
476 // This is just used to display ABSL_RANDOM_SALT_OVERRIDE in the log so that
477 // it is possible to reproduce a failure more easily while looking at a solver
478 // log.
479 //
480 // TODO(user): I didn't find a cleaner way to log this.
481 void LogSalt() const {}
482
483 private:
484 random_engine_t deterministic_random_;
485 absl::BitGen absl_random_;
486};
487
488// The model "singleton" shared time limit.
490 public:
492 : SharedTimeLimit(model->GetOrCreate<TimeLimit>()) {}
493};
494
495// Randomizes the decision heuristic of the given SatParameters.
496void RandomizeDecisionHeuristic(absl::BitGenRef random,
497 SatParameters* parameters);
498
499// This is equivalent of
500// absl::discrete_distribution<std::size_t>(input.begin(), input.end())(random)
501// but does no allocations. It is a lot faster when you need to pick just one
502// elements from a distribution for instance.
503int WeightedPick(absl::Span<const double> input, absl::BitGenRef random);
504
505// Context: this function is not really generic, but required to be unit-tested.
506// It is used in a clause minimization algorithm when we try to detect if any of
507// the clause literals can be propagated by a subset of the other literal being
508// false. For that, we want to enqueue in the solver all the subset of size n-1.
509//
510// This moves one of the unprocessed literal from literals to the last position.
511// The function tries to do that while preserving the longest possible prefix of
512// literals "amortized" through the calls assuming that we want to move each
513// literal to the last position once.
514//
515// For a vector of size n, if we want to call this n times so that each literal
516// is last at least once, the sum of the size of the changed suffixes will be
517// O(n log n). If we were to use a simpler algorithm (like moving the last
518// unprocessed literal to the last position), this sum would be O(n^2).
519//
520// Returns the size of the common prefix of literals before and after the move,
521// or -1 if all the literals are already processed. The argument
522// relevant_prefix_size is used as a hint when keeping more that this prefix
523// size do not matter. The returned value will always be lower or equal to
524// relevant_prefix_size.
525int MoveOneUnprocessedLiteralLast(
526 const absl::btree_set<LiteralIndex>& processed, int relevant_prefix_size,
527 std::vector<Literal>* literals);
528
529// Selects k out of n such that the sum of pairwise distances is maximal.
530// distances[i * n + j] = distances[j * n + j] = distances between i and j.
531//
532// In the special case k >= n - 1, we use a faster algo.
533//
534// Otherwise, this shall only be called with small n, we CHECK_LE(n, 25).
535// Complexity is in O(2 ^ n + n_choose_k * n). Memory is in O(2 ^ n).
536//
537// In case of tie, this will choose deterministically, so one can randomize the
538// order first to get a random subset. The returned subset will always be
539// sorted.
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);
544
545// HEURISTIC. Try to "cut" the list into roughly sqrt(size) equally sized parts.
546// We try to keep the same coefficients in the same buckets.
547// The list is assumed to be sorted.
548// Return a list of pair (start, size) for each part.
549//
550// Context: Currently when we load long linear constraint (more than 100 terms),
551// to keep the propagation and reason shorts, we always split them by adding
552// intermediate variable corresponding to the sum of a subpart. We just do that
553// in the CP-engine, not in the LP though. using sub-part with the same coeff
554// seems to help and kind of make sense.
555//
556// TODO(user): This sounds sub-optimal, we should also try to add variables for
557// common part between constraints, like what some of the presolve is doing.
558std::vector<std::pair<int, int>> HeuristicallySplitLongLinear(
559 absl::Span<const int64_t> coeffs);
560
561// Simple DP to compute the maximum reachable value of a "subset sum" under
562// a given bound (inclusive). Note that we abort as soon as the computation
563// become too important.
564//
565// Precondition: Both bound and all added values must be >= 0.
567 public:
568 MaxBoundedSubsetSum() : max_complexity_per_add_(/*default=*/50) { Reset(0); }
569 explicit MaxBoundedSubsetSum(int64_t bound, int max_complexity_per_add = 50)
570 : max_complexity_per_add_(max_complexity_per_add) {
571 Reset(bound);
572 }
573
574 // Resets to an empty set of values.
575 // We look for the maximum sum <= bound.
576 void Reset(int64_t bound);
577
578 // Add a value to the base set for which subset sums will be taken.
579 void Add(int64_t value);
580
581 // Add a choice of values to the base set for which subset sums will be taken.
582 // Note that even if this doesn't include zero, not taking any choices will
583 // also be an option.
584 void AddChoices(absl::Span<const int64_t> choices);
585
586 // Adds [0, coeff, 2 * coeff, ... max_value * coeff].
587 void AddMultiples(int64_t coeff, int64_t max_value);
588
589 // Returns an upper bound (inclusive) on the maximum sum <= bound_.
590 // This might return bound_ if we aborted the computation.
591 int64_t CurrentMax() const { return current_max_; }
592
593 int64_t Bound() const { return bound_; }
594
595 private:
596 // This assumes filtered values.
597 void AddChoicesInternal(absl::Span<const int64_t> values);
598
599 // Max_complexity we are willing to pay on each Add() call.
600 const int max_complexity_per_add_;
601 int64_t gcd_;
602 int64_t bound_;
603 int64_t current_max_;
604 std::vector<int64_t> sums_;
605 std::vector<bool> expanded_sums_;
606 std::vector<int64_t> filtered_values_;
607};
608
609// Simple DP to keep the set of the first n reachable value (n > 1).
610//
611// TODO(user): Maybe modulo some prime number we can keep more info.
612// TODO(user): Another common case is a bunch of really small values and larger
613// ones, so we could bound the sum of the small values and keep the first few
614// reachable by the big ones. This is similar to some presolve transformations.
615template <int n>
617 public:
619 : reachable_(new int64_t[n]), new_reachable_(new int64_t[n]) {
620 Reset();
621 }
622
623 void Reset() {
624 for (int i = 0; i < n; ++i) {
625 reachable_[i] = std::numeric_limits<int64_t>::max();
626 }
627 reachable_[0] = 0;
628 new_reachable_[0] = 0;
629 }
630
631 // We assume the given positive value can be added as many time as wanted.
632 //
633 // TODO(user): Implement Add() with an upper bound on the multiplicity.
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;
638
639 // We copy from reachable_[i] to new_reachable_[j].
640 // The position zero is already copied.
641 int i = 1;
642 int j = 1;
643 int64_t* new_reachable = new_reachable_.get();
644 for (int base = 0; j < n && base < n; ++base) {
645 const int64_t candidate = CapAdd(new_reachable[base], positive_value);
646 while (j < n && i < n && reachable[i] < candidate) {
647 new_reachable[j++] = reachable[i++];
648 }
649 if (j < n) {
650 // Eliminate duplicates.
651 while (i < n && reachable[i] == candidate) i++;
652
653 // insert candidate in its final place.
654 new_reachable[j++] = candidate;
655 }
656 }
657 std::swap(reachable_, new_reachable_);
658 }
659
660 // Returns true iff sum might be expressible as a weighted sum of the added
661 // value. Any sum >= LastValue() is always considered potentially reachable.
662 bool MightBeReachable(int64_t sum) const {
663 if (sum >= reachable_[n - 1]) return true;
664 return std::binary_search(&reachable_[0], &reachable_[0] + n, sum);
665 }
666
667 int64_t LastValue() const { return reachable_[n - 1]; }
668
669 absl::Span<const int64_t> reachable() {
670 return absl::MakeSpan(reachable_.get(), n);
671 }
672
673 private:
674 std::unique_ptr<int64_t[]> reachable_;
675 std::unique_ptr<int64_t[]> new_reachable_;
676};
677
678// Yet another variant of FirstFewValues or MaxBoundedSubsetSum.
680 public:
681 // Computes all the possible subset sums in [0, maximum_sum].
682 // Returns them sorted. All elements must be non-negative.
683 //
684 // If abort_if_maximum_reached is true, we might not return all possible
685 // subset sums as we stop the exploration as soon as a subset sum is equal to
686 // maximum_sum. When this happen, we guarantee that the last element returned
687 // will be maximum_sum though.
688 //
689 // Worst case complexity is in O(2^num_elements) if maximum_sum is large or
690 // O(maximum_sum * num_elements) if that is lower.
691 //
692 // TODO(user): We could optimize even further the case of a small maximum_sum.
693 absl::Span<const int64_t> Compute(absl::Span<const int64_t> elements,
694 int64_t maximum_sum,
695 bool abort_if_maximum_reached = false);
696
697 // Returns the possible subset sums sorted.
698 absl::Span<const int64_t> SortedSums() const { return sums_; }
699
700 private:
701 std::vector<int64_t> sums_;
702 std::vector<int64_t> new_sums_;
703};
704
705// Similar to MaxBoundedSubsetSum() above but use a different algo.
707 public:
708 // If we pack the given elements into a bin of size 'bin_size', returns
709 // largest possible sum that can be reached.
710 //
711 // This implementation allow to solve this in O(2^(num_elements/2)) allowing
712 // to go easily to 30 or 40 elements. If bin_size is small, complexity is more
713 // like O(num_element * bin_size).
714 int64_t MaxSubsetSum(absl::Span<const int64_t> elements, int64_t bin_size);
715
716 // Returns an estimate of how many elementary operations
717 // MaxSubsetSum() is going to take.
718 double ComplexityEstimate(int num_elements, int64_t bin_size);
719
720 private:
721 // We use a class just to reuse the memory and not allocate it on each query.
722 SortedSubsetSums sums_a_;
723 SortedSubsetSums sums_b_;
724};
725
726// Use Dynamic programming to solve a single knapsack. This is used by the
727// presolver to simplify variables appearing in a single linear constraint.
728//
729// Complexity is the best of
730// - O(num_variables * num_relevant_values ^ 2) or
731// - O(num_variables * num_relevant_values * max_domain_size).
733 public:
734 // Solves the problem:
735 // - minimize sum costs * X[i]
736 // - subject to sum coeffs[i] * X[i] \in rhs, with X[i] \in Domain(i).
737 //
738 // Returns:
739 // - (solved = false) if complexity is too high.
740 // - (solved = true, infeasible = true) if proven infeasible.
741 // - (solved = true, infeasible = false, solution) otherwise.
742 struct Result {
743 bool solved = false;
744 bool infeasible = false;
745 std::vector<int64_t> solution;
746 };
747 Result Solve(absl::Span<const Domain> domains,
748 absl::Span<const int64_t> coeffs,
749 absl::Span<const int64_t> costs, const Domain& rhs);
750
751 private:
752 Result InternalSolve(int64_t num_values, const Domain& rhs);
753
754 // Canonicalized version.
755 std::vector<Domain> domains_;
756 std::vector<int64_t> coeffs_;
757 std::vector<int64_t> costs_;
758
759 // We only need to keep one state with the same activity.
760 struct State {
761 int64_t cost = std::numeric_limits<int64_t>::max();
762 int64_t value = 0;
763 };
764 std::vector<std::vector<State>> var_activity_states_;
765};
766
767// Manages incremental averages.
769 public:
770 // Initializes the average with 'initial_average' and number of records to 0.
771 explicit IncrementalAverage(double initial_average)
772 : average_(initial_average) {}
774
775 // Sets the number of records to 0 and average to 'reset_value'.
776 void Reset(double reset_value);
777
778 double CurrentAverage() const { return average_; }
779 int64_t NumRecords() const { return num_records_; }
780
781 void AddData(double new_record);
782
783 private:
784 double average_ = 0.0;
785 int64_t num_records_ = 0;
786};
787
788// Manages exponential moving averages defined as
789// new_average = decaying_factor * old_average
790// + (1 - decaying_factor) * new_record.
791// where 0 < decaying_factor < 1.
793 public:
794 explicit ExponentialMovingAverage(double decaying_factor)
795 : decaying_factor_(decaying_factor) {
796 DCHECK_GE(decaying_factor, 0.0);
797 DCHECK_LE(decaying_factor, 1.0);
798 }
799
800 // Returns exponential moving average for all the added data so far.
801 double CurrentAverage() const { return average_; }
802
803 // Returns the total number of added records so far.
804 int64_t NumRecords() const { return num_records_; }
805
806 void AddData(double new_record);
807
808 private:
809 double average_ = 0.0;
810 int64_t num_records_ = 0;
811 const double decaying_factor_;
812};
813
814// Utility to calculate percentile (First variant) for limited number of
815// records. Reference: https://en.wikipedia.org/wiki/Percentile
816//
817// After the vector is sorted, we assume that the element with index i
818// correspond to the percentile 100*(i+0.5)/size. For percentiles before the
819// first element (resp. after the last one) we return the first element (resp.
820// the last). And otherwise we do a linear interpolation between the two element
821// around the asked percentile.
823 public:
824 explicit Percentile(int record_limit) : record_limit_(record_limit) {}
825
826 void AddRecord(double record);
827
828 // Returns number of stored records.
829 int64_t NumRecords() const { return records_.size(); }
830
831 // Note that this runs in O(n) for n records.
832 double GetPercentile(double percent);
833
834 private:
835 std::deque<double> records_;
836 const int record_limit_;
837};
838
839// Keep the top n elements from a stream of elements.
840//
841// TODO(user): We could use gtl::TopN when/if it gets open sourced. Note that
842// we might be slighlty faster here since we use an indirection and don't move
843// the Element class around as much.
844template <typename Element, typename Score>
845class TopN {
846 public:
847 explicit TopN(int n) : n_(n) {}
848
849 void Clear() {
850 heap_.clear();
851 elements_.clear();
852 }
853
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_) {
860 // TODO(user): We could delay that on the n + 1 push.
861 std::make_heap(heap_.begin(), heap_.end());
862 }
863 } else {
864 if (score <= heap_.front().score) return;
865 const int index_to_replace = heap_.front().index;
866 elements_[index_to_replace] = std::move(e);
867
868 // If needed, we could be faster here with an update operation.
869 std::pop_heap(heap_.begin(), heap_.end());
870 heap_.back() = {index_to_replace, score};
871 std::push_heap(heap_.begin(), heap_.end());
872 }
873 }
874
875 bool empty() const { return elements_.empty(); }
876
877 const std::vector<Element>& UnorderedElements() const { return elements_; }
878 std::vector<Element>* MutableUnorderedElements() { return &elements_; }
879
880 private:
881 const int n_;
882
883 // We keep a heap of the n highest score.
884 struct HeapElement {
885 int index; // in elements_;
886 Score score;
887 bool operator<(const HeapElement& other) const {
888 return score > other.score;
889 }
890 };
891 std::vector<HeapElement> heap_;
892 std::vector<Element> elements_;
893};
894
895// Returns true iff subset is strictly included in superset.
896// This assumes that superset has no duplicates (otherwise it is wrong).
898 int subset_size,
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) {
903 if (!in_subset[l]) {
904 --budget;
905 if (budget < 0) return false;
906 }
907 }
908 return true;
909}
910
911// ============================================================================
912// Implementation.
913// ============================================================================
914
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();
919 }
920 if (value <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
921 return std::numeric_limits<int64_t>::min();
922 }
923 return static_cast<int64_t>(value);
924}
925
926// Tells whether a int128 can be casted to a int64_t that can be negated.
927inline bool IsNegatableInt64(absl::int128 x) {
928 return x <= absl::int128(std::numeric_limits<int64_t>::max()) &&
929 x > absl::int128(std::numeric_limits<int64_t>::min());
930}
931
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());
938 return index;
939}
940
941template <typename K, typename V>
942inline void CompactVectorVector<K, V>::AppendToLastVector(const V& value) {
943 sizes_.back()++;
944 buffer_.push_back(value);
945}
946
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());
952}
953
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());
961}
962
963template <typename K, typename V>
964template <typename L>
966 const std::vector<L>& wrapped_values) {
967 const int index = size();
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());
972 }
973 return index;
974}
975
976// We need to support both StrongType and normal int.
977template <typename K, typename V>
978inline int CompactVectorVector<K, V>::InternalKey(K key) {
979 if constexpr (std::is_same_v<K, int>) {
980 return key;
981 } else {
982 return key.value();
983 }
984}
985
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;
991}
992
993template <typename K, typename V>
994inline absl::Span<const V> CompactVectorVector<K, V>::operator[](K key) const {
995 DCHECK_GE(key, 0);
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};
1002}
1003
1004template <typename K, typename V>
1005inline absl::Span<V> CompactVectorVector<K, V>::operator[](K key) {
1006 DCHECK_GE(key, 0);
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);
1013}
1014
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];
1021 }
1022 return result;
1023}
1024
1025template <typename K, typename V>
1026inline void CompactVectorVector<K, V>::clear() {
1027 starts_.clear();
1028 sizes_.clear();
1029 buffer_.clear();
1030}
1031
1032template <typename K, typename V>
1033inline size_t CompactVectorVector<K, V>::size() const {
1034 return starts_.size();
1036
1037template <typename K, typename V>
1038inline bool CompactVectorVector<K, V>::empty() const {
1039 return starts_.empty();
1041
1042template <typename K, typename V>
1043template <typename Keys, typename Values>
1045 Keys keys, Values values, int minimum_num_nodes) {
1046 // Compute maximum index.
1047 int max_key = minimum_num_nodes;
1048 for (const K key : keys) {
1049 max_key = std::max(max_key, InternalKey(key) + 1);
1050 }
1051
1052 if (keys.empty()) {
1053 clear();
1054 sizes_.assign(minimum_num_nodes, 0);
1055 starts_.assign(minimum_num_nodes, 0);
1056 return;
1057 }
1058
1059 // Compute sizes_;
1060 sizes_.assign(max_key, 0);
1061 for (const K key : keys) {
1062 sizes_[InternalKey(key)]++;
1063 }
1064
1065 // Compute starts_;
1066 starts_.assign(max_key, 0);
1067 for (int k = 1; k < max_key; ++k) {
1068 starts_[k] = starts_[k - 1] + sizes_[k - 1];
1069 }
1070
1071 // Copy data and uses starts as temporary indices.
1072 buffer_.resize(keys.size());
1073 for (int i = 0; i < keys.size(); ++i) {
1074 buffer_[starts_[InternalKey(keys[i])]++] = values[i];
1075 }
1076
1077 // Restore starts_.
1078 for (int k = max_key - 1; k > 0; --k) {
1079 starts_[k] = starts_[k - 1];
1080 }
1081 starts_[0] = 0;
1082}
1083
1084// Similar to ResetFromFlatMapping().
1085template <typename K, typename V>
1086template <typename Collection>
1087inline void CompactVectorVector<K, V>::ResetFromPairs(const Collection& pairs,
1088 int minimum_num_nodes) {
1089 // Compute maximum index.
1090 int max_key = minimum_num_nodes;
1091 for (const auto& [key, _] : pairs) {
1092 max_key = std::max(max_key, InternalKey(key) + 1);
1093 }
1094
1095 if (pairs.empty()) {
1096 clear();
1097 sizes_.assign(minimum_num_nodes, 0);
1098 starts_.assign(minimum_num_nodes, 0);
1099 return;
1100 }
1101
1102 // Compute sizes_;
1103 sizes_.assign(max_key, 0);
1104 for (const auto& [key, _] : pairs) {
1105 sizes_[InternalKey(key)]++;
1106 }
1107
1108 // Compute starts_;
1109 starts_.assign(max_key, 0);
1110 for (int k = 1; k < max_key; ++k) {
1111 starts_[k] = starts_[k - 1] + sizes_[k - 1];
1112 }
1113
1114 // Copy data and uses starts as temporary indices.
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;
1119 }
1120
1121 // Restore starts_.
1122 for (int k = max_key - 1; k > 0; --k) {
1123 starts_[k] = starts_[k - 1];
1124 }
1125 starts_[0] = 0;
1126}
1127
1128// Similar to ResetFromFlatMapping().
1129template <typename K, typename V>
1130template <typename ValueMapper, typename Container>
1131void CompactVectorVector<K, V>::ResetFromTransposeMap(const Container& other,
1132 int min_transpose_size) {
1133 ValueMapper mapper;
1134 if (other.size() == 0) {
1135 clear();
1136 if (min_transpose_size > 0) {
1137 starts_.assign(min_transpose_size, 0);
1138 sizes_.assign(min_transpose_size, 0);
1139 }
1140 return;
1141 }
1142
1143 // Compute maximum index.
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);
1150 }
1151 }
1152
1153 // Compute sizes_;
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))]++;
1158 }
1159 }
1160
1161 // Compute starts_;
1162 starts_.assign(max_key, 0);
1163 for (int k = 1; k < max_key; ++k) {
1164 starts_[k] = starts_[k - 1] + sizes_[k - 1];
1165 }
1166
1167 // Copy data and uses starts as temporary indices.
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;
1172 }
1173 }
1174
1175 // Restore starts_.
1176 for (int k = max_key - 1; k > 0; --k) {
1177 starts_[k] = starts_[k - 1];
1178 }
1179 starts_[0] = 0;
1180}
1181
1182// Similar to ResetFromFlatMapping().
1183template <typename K, typename V>
1184inline void CompactVectorVector<K, V>::ResetFromTranspose(
1185 const CompactVectorVector<V, K>& other, int min_transpose_size) {
1186 struct NoOpMapper {
1187 K operator()(K k) const { return k; }
1188 };
1189 ResetFromTransposeMap<NoOpMapper, CompactVectorVector<V, K>>(
1190 other, min_transpose_size);
1191}
1192
1193// A class to generate all possible topological sorting of a dag.
1194//
1195// If the graph has no edges, it will generate all possible permutations.
1196//
1197// If the graph has edges, it will generate all possible permutations of the dag
1198// that are a topological sorting of the graph.
1199//
1200// Typical usage:
1201//
1202// DagTopologicalSortIterator dag_topological_sort(5);
1203//
1204// dag_topological_sort.AddArc(0, 1);
1205// dag_topological_sort.AddArc(1, 2);
1206// dag_topological_sort.AddArc(3, 4);
1207//
1208// for (const auto& permutation : dag_topological_sort) {
1209// // Do something with each permutation.
1210// }
1211//
1212// Note: to test if there are cycles, it is enough to check if at least one
1213// iteration occurred in the above loop.
1214//
1215// Note 2: adding an arc during an iteration is not supported and the behavior
1216// is undefined.
1217class DagTopologicalSortIterator {
1218 public:
1220
1221 // Graph maps indices to their children. Any children must exist.
1222 explicit DagTopologicalSortIterator(int size)
1223 : graph_(size, std::vector<int>{}) {}
1225 // An iterator class to generate all possible topological sorting of a dag.
1226 //
1227 // If the graph has no edges, it will generate all possible permutations.
1228 //
1229 // If the graph has edges, it will generate all possible permutations of the
1230 // dag that are a topological sorting of the graph.
1231 //
1232 // The class maintains 5 fields:
1233 // - graph_: a vector of vectors, where graph_[i] contains the list of
1234 // elements that are adjacent to element i. This is not owned.
1235 // - size_: the size of the graph.
1236 // - missing_parent_numbers_: a vector of integers, where
1237 // missing_parent_numbers_[i] is the number of parents of element i that
1238 // are not yet in permutation_. It is always 0 except during the
1239 // execution of operator++().
1240 // - permutation_: a vector of integers, that is a topological sorting of the
1241 // graph except during the execution of operator++().
1242 // - element_original_position_: a vector of integers, where
1243 // element_original_position_[i] is the original position of element i in
1244 // the permutation_. See the algorithm below for more details.
1245
1246 class Iterator {
1247 friend class DagTopologicalSortIterator;
1249 public:
1250 using iterator_category = std::input_iterator_tag;
1251 using value_type = const std::vector<int>;
1252 using difference_type = ptrdiff_t;
1256 Iterator& operator++();
1257
1258 friend bool operator==(const Iterator& a, const Iterator& b) {
1259 return &a.graph_ == &b.graph_ && a.ordering_index_ == b.ordering_index_;
1261
1262 friend bool operator!=(const Iterator& a, const Iterator& b) {
1263 return !(a == b);
1265
1266 reference operator*() const { return permutation_; }
1267
1268 pointer operator->() const { return &permutation_; }
1269
1270 private:
1271 // End iterator.
1272 explicit Iterator(const std::vector<std::vector<int>>& graph
1273 ABSL_ATTRIBUTE_LIFETIME_BOUND,
1274 bool)
1275 : graph_(graph), ordering_index_(-1) {}
1276
1277 // Begin iterator.
1278 explicit Iterator(const std::vector<std::vector<int>>& graph
1279 ABSL_ATTRIBUTE_LIFETIME_BOUND);
1280
1281 // Unset the element at pos.
1282 void Unset(int pos);
1283
1284 // Set the element at pos to the element at k.
1285 void Set(int pos, int k);
1286
1287 // Graph maps indices to their children. Children must be in [0, size_).
1288 const std::vector<std::vector<int>>& graph_;
1289 // Number of elements in graph_.
1290 int size_;
1291 // For each element in graph_, the number of parents it has that are not yet
1292 // in permutation_. In particular, it is always 0 outside of operator++().
1293 std::vector<int> missing_parent_numbers_;
1294 // The current permutation. It is ensured to be a topological sorting of the
1295 // graph outside of operator++().
1296 std::vector<int> permutation_;
1297 // Keeps track of the original position of the element in permutation_[i].
1298 // See the comment above the class for the detailed algorithm.
1299 std::vector<int> element_original_position_;
1300
1301 // Index of the current ordering. Used to compare iterators. It is -1 if the
1302 // end has been reached.
1303 int64_t ordering_index_;
1304 };
1305
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);
1312
1313 void Reset(int size) { graph_.assign(size, {}); }
1314
1315 // Must be called before iteration starts or between iterations.
1316 void AddArc(int from, int to) {
1317 DCHECK_GE(from, 0);
1318 DCHECK_LT(from, graph_.size());
1319 DCHECK_GE(to, 0);
1320 DCHECK_LT(to, graph_.size());
1321 graph_[from].push_back(to);
1322 }
1323
1324 private:
1325 // Graph maps indices to their children. Children must be in [0, size_).
1326 std::vector<std::vector<int>> graph_;
1327};
1328
1329// To describe the algorithm in operator++() and constructor(), we consider the
1330// following invariant, called Invariant(pos) for a position pos in [0, size_):
1331// 1. permutations_[0], ..., permutations_[pos] form a prefix of a topological
1332// ordering of the graph;
1333// 2. permutations_[pos + 1], ..., permutations_.back() are all other elements
1334// that have all their parents in permutations_[0], ..., permutations_[pos],
1335// ordered lexicographically by the index of their last parent in
1336// permutations_[0], ... permutations_[pos] and then by their index in the
1337// graph;
1338// 3. missing_parent_numbers_[i] is the number of parents of element i that are
1339// not in {permutations_[0], ..., permutations_[pos]}.
1340// 4. element_original_position_[i] is the original position of element i of
1341// the permutation following the order described in 2. In particular,
1342// element_original_position_[i] = i for i > pos.
1343// Set and Unset maintain these invariants.
1344
1345// Precondition: Invariant(size_ - 1) holds.
1346// Postcondition: Invariant(size_ - 1) holds if the end of the iteration is not
1347// reached.
1348inline DagTopologicalSortIterator::Iterator&
1349DagTopologicalSortIterator::Iterator::operator++() {
1350 CHECK_GE(ordering_index_, 0) << "Iteration past end";
1351 if (size_ == 0) {
1352 // Special case: empty graph, only one topological ordering is
1353 // generated.
1354 ordering_index_ = -1;
1355 return *this;
1356 }
1357
1358 Unset(size_ - 1);
1359 for (int pos = size_ - 2; pos >= 0; --pos) {
1360 // Invariant(pos) holds.
1361 // Increasing logic: once permutation_[pos] has been put back to its
1362 // original position by Unset(pos), elements permutations_[pos], ...,
1363 // permutations_.back() are in their original ordering, in particular in
1364 // the same order as last time the iteration on permutation_[pos] occurred
1365 // (according to Invariant(pos).2, these are exactly the elements that have
1366 // to be tried at pos). All possibilities in permutations_[pos], ...,
1367 // permutations_[element_original_position_[pos]] have been run through.
1368 // The next to test is permutations_[element_original_position_[pos] + 1].
1369 const int k = element_original_position_[pos] + 1;
1370 Unset(pos);
1371 // Invariant(pos - 1) holds.
1372
1373 // No more elements to iterate on at position pos. Go backwards one position
1374 // to increase that one.
1375 if (k == permutation_.size()) continue;
1376 Set(pos, k);
1377 // Invariant(pos) holds.
1378 for (++pos; pos < size_; ++pos) {
1379 // Invariant(pos - 1) holds.
1380 // According to Invariant(pos - 1).2, if pos >= permutation_.size(), there
1381 // are no more elements we can add to the permutation which means that we
1382 // detected a cycle. It would be a bug as we would have detected it in
1383 // the constructor.
1384 CHECK_LT(pos, permutation_.size())
1385 << "Unexpected cycle detected during iteration";
1386 // According to Invariant(pos - 1).2, elements that can be used at pos are
1387 // permutations_[pos], ..., permutations_.back(). Starts the iteration at
1388 // permutations_[pos].
1389 Set(pos, pos);
1390 // Invariant(pos) holds.
1391 }
1392 // Invariant(size_ - 1) holds.
1393 ++ordering_index_;
1394 return *this;
1395 }
1396 ordering_index_ = -1;
1397 return *this;
1398}
1399
1400inline DagTopologicalSortIterator::Iterator::Iterator(
1401 const std::vector<std::vector<int>>& graph)
1402 : graph_(graph),
1403 size_(graph.size()),
1404 missing_parent_numbers_(size_, 0),
1405 element_original_position_(size_, 0),
1406 ordering_index_(0) {
1407 if (size_ == 0) {
1408 // Special case: empty graph, only one topological ordering is generated,
1409 // which is the "empty" ordering.
1410 return;
1411 }
1412
1413 for (const auto& children : graph_) {
1414 for (const int child : children) {
1415 missing_parent_numbers_[child]++;
1416 }
1417 }
1418
1419 for (int i = 0; i < size_; ++i) {
1420 if (missing_parent_numbers_[i] == 0) {
1421 permutation_.push_back(i);
1422 }
1423 }
1424 for (int pos = 0; pos < size_; ++pos) {
1425 // Invariant(pos - 1) holds.
1426 // According to Invariant(pos - 1).2, if pos >= permutation_.size(), there
1427 // are no more elements we can add to the permutation.
1428 if (pos >= permutation_.size()) {
1429 ordering_index_ = -1;
1430 return;
1431 }
1432 // According to Invariant(pos - 1).2, elements that can be used at pos are
1433 // permutations_[pos], ..., permutations_.back(). Starts the iteration at
1434 // permutations_[pos].
1435 Set(pos, pos);
1436 // Invariant(pos) holds.
1437 }
1438 // Invariant(pos - 1) hold. We have a permutation.
1439}
1440
1441// Unset the element at pos.
1442//
1443// - Precondition: Invariant(pos) holds.
1444// - Postcondition: Invariant(pos - 1) holds.
1445inline void DagTopologicalSortIterator::Iterator::Unset(int pos) {
1446 const int n = permutation_[pos];
1447 // Before the loop: Invariant(pos).2 and Invariant(pos).3 hold.
1448 // After the swap below: Invariant(pos - 1).2 and Invariant(pos - 1).3 hold.
1449 for (const int c : graph_[n]) {
1450 if (missing_parent_numbers_[c] == 0) permutation_.pop_back();
1451 ++missing_parent_numbers_[c];
1452 }
1453 std::swap(permutation_[element_original_position_[pos]], permutation_[pos]);
1454 // Invariant(pos).4 -> Invariant(pos - 1).4.
1455 element_original_position_[pos] = pos;
1456}
1457
1458// Set the element at pos to the element at k.
1459//
1460// - Precondition: Invariant(pos - 1) holds and k in [pos,
1461// permutation_.size()).
1462// - Postcondition: Invariant(pos) holds and permutation_[pos] has been swapped
1463// with permutation_[k].
1464inline void DagTopologicalSortIterator::Iterator::Set(int pos, int k) {
1465 int n = permutation_[k];
1466 // Before the loop: Invariant(pos - 1).2 and Invariant(pos - 1).3 hold.
1467 // After the loop: Invariant(pos).2 and Invariant(pos).3 hold.
1468 for (int c : graph_[n]) {
1469 --missing_parent_numbers_[c];
1470 if (missing_parent_numbers_[c] == 0) permutation_.push_back(c);
1471 }
1472 // Invariant(pos - 1).1 -> Invariant(pos).1.
1473 std::swap(permutation_[k], permutation_[pos]);
1474 // Invariant(pos - 1).4 -> Invariant(pos).4.
1475 element_original_position_[pos] = k;
1476}
1477
1478template <typename K, typename V>
1479inline int MergeableOccurrenceList<K, V>::InternalKey(K key) const {
1480 DCHECK_GE(key, 0);
1481 DCHECK_LT(key, rows_.size());
1482 if constexpr (std::is_same_v<K, int>) {
1483 return key;
1484 } else {
1485 return key.value();
1486 }
1487}
1488
1489} // namespace sat
1490} // namespace operations_research
1491
1492#endif // ORTOOLS_SAT_UTIL_H_
SharedTimeLimit(TimeLimit *time_limit)
Definition time_limit.h:329
Result Solve(absl::Span< const Domain > domains, absl::Span< const int64_t > coeffs, absl::Span< const int64_t > costs, const Domain &rhs)
Definition util.cc:610
void ResetFromTranspose(const CompactVectorVector< V, K > &other, int min_transpose_size=0)
Definition util.h:1186
void ResetFromPairs(const Collection &pairs, int minimum_num_nodes=0)
Definition util.h:1089
void ResetFromFlatMapping(Keys keys, Values values, int minimum_num_nodes=0)
Definition util.h:1046
void reserve(int size, int num_entries)
Definition util.h:101
void emplace_back(V const *begin, V const *end)
Definition util.h:176
void ReplaceValuesBySmallerSet(K key, absl::Span< const V > values)
Definition util.h:957
void Shrink(K key, int new_size)
Definition util.h:989
std::vector< absl::Span< const V > > AsVectorOfSpan() const
Definition util.h:1019
void RemoveBySwap(K key, int index)
Definition util.h:159
int AddLiterals(const std::vector< L > &wrapped_values)
Definition util.h:967
void AppendToLastVector(const V &value)
Definition util.h:944
int Add(absl::Span< const V > values)
Definition util.h:935
void ResetFromTransposeMap(const Container &other, int min_transpose_size=0)
Definition util.h:1133
friend bool operator==(const Iterator &a, const Iterator &b)
Definition util.h:1260
ExponentialMovingAverage(double decaying_factor)
Definition util.h:794
absl::Span< const int64_t > reachable()
Definition util.h:669
bool MightBeReachable(int64_t sum) const
Definition util.h:662
void Add(const int64_t positive_value)
Definition util.h:634
FixedCapacityVector(absl::Span< const T > span)
Definition util.h:308
IncrementalAverage(double initial_average)
Definition util.h:771
double ComplexityEstimate(int num_elements, int64_t bin_size)
Definition util.cc:930
int64_t MaxSubsetSum(absl::Span< const int64_t > elements, int64_t bin_size)
Definition util.cc:940
MaxBoundedSubsetSum(int64_t bound, int max_complexity_per_add=50)
Definition util.h:569
void ResetFromTransposeMap(const Container &input, int min_transpose_size=0)
Definition util.h:197
absl::Span< const V > operator[](K key)
Definition util.h:216
void MergeInto(K to_merge, K representative)
Definition util.h:253
ModelRandomGenerator(const absl::BitGenRef &bit_gen_ref)
Definition util.h:468
ModelRandomGenerator(const SatParameters &params)
Definition util.h:459
Percentile(int record_limit)
Definition util.h:824
absl::Span< const int64_t > Compute(absl::Span< const int64_t > elements, int64_t maximum_sum, bool abort_if_maximum_reached=false)
Definition util.cc:868
absl::Span< const int64_t > SortedSums() const
Definition util.h:698
void Add(Element e, Score score)
Definition util.h:854
std::vector< Element > * MutableUnorderedElements()
Definition util.h:878
const std::vector< Element > & UnorderedElements() const
Definition util.h:877
void OpenSourceEraseIf(Container &c, Pred pred)
Definition util.h:55
int64_t ProductWithModularInverse(int64_t coeff, int64_t mod, int64_t rhs)
Definition util.cc:171
bool SolveDiophantineEquationOfSizeTwo(int64_t &a, int64_t &b, int64_t &cte, int64_t &x0, int64_t &y0)
Definition util.cc:193
int64_t FloorSquareRoot(int64_t a)
Definition util.cc:289
int64_t CeilSquareRoot(int64_t a)
Definition util.cc:298
int64_t ModularInverse(int64_t x, int64_t m)
Definition util.cc:133
bool IsNegatableInt64(absl::int128 x)
Definition util.h:929
int64_t SafeDoubleToInt64(double value)
Definition util.h:917
bool DiophantineEquationOfSizeTwoHasSolutionInDomain(const Domain &x, int64_t a, const Domain &y, int64_t b, int64_t cte)
Definition util.cc:237
bool IsStrictlyIncluded(Bitset64< LiteralIndex >::ConstView in_subset, int subset_size, absl::Span< const Literal > superset)
Definition util.h:897
int64_t ClosestMultiple(int64_t value, int64_t base)
Definition util.cc:306
int64_t PositiveMod(int64_t x, int64_t m)
Definition util.cc:166
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)
Definition util.cc:313
std::vector< absl::Span< int > > AtMostOneDecomposition(const std::vector< std::vector< int > > &graph, absl::BitGenRef random, std::vector< int > *buffer)
Definition util.cc:856
LinearExpr operator*(LinearExpr expr, int64_t factor)
Definition cp_model.h:1276
std::string FormatName(absl::string_view name)
Definition util.h:342
std::string FormatTable(std::vector< std::vector< std::string > > &table, int spacing)
Definition util.cc:61
OR-Tools root namespace.
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)
STL namespace.
trees with all degrees equal to
if(!yyg->yy_init)
Definition parser.yy.cc:966
static int input(yyscan_t yyscanner)