Google OR-Tools v9.11
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-2024 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 OR_TOOLS_SAT_UTIL_H_
15#define OR_TOOLS_SAT_UTIL_H_
16
17#include <algorithm>
18#include <array>
19#include <cmath>
20#include <cstdint>
21#include <deque>
22#include <limits>
23#include <string>
24#include <type_traits>
25#include <utility>
26#include <vector>
27
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"
41#include "ortools/sat/model.h"
43#include "ortools/sat/sat_parameters.pb.h"
48
49namespace operations_research {
50namespace sat {
51
52// A simple class with always IdentityMap[t] == t.
53// This is to avoid allocating vector with std::iota() in some Apis.
54template <typename T>
56 public:
57 T operator[](T t) const { return t; }
58};
59
60// Small utility class to store a vector<vector<>> where one can only append new
61// vector and never change previously added ones. This allows to store a static
62// key -> value(s) mapping.
63//
64// This is a lot more compact memorywise and thus faster than vector<vector<>>.
65// Note that we implement a really small subset of the vector<vector<>> API.
66//
67// We support int and StrongType for key K and any copyable type for value V.
68template <typename K = int, typename V = int>
70 public:
71 // Size of the "key" space, always in [0, size()).
72 size_t size() const;
73 bool empty() const;
74
75 // Getters, either via [] or via a wrapping to be compatible with older api.
76 //
77 // Warning: Spans are only valid until the next modification!
78 absl::Span<V> operator[](K key);
79 absl::Span<const V> operator[](K key) const;
80 std::vector<absl::Span<const V>> AsVectorOfSpan() const;
81
82 // Restore to empty vector<vector<>>.
83 void clear();
84
85 // Reserve memory if it is already known or tightly estimated.
86 void reserve(int size) {
87 starts_.reserve(size);
88 sizes_.reserve(size);
89 }
90 void reserve(int size, int num_terms) {
92 buffer_.reserve(num_terms);
93 }
94
95 // Given a flat mapping (keys[i] -> values[i]) with two parallel vectors, not
96 // necessarily sorted by key, regroup the same key so that
97 // CompactVectorVector[key] list all values in the order in which they appear.
98 //
99 // We only check keys.size(), so this can be used with IdentityMap() as
100 // second argument.
101 template <typename Keys, typename Values>
102 void ResetFromFlatMapping(Keys keys, Values values);
103
104 // Initialize this vector from the transpose of another.
105 // IMPORTANT: This cannot be called with the vector itself.
106 //
107 // If min_transpose_size is given, then the transpose will have at least this
108 // size even if some of the last keys do not appear in other.
109 //
110 // If this is called twice in a row, then it has the side effect of sorting
111 // all inner vectors by values !
113 int min_transpose_size = 0);
114
115 // Append a new entry.
116 // Returns the previous size() as this is convenient for how we use it.
117 int Add(absl::Span<const V> values);
118
119 // Hacky: same as Add() but for sat::Literal or any type from which we can get
120 // a value type V via L.Index().value().
121 template <typename L>
122 int AddLiterals(const std::vector<L>& wrapped_values);
123
124 // We lied when we said this is a pure read-only class :)
125 // It is possible to shrink inner vectors with not much cost.
126 //
127 // Removes the element at index from this[key] by swapping it with
128 // this[key].back() and then decreasing this key size. It is an error to
129 // call this on an empty inner vector.
130 void RemoveBySwap(K key, int index) {
131 DCHECK_GE(index, 0);
132 DCHECK_LT(index, sizes_[key]);
133 const int start = starts_[key];
134 std::swap(buffer_[start + index], buffer_[start + sizes_[key] - 1]);
135 sizes_[key]--;
136 }
137
138 // Replace the values at the given key.
139 // This will crash if there are more values than before.
140 void ReplaceValuesBySmallerSet(K key, absl::Span<const V> values);
141
142 // Interface so this can be used as an output of
143 // FindStronglyConnectedComponents().
144 void emplace_back(V const* begin, V const* end) {
145 Add(absl::MakeSpan(begin, end - begin));
146 }
147
148 private:
149 // Convert int and StrongInt to normal int.
150 static int InternalKey(K key);
151
152 std::vector<int> starts_;
153 std::vector<int> sizes_;
154 std::vector<V> buffer_;
155};
156
157// We often have a vector with fixed capacity reserved outside the hot loops.
158// Using this class instead save the capacity but most importantly link a lot
159// less code for the push_back() calls which allow more inlining.
160//
161// TODO(user): Add more functions and unit-test.
162template <typename T>
164 public:
165 void ClearAndReserve(size_t size) {
166 size_ = 0;
167 data_.reset(new T[size]);
168 }
169
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; }
175
176 T operator[](int i) const { return data_[i]; }
177 T& operator[](int i) { return data_[i]; }
178
179 T back() const { return data_[size_ - 1]; }
180 T& back() { return data_[size_ - 1]; }
181
182 void clear() { size_ = 0; }
183 void resize(size_t size) { size_ = size; }
184 void pop_back() { --size_; }
185 void push_back(T t) { data_[size_++] = t; }
186
187 private:
188 int size_ = 0;
189 std::unique_ptr<T[]> data_ = nullptr;
190};
191
192// Prints a positive number with separators for easier reading (ex: 1'348'065).
193std::string FormatCounter(int64_t num);
194
195// This is used to format our table first row entry.
196inline std::string FormatName(absl::string_view name) {
197 return absl::StrCat("'", name, "':");
198}
199
200// Display tabular data by auto-computing cell width. Note that we right align
201// everything but the first row/col that is assumed to be the table name and is
202// left aligned.
203std::string FormatTable(std::vector<std::vector<std::string>>& table,
204 int spacing = 2);
205
206// Returns a in [0, m) such that a * x = 1 modulo m.
207// If gcd(x, m) != 1, there is no inverse, and it returns 0.
208//
209// This DCHECK that x is in [0, m).
210// This is integer overflow safe.
211//
212// Note(user): I didn't find this in a easily usable standard library.
213int64_t ModularInverse(int64_t x, int64_t m);
214
215// Just returns x % m but with a result always in [0, m).
216int64_t PositiveMod(int64_t x, int64_t m);
217
218// If we know that X * coeff % mod = rhs % mod, this returns c such that
219// PositiveMod(X, mod) = c.
220//
221// This requires coeff != 0, mod !=0 and gcd(coeff, mod) == 1.
222// The result will be in [0, mod) but there is no other condition on the sign or
223// magnitude of a and b.
224//
225// This is overflow safe, and when rhs == 0 or abs(mod) == 1, it returns 0.
226int64_t ProductWithModularInverse(int64_t coeff, int64_t mod, int64_t rhs);
227
228// Returns true if the equation a * X + b * Y = cte has some integer solutions.
229// For now, we check that a and b are different from 0 and from int64_t min.
230//
231// There is actually always a solution if cte % gcd(|a|, |b|) == 0. And because
232// a, b and cte fit on an int64_t, if there is a solution, there is one with X
233// and Y fitting on an int64_t.
234//
235// We will divide everything by gcd(a, b) first, so it is why we take reference
236// and the equation can change.
237//
238// If there are solutions, we return one of them (x0, y0).
239// From any such solution, the set of all solutions is given for Z integer by:
240// X = x0 + b * Z;
241// Y = y0 - a * Z;
242//
243// Given a domain for X and Y, it is possible to compute the "exact" domain of Z
244// with our Domain functions. Note however that this will only compute solution
245// where both x-x0 and y-y0 do fit on an int64_t:
246// DomainOf(x).SubtractionWith(x0).InverseMultiplicationBy(b).IntersectionWith(
247// DomainOf(y).SubtractionWith(y0).InverseMultiplicationBy(-a))
248bool SolveDiophantineEquationOfSizeTwo(int64_t& a, int64_t& b, int64_t& cte,
249 int64_t& x0, int64_t& y0);
250
251// The argument must be non-negative.
252int64_t FloorSquareRoot(int64_t a);
253int64_t CeilSquareRoot(int64_t a);
254
255// Converts a double to int64_t and cap large magnitudes at kint64min/max.
256// We also arbitrarily returns 0 for NaNs.
257//
258// Note(user): This is similar to SaturatingFloatToInt(), but we use our own
259// since we need to open source it and the code is simple enough.
260int64_t SafeDoubleToInt64(double value);
261
262// Returns the multiple of base closest to value. If there is a tie, we return
263// the one closest to zero. This way we have ClosestMultiple(x) =
264// -ClosestMultiple(-x) which is important for how this is used.
265int64_t ClosestMultiple(int64_t value, int64_t base);
266
267// Assuming n "literal" in [0, n), and a graph such that graph[i] list the
268// literal in [0, n) implied to false when the literal with index i is true,
269// this returns an heuristic decomposition of the literals into disjoint at most
270// ones.
271//
272// Note(user): Symmetrize the matrix if not already, maybe rephrase in term
273// of undirected graph, and clique decomposition.
274std::vector<absl::Span<int>> AtMostOneDecomposition(
275 const std::vector<std::vector<int>>& graph, absl::BitGenRef random,
276 std::vector<int>* buffer);
277
278// Given a linear equation "sum coeff_i * X_i <= rhs. We can rewrite it using
279// ClosestMultiple() as "base * new_terms + error <= rhs" where error can be
280// bounded using the provided bounds on each variables. This will return true if
281// the error can be ignored and this equation is completely equivalent to
282// new_terms <= new_rhs.
283//
284// This is useful for cases like 9'999 X + 10'0001 Y <= 155'000 where we have
285// weird coefficient (maybe due to scaling). With a base of 10K, this is
286// equivalent to X + Y <= 15.
287//
288// Preconditions: All coeffs are assumed to be positive. You can easily negate
289// all the negative coeffs and corresponding bounds before calling this.
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,
293 int64_t* new_rhs);
294
295// The model "singleton" random engine used in the solver.
296//
297// In test, we usually set use_absl_random() so that the sequence is changed at
298// each invocation. This way, clients do not relly on the wrong assumption that
299// a particular optimal solution will be returned if they are many equivalent
300// ones.
301class ModelRandomGenerator : public absl::BitGenRef {
302 public:
303 // We seed the strategy at creation only. This should be enough for our use
304 // case since the SatParameters is set first before the solver is created. We
305 // also never really need to change the seed afterwards, it is just used to
306 // diversify solves with identical parameters on different Model objects.
307 explicit ModelRandomGenerator(const SatParameters& params)
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_));
313 }
314 }
316 : ModelRandomGenerator(*model->GetOrCreate<SatParameters>()) {}
317
318 // This is just used to display ABSL_RANDOM_SALT_OVERRIDE in the log so that
319 // it is possible to reproduce a failure more easily while looking at a solver
320 // log.
321 //
322 // TODO(user): I didn't find a cleaner way to log this.
323 void LogSalt() const {}
324
325 private:
326 random_engine_t deterministic_random_;
327 absl::BitGen absl_random_;
328};
329
330// The model "singleton" shared time limit.
332 public:
334 : SharedTimeLimit(model->GetOrCreate<TimeLimit>()) {}
335};
336
337// Randomizes the decision heuristic of the given SatParameters.
338void RandomizeDecisionHeuristic(absl::BitGenRef random,
339 SatParameters* parameters);
340
341// This is equivalent of
342// absl::discrete_distribution<std::size_t>(input.begin(), input.end())(random)
343// but does no allocations. It is a lot faster when you need to pick just one
344// elements from a distribution for instance.
345int WeightedPick(absl::Span<const double> input, absl::BitGenRef random);
346
347// Context: this function is not really generic, but required to be unit-tested.
348// It is used in a clause minimization algorithm when we try to detect if any of
349// the clause literals can be propagated by a subset of the other literal being
350// false. For that, we want to enqueue in the solver all the subset of size n-1.
351//
352// This moves one of the unprocessed literal from literals to the last position.
353// The function tries to do that while preserving the longest possible prefix of
354// literals "amortized" through the calls assuming that we want to move each
355// literal to the last position once.
356//
357// For a vector of size n, if we want to call this n times so that each literal
358// is last at least once, the sum of the size of the changed suffixes will be
359// O(n log n). If we were to use a simpler algorithm (like moving the last
360// unprocessed literal to the last position), this sum would be O(n^2).
361//
362// Returns the size of the common prefix of literals before and after the move,
363// or -1 if all the literals are already processed. The argument
364// relevant_prefix_size is used as a hint when keeping more that this prefix
365// size do not matter. The returned value will always be lower or equal to
366// relevant_prefix_size.
367int MoveOneUnprocessedLiteralLast(
368 const absl::btree_set<LiteralIndex>& processed, int relevant_prefix_size,
369 std::vector<Literal>* literals);
370
371// Simple DP to compute the maximum reachable value of a "subset sum" under
372// a given bound (inclusive). Note that we abort as soon as the computation
373// become too important.
374//
375// Precondition: Both bound and all added values must be >= 0.
377 public:
378 MaxBoundedSubsetSum() : max_complexity_per_add_(/*default=*/50) { Reset(0); }
379 explicit MaxBoundedSubsetSum(int64_t bound, int max_complexity_per_add = 50)
380 : max_complexity_per_add_(max_complexity_per_add) {
381 Reset(bound);
382 }
383
384 // Resets to an empty set of values.
385 // We look for the maximum sum <= bound.
386 void Reset(int64_t bound);
387
388 // Returns the updated max if value was added to the subset-sum.
389 int64_t MaxIfAdded(int64_t candidate) const;
390
391 // Add a value to the base set for which subset sums will be taken.
392 void Add(int64_t value);
393
394 // Add a choice of values to the base set for which subset sums will be taken.
395 // Note that even if this doesn't include zero, not taking any choices will
396 // also be an option.
397 void AddChoices(absl::Span<const int64_t> choices);
398
399 // Adds [0, coeff, 2 * coeff, ... max_value * coeff].
400 void AddMultiples(int64_t coeff, int64_t max_value);
401
402 // Returns an upper bound (inclusive) on the maximum sum <= bound_.
403 // This might return bound_ if we aborted the computation.
404 int64_t CurrentMax() const { return current_max_; }
405
406 int64_t Bound() const { return bound_; }
407
408 private:
409 // This assumes filtered values.
410 void AddChoicesInternal(absl::Span<const int64_t> values);
411
412 // Max_complexity we are willing to pay on each Add() call.
413 const int max_complexity_per_add_;
414 int64_t gcd_;
415 int64_t bound_;
416 int64_t current_max_;
417 std::vector<int64_t> sums_;
418 std::vector<bool> expanded_sums_;
419 std::vector<int64_t> filtered_values_;
420};
421
422// Simple DP to keep the set of the first n reachable value (n > 1).
423//
424// TODO(user): Maybe modulo some prime number we can keep more info.
425// TODO(user): Another common case is a bunch of really small values and larger
426// ones, so we could bound the sum of the small values and keep the first few
427// reachable by the big ones. This is similar to some presolve transformations.
428template <int n>
430 public:
431 FirstFewValues() { Reset(); }
432
433 void Reset() {
434 reachable_.fill(std::numeric_limits<int64_t>::max());
435 reachable_[0] = 0;
436 new_reachable_[0] = 0;
437 }
438
439 // We assume the given positive value can be added as many time as wanted.
440 //
441 // TODO(user): Implement Add() with an upper bound on the multiplicity.
442 void Add(const int64_t positive_value) {
443 DCHECK_GT(positive_value, 0);
444 if (positive_value >= reachable_.back()) return;
445
446 // We copy from reachable_[i] to new_reachable_[j].
447 // The position zero is already copied.
448 int i = 1;
449 int j = 1;
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++];
454 }
455 if (j < n) {
456 // Eliminate duplicates.
457 while (i < n && reachable_[i] == candidate) i++;
458
459 // insert candidate in its final place.
460 new_reachable_[j++] = candidate;
461 }
462 }
463 std::swap(reachable_, new_reachable_);
464 }
465
466 // Returns true iff sum might be expressible as a weighted sum of the added
467 // value. Any sum >= LastValue() is always considered potentially reachable.
468 bool MightBeReachable(int64_t sum) const {
469 if (sum >= reachable_.back()) return true;
470 return std::binary_search(reachable_.begin(), reachable_.end(), sum);
471 }
472
473 const std::array<int64_t, n>& reachable() const { return reachable_; }
474 int64_t LastValue() const { return reachable_.back(); }
475
476 private:
477 std::array<int64_t, n> reachable_;
478 std::array<int64_t, n> new_reachable_;
479};
480
481// Use Dynamic programming to solve a single knapsack. This is used by the
482// presolver to simplify variables appearing in a single linear constraint.
483//
484// Complexity is the best of
485// - O(num_variables * num_relevant_values ^ 2) or
486// - O(num_variables * num_relevant_values * max_domain_size).
488 public:
489 // Solves the problem:
490 // - minimize sum costs * X[i]
491 // - subject to sum coeffs[i] * X[i] \in rhs, with X[i] \in Domain(i).
492 //
493 // Returns:
494 // - (solved = false) if complexity is too high.
495 // - (solved = true, infeasible = true) if proven infeasible.
496 // - (solved = true, infeasible = false, solution) otherwise.
497 struct Result {
498 bool solved = false;
499 bool infeasible = false;
500 std::vector<int64_t> solution;
501 };
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);
505
506 private:
507 Result InternalSolve(int64_t num_values, const Domain& rhs);
508
509 // Canonicalized version.
510 std::vector<Domain> domains_;
511 std::vector<int64_t> coeffs_;
512 std::vector<int64_t> costs_;
513
514 // We only need to keep one state with the same activity.
515 struct State {
516 int64_t cost = std::numeric_limits<int64_t>::max();
517 int64_t value = 0;
518 };
519 std::vector<std::vector<State>> var_activity_states_;
520};
521
522// Manages incremental averages.
524 public:
525 // Initializes the average with 'initial_average' and number of records to 0.
526 explicit IncrementalAverage(double initial_average)
527 : average_(initial_average) {}
529
530 // Sets the number of records to 0 and average to 'reset_value'.
531 void Reset(double reset_value);
532
533 double CurrentAverage() const { return average_; }
534 int64_t NumRecords() const { return num_records_; }
535
536 void AddData(double new_record);
537
538 private:
539 double average_ = 0.0;
540 int64_t num_records_ = 0;
541};
542
543// Manages exponential moving averages defined as
544// new_average = decaying_factor * old_average
545// + (1 - decaying_factor) * new_record.
546// where 0 < decaying_factor < 1.
548 public:
549 explicit ExponentialMovingAverage(double decaying_factor)
550 : decaying_factor_(decaying_factor) {
551 DCHECK_GE(decaying_factor, 0.0);
552 DCHECK_LE(decaying_factor, 1.0);
553 }
554
555 // Returns exponential moving average for all the added data so far.
556 double CurrentAverage() const { return average_; }
557
558 // Returns the total number of added records so far.
559 int64_t NumRecords() const { return num_records_; }
560
561 void AddData(double new_record);
562
563 private:
564 double average_ = 0.0;
565 int64_t num_records_ = 0;
566 const double decaying_factor_;
567};
568
569// Utility to calculate percentile (First variant) for limited number of
570// records. Reference: https://en.wikipedia.org/wiki/Percentile
571//
572// After the vector is sorted, we assume that the element with index i
573// correspond to the percentile 100*(i+0.5)/size. For percentiles before the
574// first element (resp. after the last one) we return the first element (resp.
575// the last). And otherwise we do a linear interpolation between the two element
576// around the asked percentile.
578 public:
579 explicit Percentile(int record_limit) : record_limit_(record_limit) {}
580
581 void AddRecord(double record);
582
583 // Returns number of stored records.
584 int64_t NumRecords() const { return records_.size(); }
585
586 // Note that this runs in O(n) for n records.
587 double GetPercentile(double percent);
588
589 private:
590 std::deque<double> records_;
591 const int record_limit_;
592};
593
594// This method tries to compress a list of tuples by merging complementary
595// tuples, that is a set of tuples that only differ on one variable, and that
596// cover the domain of the variable. In that case, it will keep only one tuple,
597// and replace the value for variable by any_value, the equivalent of '*' in
598// regexps.
599//
600// This method is exposed for testing purposes.
601constexpr int64_t kTableAnyValue = std::numeric_limits<int64_t>::min();
602void CompressTuples(absl::Span<const int64_t> domain_sizes,
603 std::vector<std::vector<int64_t>>* tuples);
604
605// Similar to CompressTuples() but produces a final table where each cell is
606// a set of value. This should result in a table that can still be encoded
607// efficiently in SAT but with less tuples and thus less extra Booleans. Note
608// that if a set of value is empty, it is interpreted at "any" so we can gain
609// some space.
610//
611// The passed tuples vector is used as temporary memory and is detroyed.
612// We interpret kTableAnyValue as an "any" tuple.
613//
614// TODO(user): To reduce memory, we could return some absl::Span in the last
615// layer instead of vector.
616//
617// TODO(user): The final compression is depend on the order of the variables.
618// For instance the table (1,1)(1,2)(1,3),(1,4),(2,3) can either be compressed
619// as (1,*)(2,3) or (1,{1,2,4})({1,3},3). More experiment are needed to devise
620// a better heuristic. It might for example be good to call CompressTuples()
621// first.
622std::vector<std::vector<absl::InlinedVector<int64_t, 2>>> FullyCompressTuples(
623 absl::Span<const int64_t> domain_sizes,
624 std::vector<std::vector<int64_t>>* tuples);
625
626// Keep the top n elements from a stream of elements.
627//
628// TODO(user): We could use gtl::TopN when/if it gets open sourced. Note that
629// we might be slighlty faster here since we use an indirection and don't move
630// the Element class around as much.
631template <typename Element, typename Score>
632class TopN {
633 public:
634 explicit TopN(int n) : n_(n) {}
635
636 void Clear() {
637 heap_.clear();
638 elements_.clear();
639 }
640
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_) {
647 // TODO(user): We could delay that on the n + 1 push.
648 std::make_heap(heap_.begin(), heap_.end());
649 }
650 } else {
651 if (score <= heap_.front().score) return;
652 const int index_to_replace = heap_.front().index;
653 elements_[index_to_replace] = std::move(e);
654
655 // If needed, we could be faster here with an update operation.
656 std::pop_heap(heap_.begin(), heap_.end());
657 heap_.back() = {index_to_replace, score};
658 std::push_heap(heap_.begin(), heap_.end());
659 }
660 }
661
662 bool empty() const { return elements_.empty(); }
663
664 const std::vector<Element>& UnorderedElements() const { return elements_; }
665 std::vector<Element>* MutableUnorderedElements() { return &elements_; }
666
667 private:
668 const int n_;
669
670 // We keep a heap of the n highest score.
671 struct HeapElement {
672 int index; // in elements_;
673 Score score;
674 bool operator<(const HeapElement& other) const {
675 return score > other.score;
676 }
677 };
678 std::vector<HeapElement> heap_;
679 std::vector<Element> elements_;
680};
681
682// ============================================================================
683// Implementation.
684// ============================================================================
685
686inline int64_t SafeDoubleToInt64(double value) {
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();
690 }
691 if (value <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
692 return std::numeric_limits<int64_t>::min();
693 }
694 return static_cast<int64_t>(value);
695}
696
697// Tells whether a int128 can be casted to a int64_t that can be negated.
698inline bool IsNegatableInt64(absl::int128 x) {
699 return x <= absl::int128(std::numeric_limits<int64_t>::max()) &&
700 x > absl::int128(std::numeric_limits<int64_t>::min());
701}
702
703// These functions are copied from MathUtils. However, the original ones are
704// incompatible with absl::int128 as MathLimits<absl::int128>::kIsInteger ==
705// false.
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";
713
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);
717
718 if (ceil) { // Compile-time condition: not an actual branching
719 return rounded_toward_zero + static_cast<IntType>(same_sign && needs_round);
720 } else {
721 return rounded_toward_zero -
722 static_cast<IntType>(!same_sign && needs_round);
723 }
724}
725
726template <typename IntType>
727IntType CeilOfRatio(IntType numerator, IntType denominator) {
728 return CeilOrFloorOfRatio<IntType, true>(numerator, denominator);
730
731template <typename IntType>
732IntType FloorOfRatio(IntType numerator, IntType denominator) {
733 return CeilOrFloorOfRatio<IntType, false>(numerator, denominator);
735
736template <typename K, typename V>
737inline int CompactVectorVector<K, V>::Add(absl::Span<const V> values) {
738 const int index = size();
739 starts_.push_back(buffer_.size());
740 sizes_.push_back(values.size());
741 buffer_.insert(buffer_.end(), values.begin(), values.end());
742 return index;
743}
744
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());
752}
753
754template <typename K, typename V>
755template <typename L>
757 const std::vector<L>& wrapped_values) {
758 const int index = size();
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());
763 }
764 return index;
765}
766
767// We need to support both StrongType and normal int.
768template <typename K, typename V>
769inline int CompactVectorVector<K, V>::InternalKey(K key) {
770 if constexpr (std::is_same_v<K, int>) {
771 return key;
772 } else {
773 return key.value();
774 }
775}
776
777template <typename K, typename V>
778inline absl::Span<const V> CompactVectorVector<K, V>::operator[](K key) const {
779 DCHECK_GE(key, 0);
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};
786}
787
788template <typename K, typename V>
789inline absl::Span<V> CompactVectorVector<K, V>::operator[](K key) {
790 DCHECK_GE(key, 0);
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);
797}
798
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];
805 }
806 return result;
807}
808
809template <typename K, typename V>
810inline void CompactVectorVector<K, V>::clear() {
811 starts_.clear();
812 sizes_.clear();
813 buffer_.clear();
814}
815
816template <typename K, typename V>
817inline size_t CompactVectorVector<K, V>::size() const {
818 return starts_.size();
820
821template <typename K, typename V>
822inline bool CompactVectorVector<K, V>::empty() const {
823 return starts_.empty();
825
826template <typename K, typename V>
827template <typename Keys, typename Values>
829 Values values) {
830 if (keys.empty()) return clear();
831
832 // Compute maximum index.
833 int max_key = 0;
834 for (const K key : keys) {
835 max_key = std::max(max_key, InternalKey(key) + 1);
836 }
837
838 // Compute sizes_;
839 sizes_.assign(max_key, 0);
840 for (const K key : keys) {
841 sizes_[InternalKey(key)]++;
842 }
843
844 // Compute starts_;
845 starts_.assign(max_key, 0);
846 for (int k = 1; k < max_key; ++k) {
847 starts_[k] = starts_[k - 1] + sizes_[k - 1];
848 }
849
850 // Copy data and uses starts as temporary indices.
851 buffer_.resize(keys.size());
852 for (int i = 0; i < keys.size(); ++i) {
853 buffer_[starts_[InternalKey(keys[i])]++] = values[i];
854 }
855
856 // Restore starts_.
857 for (int k = max_key - 1; k > 0; --k) {
858 starts_[k] = starts_[k - 1];
859 }
860 starts_[0] = 0;
861}
862
863// Similar to ResetFromFlatMapping().
864template <typename K, typename V>
865inline void CompactVectorVector<K, V>::ResetFromTranspose(
866 const CompactVectorVector<V, K>& other, int min_transpose_size) {
867 if (other.empty()) {
868 clear();
869 if (min_transpose_size > 0) {
870 starts_.assign(min_transpose_size, 0);
871 sizes_.assign(min_transpose_size, 0);
872 }
873 return;
874 }
875
876 // Compute maximum index.
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);
881 }
882 }
883
884 // Compute sizes_;
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)]++;
889 }
890 }
891
892 // Compute starts_;
893 starts_.assign(max_key, 0);
894 for (int k = 1; k < max_key; ++k) {
895 starts_[k] = starts_[k - 1] + sizes_[k - 1];
896 }
897
898 // Copy data and uses starts as temporary indices.
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;
903 }
904 }
905
906 // Restore starts_.
907 for (int k = max_key - 1; k > 0; --k) {
908 starts_[k] = starts_[k - 1];
909 }
910 starts_[0] = 0;
911}
912
913} // namespace sat
914} // namespace operations_research
915
916#endif // OR_TOOLS_SAT_UTIL_H_
IntegerValue size
Wrapper around TimeLimit to make it thread safe and add Stop() support.
Definition time_limit.h:316
void ResetFromFlatMapping(Keys keys, Values values)
Definition util.h:830
void ResetFromTranspose(const CompactVectorVector< V, K > &other, int min_transpose_size=0)
Similar to ResetFromFlatMapping().
Definition util.h:867
void clear()
Restore to empty vector<vector<>>.
Definition util.h:812
void emplace_back(V const *begin, V const *end)
Definition util.h:144
absl::Span< const V > operator[](K key) const
Definition util.h:780
void ReplaceValuesBySmallerSet(K key, absl::Span< const V > values)
Definition util.h:748
void reserve(int size, int num_terms)
Definition util.h:90
std::vector< absl::Span< const V > > AsVectorOfSpan() const
Definition util.h:803
void RemoveBySwap(K key, int index)
Definition util.h:130
int AddLiterals(const std::vector< L > &wrapped_values)
Definition util.h:758
size_t size() const
Size of the "key" space, always in [0, size()).
Definition util.h:819
void reserve(int size)
Reserve memory if it is already known or tightly estimated.
Definition util.h:86
int Add(absl::Span< const V > values)
Definition util.h:739
double CurrentAverage() const
Returns exponential moving average for all the added data so far.
Definition util.h:556
int64_t NumRecords() const
Returns the total number of added records so far.
Definition util.h:559
ExponentialMovingAverage(double decaying_factor)
Definition util.h:549
const std::array< int64_t, n > & reachable() const
Definition util.h:473
bool MightBeReachable(int64_t sum) const
Definition util.h:468
void Add(const int64_t positive_value)
Definition util.h:442
Manages incremental averages.
Definition util.h:523
IncrementalAverage(double initial_average)
Initializes the average with 'initial_average' and number of records to 0.
Definition util.h:526
MaxBoundedSubsetSum(int64_t bound, int max_complexity_per_add=50)
Definition util.h:379
ModelRandomGenerator(const SatParameters &params)
Definition util.h:307
The model "singleton" shared time limit.
Definition util.h:331
int64_t NumRecords() const
Returns number of stored records.
Definition util.h:584
Percentile(int record_limit)
Definition util.h:579
void Add(Element e, Score score)
Definition util.h:641
std::vector< Element > * MutableUnorderedElements()
Definition util.h:665
const std::vector< Element > & UnorderedElements() const
Definition util.h:664
int64_t a
Definition table.cc:44
SatParameters parameters
GraphType graph
const std::string name
A name for logging purposes.
int64_t value
GRBmodel * model
int index
constexpr int64_t kTableAnyValue
Definition util.h:601
void CompressTuples(absl::Span< const int64_t > domain_sizes, std::vector< std::vector< int64_t > > *tuples)
Definition util.cc:454
int64_t ProductWithModularInverse(int64_t coeff, int64_t mod, int64_t rhs)
Definition util.cc:187
bool SolveDiophantineEquationOfSizeTwo(int64_t &a, int64_t &b, int64_t &cte, int64_t &x0, int64_t &y0)
Definition util.cc:209
std::vector< std::vector< absl::InlinedVector< int64_t, 2 > > > FullyCompressTuples(absl::Span< const int64_t > domain_sizes, std::vector< std::vector< int64_t > > *tuples)
Definition util.cc:878
int64_t FloorSquareRoot(int64_t a)
The argument must be non-negative.
Definition util.cc:256
IntType CeilOfRatio(IntType numerator, IntType denominator)
Definition util.h:729
int64_t CeilSquareRoot(int64_t a)
Definition util.cc:265
int64_t ModularInverse(int64_t x, int64_t m)
Definition util.cc:149
bool IsNegatableInt64(absl::int128 x)
Tells whether a int128 can be casted to a int64_t that can be negated.
Definition util.h:700
int64_t SafeDoubleToInt64(double value)
Definition util.h:688
std::string FormatCounter(int64_t num)
Prints a positive number with separators for easier reading (ex: 1'348'065).
Definition util.cc:49
int64_t ClosestMultiple(int64_t value, int64_t base)
Definition util.cc:273
int64_t PositiveMod(int64_t x, int64_t m)
Just returns x % m but with a result always in [0, m).
Definition util.cc:182
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:280
std::vector< absl::Span< int > > AtMostOneDecomposition(const std::vector< std::vector< int > > &graph, absl::BitGenRef random, std::vector< int > *buffer)
Definition util.cc:998
std::string FormatName(absl::string_view name)
This is used to format our table first row entry.
Definition util.h:196
std::string FormatTable(std::vector< std::vector< std::string > > &table, int spacing)
Definition util.cc:77
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
if(!yyg->yy_init)
Definition parser.yy.cc:965
static int input(yyscan_t yyscanner)
const Variable x
Definition qp_tests.cc:127
int64_t bound
std::optional< int64_t > end
int64_t start