1919#include < functional>
2020#include < utility>
2121
22+ #include " absl/base/log_severity.h"
2223#include " absl/functional/function_ref.h"
2324#include " absl/log/check.h"
2425#include " absl/numeric/int128.h"
2526#include " absl/types/span.h"
2627#include " ortools/base/logging.h"
2728
2829namespace operations_research {
29-
30+ // Finds a point in [x_true, x_false) where f changes from true to false.
31+ // If check_bounds is true, it will CHECK that f(x_true) = true and
32+ // f(x_false) = false.
33+ //
3034// EXAMPLE:
3135// // Finds the value x in [0,Pi/2] such that cos(x)=2sin(x):
3236// BinarySearch<double>(/*x_true=*/0.0, /*x_false=*/M_PI/2,
3337// [](double x) { return cos(x) >= 2*sin(x); });
3438//
35- // Note that x_true > x_false is supported: it works either way.
39+ // MONOTONIC FUNCTIONS: Suppose f is a monotonic boolean function. See below for
40+ // the NON-MONOTONIC case.
3641//
37- // Ideally, f is a monotonic boolean function, such that:
38- // - f( x_true) = true
39- // - f(x_false ) = false
40- // - there exists X such that f(x)=true for all x between x_true and X, and
41- // f(x)=false for all x between X and x_false .
42+ // If x_true < x_false, this returns X such that:
43+ // - x_true < X < x_false,
44+ // - f((x_true, X] ) = true (i.e. for all x in (x_true, X], f(x) = true),
45+ // - f((X, x_false)) = false (i.e. for all x in ( X, x_false), f(x) = false)
46+ // or this returns x_true if such an X does not exist .
4247//
43- // In those conditions, this returns that value X (note that f(X) is true).
44- // See below for the NON-MONOTONIC case.
48+ // If x_true > x_false, this function returns X such that:
49+ // - x_false < X < x_true
50+ // - f((x_false, X)) = false
51+ // - f([X, x_true)) = true
52+ // or this return x_true if such an X does not exist.
4553//
4654// Also note that 'Point' may be floating-point types: the function will still
4755// converge when the midpoint can't be distinguished from one of the limits,
@@ -68,7 +76,7 @@ namespace operations_research {
6876// Note also that even if f() is non-deterministic, i.e. f(X) can sometimes
6977// return true and sometimes false for the same X, then the binary search will
7078// still finish, but it's hard to say anything about the returned X.
71- template <class Point >
79+ template <class Point , bool check_bounds = DEBUG_MODE >
7280Point BinarySearch (Point x_true, Point x_false, std::function<bool (Point)> f);
7381
7482// Used by BinarySearch(). This is just (x+y)/2, with some DCHECKs to catch
@@ -207,10 +215,12 @@ Point BinarySearchMidpoint(Point x, Point y) {
207215 return midpoint;
208216}
209217
210- template <class Point >
218+ template <class Point , bool check_bounds >
211219Point 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;
220+ if constexpr (check_bounds) {
221+ CHECK (f (x_true)) << x_true;
222+ CHECK (!f (x_false)) << x_false;
223+ }
214224 int num_iterations = 0 ;
215225 constexpr int kMaxNumIterations = 1000000 ;
216226 while (true ) {
0 commit comments