14#ifndef OR_TOOLS_ALGORITHMS_BINARY_SEARCH_H_
15#define OR_TOOLS_ALGORITHMS_BINARY_SEARCH_H_
22#include "absl/functional/function_ref.h"
23#include "absl/log/check.h"
24#include "absl/numeric/int128.h"
25#include "absl/types/span.h"
72Point
BinarySearch(Point x_true, Point x_false, std::function<
bool(Point)> f);
107template <
class Po
int,
class Value>
108std::pair<Point, Value>
ConvexMinimum(absl::Span<const Point> sorted_points,
109 std::function<
Value(Point)> f);
115template <
class Po
int,
class Value>
117 std::pair<Point, Value> current_min,
118 absl::Span<const Point> sorted_points,
119 std::function<
Value(Point)> f);
122template <
class Po
int,
class Value>
124 absl::FunctionRef<
Value(Point)> f);
125template <
class Po
int,
class Value>
127 Point begin, Point
end,
128 absl::FunctionRef<
Value(Point)> f);
141 return std::isnan(
x);
145 return std::isnan(
x);
149 return std::isnan(
x);
154 if constexpr (std::is_same_v<T, absl::int128>) {
155 return (
x < 0) == (
y < 0);
156 }
else if constexpr (std::is_same_v<T, absl::uint128> ||
157 std::is_unsigned_v<T>) {
159 }
else if constexpr (std::is_signed_v<T>) {
160 return std::signbit(
x) == std::signbit(
y);
165template <
typename IntT>
167 if constexpr (std::is_integral_v<IntT>) {
168 if constexpr (std::is_unsigned_v<IntT>) {
171 return (IntT{-1} & IntT{3}) == IntT{3};
179template <
class Po
int>
187 midpoint = (
x |
y) - ((
x ^
y) >> 1);
194 x <
y ?
x + (
y -
x) / 2
200 DCHECK_LE(midpoint,
y) <<
"Overflow?";
201 DCHECK_GE(midpoint,
x) <<
"Overflow?";
203 DCHECK_GE(midpoint,
y) <<
"Overflow?";
204 DCHECK_LE(midpoint,
x) <<
"Overflow?";
210template <
class Po
int>
211Point
BinarySearch(Point x_true, Point x_false, std::function<
bool(Point)> f) {
212 DCHECK(f(x_true)) << x_true;
213 DCHECK(!f(x_false)) << x_false;
214 int num_iterations = 0;
215 constexpr int kMaxNumIterations = 1000000;
222 if (++num_iterations > kMaxNumIterations) {
224 <<
"The binary search seems to loop forever! This indicates that your"
225 " input types don't converge when repeatedly taking the midpoint";
236template <
class Po
int,
class Value>
238 absl::FunctionRef<Value(Point)> f) {
239 DCHECK_LT(begin,
end);
240 const Value
size =
end - begin;
242 return {begin, f(begin)};
247 std::pair<Point, Value> current_min;
250 const Point mid = begin + (
end - begin) / 2;
251 DCHECK_GT(mid, begin);
252 const Value v = f(mid);
253 const Point before_mid = mid - 1;
254 const Value before_v = f(before_mid);
255 if (before_v == v)
return {before_mid, before_v};
258 current_min = {before_mid, before_v};
261 current_min = {mid, v};
265 if (begin >=
end)
return current_min;
269template <
class Po
int,
class Value>
271 Point begin, Point
end,
272 absl::FunctionRef<Value(Point)> f) {
273 DCHECK_LT(begin,
end);
274 while ((
end - begin) > 1) {
275 DCHECK(current_min.first < begin || current_min.first >=
end);
276 bool current_is_after_end = current_min.first >=
end;
277 const Point mid = begin + (
end - begin) / 2;
278 const Value v = f(mid);
279 if (v >= current_min.second) {
282 if (current_is_after_end) {
290 DCHECK_GT(mid, begin);
291 const Point before_mid = mid - 1;
292 const Value before_v = f(before_mid);
293 if (before_v == v)
return {before_mid, before_v};
295 current_min = {before_mid, before_v};
296 current_is_after_end =
true;
299 current_is_after_end =
false;
300 current_min = {mid, v};
306 if (
end - begin == 1) {
307 const Value v = f(begin);
308 if (v <= current_min.second)
return {begin, v};
313template <
class Po
int,
class Value>
315 std::function<Value(Point)> f) {
316 auto index_f = [&](
int index) -> Value {
return f(sorted_points[
index]); };
317 const auto& [
index, v] =
319 return {sorted_points[
index], v};
322template <
class Po
int,
class Value>
324 std::pair<Point, Value> current_min,
325 absl::Span<const Point> sorted_points,
326 std::function<Value(Point)> f) {
327 auto index_f = [&](
int index) -> Value {
return f(sorted_points[
index]); };
328 std::pair<int, Value> index_current_min = std::make_pair(
329 is_to_the_right ? sorted_points.size() : -1, current_min.second);
331 index_current_min, 0, sorted_points.size(), index_f);
332 if (
index == index_current_min.first)
return current_min;
333 return {sorted_points[
index], v};
bool AreNumbersOfSameSign(const T &x, const T &y)
bool IsNanGeneric(const T &)
constexpr bool UsesTwosComplement()
std::function< int64_t(const Model &)> Value(IntegerVariable v)
This checks that the variable is fixed.
In SWIG mode, we don't want anything besides these top-level includes.
Point BinarySearchMidpoint(Point x, Point y)
std::pair< Point, Value > RangeConvexMinimum(Point begin, Point end, absl::FunctionRef< Value(Point)> f)
Searches in the range [begin, end), where Point supports basic arithmetic.
Point BinarySearch(Point x_true, Point x_false, std::function< bool(Point)> f)
std::pair< Point, Value > ConvexMinimum(absl::Span< const Point > sorted_points, std::function< Value(Point)> f)
std::optional< int64_t > end