OR-Tools  9.3
sat/util.cc
Go to the documentation of this file.
1// Copyright 2010-2021 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#include "ortools/sat/util.h"
15
16#include <algorithm>
17#include <cmath>
18#include <cstdint>
19#include <cstdlib>
20#include <deque>
21#include <limits>
22#include <numeric>
23#include <utility>
24#include <vector>
25
28#if !defined(__PORTABLE_PLATFORM__)
29#include "google/protobuf/descriptor.h"
30#endif // __PORTABLE_PLATFORM__
31#include "absl/container/btree_set.h"
32#include "absl/container/flat_hash_map.h"
33#include "absl/numeric/int128.h"
34#include "absl/random/bit_gen_ref.h"
35#include "absl/random/distributions.h"
36#include "absl/types/span.h"
41#include "ortools/sat/sat_parameters.pb.h"
44
45namespace operations_research {
46namespace sat {
47
48namespace {
49// This will be optimized into one division. I tested that in other places:
50//
51// Note that I am not 100% sure we need the indirection for the optimization
52// to kick in though, but this seemed safer given our weird r[i ^ 1] inputs.
53void QuotientAndRemainder(int64_t a, int64_t b, int64_t& q, int64_t& r) {
54 q = a / b;
55 r = a % b;
56}
57} // namespace
58
59void RandomizeDecisionHeuristic(absl::BitGenRef random,
60 SatParameters* parameters) {
61#if !defined(__PORTABLE_PLATFORM__)
62 // Random preferred variable order.
63 const google::protobuf::EnumDescriptor* order_d =
64 SatParameters::VariableOrder_descriptor();
65 parameters->set_preferred_variable_order(
66 static_cast<SatParameters::VariableOrder>(
67 order_d->value(absl::Uniform(random, 0, order_d->value_count()))
68 ->number()));
69
70 // Random polarity initial value.
71 const google::protobuf::EnumDescriptor* polarity_d =
72 SatParameters::Polarity_descriptor();
73 parameters->set_initial_polarity(static_cast<SatParameters::Polarity>(
74 polarity_d->value(absl::Uniform(random, 0, polarity_d->value_count()))
75 ->number()));
76#endif // __PORTABLE_PLATFORM__
77 // Other random parameters.
78 parameters->set_use_phase_saving(absl::Bernoulli(random, 0.5));
79 parameters->set_random_polarity_ratio(absl::Bernoulli(random, 0.5) ? 0.01
80 : 0.0);
81 parameters->set_random_branches_ratio(absl::Bernoulli(random, 0.5) ? 0.01
82 : 0.0);
83}
84
85// Using the extended Euclidian algo, we find a and b such that a x + b m = gcd.
86// https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
87int64_t ModularInverse(int64_t x, int64_t m) {
88 DCHECK_GE(x, 0);
89 DCHECK_LT(x, m);
90
91 int64_t r[2] = {m, x};
92 int64_t t[2] = {0, 1};
93 int64_t q;
94
95 // We only keep the last two terms of the sequences with the "^1" trick:
96 //
97 // q = r[i-2] / r[i-1]
98 // r[i] = r[i-2] % r[i-1]
99 // t[i] = t[i-2] - t[i-1] * q
100 //
101 // We always have:
102 // - gcd(r[i], r[i - 1]) = gcd(r[i - 1], r[i - 2])
103 // - x * t[i] + m * t[i - 1] = r[i]
104 int i = 0;
105 for (; r[i ^ 1] != 0; i ^= 1) {
106 QuotientAndRemainder(r[i], r[i ^ 1], q, r[i]);
107 t[i] -= t[i ^ 1] * q;
108 }
109
110 // If the gcd is not one, there is no inverse, we returns 0.
111 if (r[i] != 1) return 0;
112
113 // Correct the result so that it is in [0, m). Note that abs(t[i]) is known to
114 // be less than or equal to x / 2, and we have thorough unit-tests.
115 if (t[i] < 0) t[i] += m;
116
117 return t[i];
118}
119
120int64_t PositiveMod(int64_t x, int64_t m) {
121 const int64_t r = x % m;
122 return r < 0 ? r + m : r;
123}
124
125int64_t ProductWithModularInverse(int64_t coeff, int64_t mod, int64_t rhs) {
126 DCHECK_NE(coeff, 0);
127 DCHECK_NE(mod, 0);
128
129 mod = std::abs(mod);
130 if (rhs == 0 || mod == 1) return 0;
131 DCHECK_EQ(std::gcd(std::abs(coeff), mod), 1);
132
133 // Make both in [0, mod).
134 coeff = PositiveMod(coeff, mod);
135 rhs = PositiveMod(rhs, mod);
136
137 // From X * coeff % mod = rhs
138 // We deduce that X % mod = rhs * inverse % mod
139 const int64_t inverse = ModularInverse(coeff, mod);
140 CHECK_NE(inverse, 0);
141
142 // We make the operation in 128 bits to be sure not to have any overflow here.
143 const absl::int128 p = absl::int128{inverse} * absl::int128{rhs};
144 return static_cast<int64_t>(p % absl::int128{mod});
145}
146
147bool SolveDiophantineEquationOfSizeTwo(int64_t& a, int64_t& b, int64_t& cte,
148 int64_t& x0, int64_t& y0) {
149 CHECK_NE(a, 0);
150 CHECK_NE(b, 0);
153
154 const int64_t gcd = std::gcd(std::abs(a), std::abs(b));
155 if (cte % gcd != 0) return false;
156 a /= gcd;
157 b /= gcd;
158 cte /= gcd;
159
160 // The simple case where (0, 0) is a solution.
161 if (cte == 0) {
162 x0 = y0 = 0;
163 return true;
164 }
165
166 // We solve a * X + b * Y = cte
167 // We take a valid x0 in [0, b) by considering the equation mod b.
168 x0 = ProductWithModularInverse(a, b, cte);
169
170 // We choose x0 of the same sign as cte.
171 if (cte < 0 && x0 != 0) x0 -= std::abs(b);
172
173 // By plugging X = x0 + b * Z
174 // We have a * (x0 + b * Z) + b * Y = cte
175 // so a * b * Z + b * Y = cte - a * x0;
176 // and y0 = (cte - a * x0) / b (with an exact division by construction).
177 const absl::int128 t = absl::int128{cte} - absl::int128{a} * absl::int128{x0};
178 DCHECK_EQ(t % absl::int128{b}, absl::int128{0});
179
180 // Overflow-wise, there is two cases for cte > 0:
181 // - a * x0 <= cte, in this case y0 will not overflow (<= cte).
182 // - a * x0 > cte, in this case y0 will be in (-a, 0].
183 const absl::int128 r = t / absl::int128{b};
186
187 y0 = static_cast<int64_t>(r);
188 return true;
189}
190
191// TODO(user): Find better implementation? In pratice passing via double is
192// almost always correct, but the CapProd() might be a bit slow. However this
193// is only called when we do propagate something.
194int64_t FloorSquareRoot(int64_t a) {
195 int64_t result =
196 static_cast<int64_t>(std::floor(std::sqrt(static_cast<double>(a))));
197 while (CapProd(result, result) > a) --result;
198 while (CapProd(result + 1, result + 1) <= a) ++result;
199 return result;
200}
201
202// TODO(user): Find better implementation?
203int64_t CeilSquareRoot(int64_t a) {
204 int64_t result =
205 static_cast<int64_t>(std::ceil(std::sqrt(static_cast<double>(a))));
206 while (CapProd(result, result) < a) ++result;
207 while ((result - 1) * (result - 1) >= a) --result;
208 return result;
209}
210
211int64_t ClosestMultiple(int64_t value, int64_t base) {
212 if (value < 0) return -ClosestMultiple(-value, base);
213 int64_t result = value / base * base;
214 if (value - result > base / 2) result += base;
215 return result;
216}
217
219 int64_t base, const std::vector<int64_t>& coeffs,
220 const std::vector<int64_t>& lbs, const std::vector<int64_t>& ubs,
221 int64_t rhs, int64_t* new_rhs) {
222 // Precompute some bounds for the equation base * X + error <= rhs.
223 int64_t max_activity = 0;
224 int64_t max_x = 0;
225 int64_t min_error = 0;
226 const int num_terms = coeffs.size();
227 if (num_terms == 0) return false;
228 for (int i = 0; i < num_terms; ++i) {
229 const int64_t coeff = coeffs[i];
230 CHECK_GT(coeff, 0);
231 const int64_t closest = ClosestMultiple(coeff, base);
232 max_activity += coeff * ubs[i];
233 max_x += closest / base * ubs[i];
234
235 const int64_t error = coeff - closest;
236 if (error >= 0) {
237 min_error += error * lbs[i];
238 } else {
239 min_error += error * ubs[i];
240 }
241 }
242
243 if (max_activity <= rhs) {
244 // The constraint is trivially true.
245 *new_rhs = max_x;
246 return true;
247 }
248
249 // This is the max error assuming that activity > rhs.
250 int64_t max_error_if_invalid = 0;
251 const int64_t slack = max_activity - rhs - 1;
252 for (int i = 0; i < num_terms; ++i) {
253 const int64_t coeff = coeffs[i];
254 const int64_t closest = ClosestMultiple(coeff, base);
255 const int64_t error = coeff - closest;
256 if (error >= 0) {
257 max_error_if_invalid += error * ubs[i];
258 } else {
259 const int64_t lb = std::max(lbs[i], ubs[i] - slack / coeff);
260 max_error_if_invalid += error * lb;
261 }
262 }
263
264 // We have old solution valid =>
265 // base * X + error <= rhs
266 // base * X <= rhs - error
267 // base * X <= rhs - min_error
268 // X <= new_rhs
269 *new_rhs = std::min(max_x, MathUtil::FloorOfRatio(rhs - min_error, base));
270
271 // And we have old solution invalid =>
272 // base * X + error >= rhs + 1
273 // base * X >= rhs + 1 - max_error_if_invalid
274 // X >= infeasibility_bound
275 const int64_t infeasibility_bound =
276 MathUtil::CeilOfRatio(rhs + 1 - max_error_if_invalid, base);
277
278 // If the two bounds can be separated, we have an equivalence !
279 return *new_rhs < infeasibility_bound;
280}
281
283 const absl::btree_set<LiteralIndex>& processed, int relevant_prefix_size,
284 std::vector<Literal>* literals) {
285 if (literals->empty()) return -1;
286 if (!gtl::ContainsKey(processed, literals->back().Index())) {
287 return std::min<int>(relevant_prefix_size, literals->size());
288 }
289
290 // To get O(n log n) size of suffixes, we will first process the last n/2
291 // literals, we then move all of them first and process the n/2 literals left.
292 // We use the same algorithm recursively. The sum of the suffixes' size S(n)
293 // is thus S(n/2) + n + S(n/2). That gives us the correct complexity. The code
294 // below simulates one step of this algorithm and is made to be "robust" when
295 // from one call to the next, some literals have been removed (but the order
296 // of literals is preserved).
297 int num_processed = 0;
298 int num_not_processed = 0;
299 int target_prefix_size = literals->size() - 1;
300 for (int i = literals->size() - 1; i >= 0; i--) {
301 if (gtl::ContainsKey(processed, (*literals)[i].Index())) {
302 ++num_processed;
303 } else {
304 ++num_not_processed;
305 target_prefix_size = i;
306 }
307 if (num_not_processed >= num_processed) break;
308 }
309 if (num_not_processed == 0) return -1;
310 target_prefix_size = std::min(target_prefix_size, relevant_prefix_size);
311
312 // Once a prefix size has been decided, it is always better to
313 // enqueue the literal already processed first.
314 std::stable_partition(literals->begin() + target_prefix_size, literals->end(),
315 [&processed](Literal l) {
316 return gtl::ContainsKey(processed, l.Index());
317 });
318 return target_prefix_size;
319}
320
321void IncrementalAverage::Reset(double reset_value) {
322 num_records_ = 0;
323 average_ = reset_value;
324}
325
326void IncrementalAverage::AddData(double new_record) {
327 num_records_++;
328 average_ += (new_record - average_) / num_records_;
329}
330
331void ExponentialMovingAverage::AddData(double new_record) {
332 num_records_++;
333 average_ = (num_records_ == 1)
334 ? new_record
335 : (new_record + decaying_factor_ * (average_ - new_record));
336}
337
338void Percentile::AddRecord(double record) {
339 records_.push_front(record);
340 if (records_.size() > record_limit_) {
341 records_.pop_back();
342 }
343}
344
345double Percentile::GetPercentile(double percent) {
346 CHECK_GT(records_.size(), 0);
347 CHECK_LE(percent, 100.0);
348 CHECK_GE(percent, 0.0);
349 std::vector<double> sorted_records(records_.begin(), records_.end());
350 std::sort(sorted_records.begin(), sorted_records.end());
351 const int num_records = sorted_records.size();
352
353 const double percentile_rank =
354 static_cast<double>(num_records) * percent / 100.0 - 0.5;
355 if (percentile_rank <= 0) {
356 return sorted_records.front();
357 } else if (percentile_rank >= num_records - 1) {
358 return sorted_records.back();
359 }
360 // Interpolate.
361 DCHECK_GE(num_records, 2);
362 DCHECK_LT(percentile_rank, num_records - 1);
363 const int lower_rank = static_cast<int>(std::floor(percentile_rank));
364 DCHECK_LT(lower_rank, num_records - 1);
365 return sorted_records[lower_rank] +
366 (percentile_rank - lower_rank) *
367 (sorted_records[lower_rank + 1] - sorted_records[lower_rank]);
368}
369
370void CompressTuples(absl::Span<const int64_t> domain_sizes, int64_t any_value,
371 std::vector<std::vector<int64_t>>* tuples) {
372 if (tuples->empty()) return;
373
374 // Remove duplicates if any.
376
377 const int num_vars = (*tuples)[0].size();
378
379 std::vector<int> to_remove;
380 std::vector<int64_t> tuple_minus_var_i(num_vars - 1);
381 for (int i = 0; i < num_vars; ++i) {
382 const int domain_size = domain_sizes[i];
383 if (domain_size == 1) continue;
384 absl::flat_hash_map<const std::vector<int64_t>, std::vector<int>>
385 masked_tuples_to_indices;
386 for (int t = 0; t < tuples->size(); ++t) {
387 int out = 0;
388 for (int j = 0; j < num_vars; ++j) {
389 if (i == j) continue;
390 tuple_minus_var_i[out++] = (*tuples)[t][j];
391 }
392 masked_tuples_to_indices[tuple_minus_var_i].push_back(t);
393 }
394 to_remove.clear();
395 for (const auto& it : masked_tuples_to_indices) {
396 if (it.second.size() != domain_size) continue;
397 (*tuples)[it.second.front()][i] = any_value;
398 to_remove.insert(to_remove.end(), it.second.begin() + 1, it.second.end());
399 }
400 std::sort(to_remove.begin(), to_remove.end(), std::greater<int>());
401 for (const int t : to_remove) {
402 (*tuples)[t] = tuples->back();
403 tuples->pop_back();
404 }
405 }
406}
407
408} // namespace sat
409} // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:893
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:892
#define CHECK_GE(val1, val2)
Definition: base/logging.h:707
#define CHECK_GT(val1, val2)
Definition: base/logging.h:708
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:895
#define CHECK_NE(val1, val2)
Definition: base/logging.h:704
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:894
#define CHECK_LE(val1, val2)
Definition: base/logging.h:705
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:891
static IntegralType CeilOfRatio(IntegralType numerator, IntegralType denominator)
Definition: mathutil.h:39
static IntegralType FloorOfRatio(IntegralType numerator, IntegralType denominator)
Definition: mathutil.h:53
double GetPercentile(double percent)
Definition: sat/util.cc:345
int64_t b
int64_t a
SatParameters parameters
int64_t value
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
Definition: stl_util.h:58
bool ContainsKey(const Collection &collection, const Key &key)
Definition: map_util.h:200
void RandomizeDecisionHeuristic(absl::BitGenRef random, SatParameters *parameters)
Definition: sat/util.cc:59
int64_t ClosestMultiple(int64_t value, int64_t base)
Definition: sat/util.cc:211
void CompressTuples(absl::Span< const int64_t > domain_sizes, int64_t any_value, std::vector< std::vector< int64_t > > *tuples)
Definition: sat/util.cc:370
int64_t PositiveMod(int64_t x, int64_t m)
Definition: sat/util.cc:120
int64_t CeilSquareRoot(int64_t a)
Definition: sat/util.cc:203
bool SolveDiophantineEquationOfSizeTwo(int64_t &a, int64_t &b, int64_t &cte, int64_t &x0, int64_t &y0)
Definition: sat/util.cc:147
int64_t FloorSquareRoot(int64_t a)
Definition: sat/util.cc:194
int64_t ModularInverse(int64_t x, int64_t m)
Definition: sat/util.cc:87
int64_t ProductWithModularInverse(int64_t coeff, int64_t mod, int64_t rhs)
Definition: sat/util.cc:125
int MoveOneUnprocessedLiteralLast(const absl::btree_set< LiteralIndex > &processed, int relevant_prefix_size, std::vector< Literal > *literals)
Definition: sat/util.cc:282
bool LinearInequalityCanBeReducedWithClosestMultiple(int64_t base, const std::vector< int64_t > &coeffs, const std::vector< int64_t > &lbs, const std::vector< int64_t > &ubs, int64_t rhs, int64_t *new_rhs)
Definition: sat/util.cc:218
Collection of objects used to extend the Constraint Solver library.
int64_t CapProd(int64_t x, int64_t y)
const double coeff