OR-Tools  9.0
range_query_function.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 
15 
16 #include <memory>
17 
19 #include "ortools/base/logging.h"
20 #include "ortools/base/macros.h"
22 
23 namespace operations_research {
24 namespace {
25 // This implementation basically calls the function as many times as needed for
26 // each query.
27 class LinearRangeIntToIntFunction : public RangeIntToIntFunction {
28  public:
29  explicit LinearRangeIntToIntFunction(
30  std::function<int64_t(int64_t)> base_function)
31  : base_function_(std::move(base_function)) {}
32 
33  int64_t Query(int64_t argument) const override {
34  return base_function_(argument);
35  }
36 
37  int64_t RangeMin(int64_t range_begin, int64_t range_end) const override {
38  DCHECK_LT(range_begin, range_end);
39  int64_t min_val = kint64max;
40  for (int64_t i = range_begin; i < range_end; ++i) {
41  min_val = std::min(min_val, base_function_(i));
42  }
43  return min_val;
44  }
45 
46  int64_t RangeMax(int64_t range_begin, int64_t range_end) const override {
47  DCHECK_LT(range_begin, range_end);
48  int64_t max_val = kint64min;
49  for (int64_t i = range_begin; i < range_end; ++i) {
50  max_val = std::max(max_val, base_function_(i));
51  }
52  return max_val;
53  }
54 
55  int64_t RangeFirstInsideInterval(int64_t range_begin, int64_t range_end,
56  int64_t interval_begin,
57  int64_t interval_end) const override {
58  // domain_start_ <= range_begin < range_end <= domain_start_+array().size()
59  DCHECK_LT(range_begin, range_end);
60  DCHECK_LT(interval_begin, interval_end);
61  int64_t i = range_begin;
62  for (; i < range_end; ++i) {
63  const int64_t value = base_function_(i);
64  if (interval_begin <= value && value < interval_end) break;
65  }
66  return i;
67  }
68 
69  int64_t RangeLastInsideInterval(int64_t range_begin, int64_t range_end,
70  int64_t interval_begin,
71  int64_t interval_end) const override {
72  // domain_start_ <= range_begin < range_end <= domain_start_+array().size()
73  DCHECK_NE(range_begin, kint64max);
74  DCHECK_LT(range_begin, range_end);
75  DCHECK_LT(interval_begin, interval_end);
76  int64_t i = range_end - 1;
77  for (; i >= range_begin; --i) {
78  const int64_t value = base_function_(i);
79  if (interval_begin <= value && value < interval_end) break;
80  }
81  return i;
82  }
83 
84  private:
85  std::function<int64_t(int64_t)> base_function_;
86 
87  DISALLOW_COPY_AND_ASSIGN(LinearRangeIntToIntFunction);
88 };
89 
90 std::vector<int64_t> FunctionToVector(const std::function<int64_t(int64_t)>& f,
91  int64_t domain_start,
92  int64_t domain_end) {
93  CHECK_LT(domain_start, domain_end);
94  std::vector<int64_t> output(domain_end - domain_start, 0);
95  for (int64_t i = 0; i < domain_end - domain_start; ++i) {
96  output[i] = f(i + domain_start);
97  }
98  return output;
99 }
100 
101 // This implementation caches the underlying function and improves on the
102 // non-cached version in two ways:
103 // 1. It caches the values returned by the function.
104 // 2. It creates a data structure for quick answer to range queries.
105 class CachedRangeIntToIntFunction : public RangeIntToIntFunction {
106  public:
107  CachedRangeIntToIntFunction(
108  const std::function<int64_t(int64_t)>& base_function,
109  int64_t domain_start, int64_t domain_end)
110  : domain_start_(domain_start),
111  rmq_min_(FunctionToVector(base_function, domain_start, domain_end)),
112  rmq_max_(rmq_min_.array()) {
113  CHECK_LT(domain_start, domain_end);
114  }
115 
116  int64_t Query(int64_t argument) const override {
117  DCHECK_LE(domain_start_, argument);
118  DCHECK_LE(argument, domain_start_ + static_cast<int64_t>(array().size()));
119  return array()[argument - domain_start_];
120  }
121  int64_t RangeMin(int64_t from, int64_t to) const override {
122  DCHECK_LE(domain_start_, from);
123  DCHECK_LT(from, to);
124  DCHECK_LE(to, domain_start_ + static_cast<int64_t>(array().size()));
125  return rmq_min_.GetMinimumFromRange(from - domain_start_,
126  to - domain_start_);
127  }
128  int64_t RangeMax(int64_t from, int64_t to) const override {
129  DCHECK_LE(domain_start_, from);
130  DCHECK_LT(from, to);
131  DCHECK_LE(to, domain_start_ + static_cast<int64_t>(array().size()));
132  return rmq_max_.GetMinimumFromRange(from - domain_start_,
133  to - domain_start_);
134  }
135  int64_t RangeFirstInsideInterval(int64_t range_begin, int64_t range_end,
136  int64_t interval_begin,
137  int64_t interval_end) const override {
138  // domain_start_ <= range_begin < range_end <= domain_start_+array().size()
139  DCHECK_LE(domain_start_, range_begin);
140  DCHECK_LT(range_begin, range_end);
141  DCHECK_LE(range_end, domain_start_ + array().size());
142  DCHECK_LT(interval_begin, interval_end);
143  int64_t i = range_begin;
144  for (; i < range_end; ++i) {
145  const int64_t value = array()[i - domain_start_];
146  if (interval_begin <= value && value < interval_end) break;
147  }
148  return i;
149  }
150  int64_t RangeLastInsideInterval(int64_t range_begin, int64_t range_end,
151  int64_t interval_begin,
152  int64_t interval_end) const override {
153  // domain_start_ <= range_begin < range_end <= domain_start_+array().size()
154  DCHECK_LE(domain_start_, range_begin);
155  DCHECK_LT(range_begin, range_end);
156  DCHECK_LE(range_end, domain_start_ + array().size());
157  DCHECK_LT(interval_begin, interval_end);
158  int64_t i = range_end - 1;
159  for (; i >= range_begin; --i) {
160  const int64_t value = array()[i - domain_start_];
161  if (interval_begin <= value && value < interval_end) break;
162  }
163  return i;
164  }
165 
166  private:
167  const std::vector<int64_t>& array() const { return rmq_min_.array(); }
168 
169  const int64_t domain_start_;
170  const RangeMinimumQuery<int64_t, std::less<int64_t>> rmq_min_;
171  const RangeMinimumQuery<int64_t, std::greater<int64_t>> rmq_max_;
172 
173  DISALLOW_COPY_AND_ASSIGN(CachedRangeIntToIntFunction);
174 };
175 
176 class CachedRangeMinMaxIndexFunction : public RangeMinMaxIndexFunction {
177  public:
178  CachedRangeMinMaxIndexFunction(const std::function<int64_t(int64_t)>& f,
179  int64_t domain_start, int64_t domain_end)
180  : domain_start_(domain_start),
181  domain_end_(domain_end),
182  index_rmq_min_(FunctionToVector(f, domain_start, domain_end)),
183  index_rmq_max_(index_rmq_min_.array()) {
184  CHECK_LT(domain_start, domain_end);
185  }
186 
187  inline int64_t RangeMinArgument(int64_t from, int64_t to) const override {
188  DCHECK_LE(domain_start_, from);
189  DCHECK_LT(from, to);
190  DCHECK_LE(to, domain_end_);
191  return index_rmq_min_.GetMinimumIndexFromRange(from - domain_start_,
192  to - domain_start_) +
193  domain_start_;
194  }
195  inline int64_t RangeMaxArgument(int64_t from, int64_t to) const override {
196  DCHECK_LE(domain_start_, from);
197  DCHECK_LT(from, to);
198  DCHECK_LE(to, domain_end_);
199  return index_rmq_max_.GetMinimumIndexFromRange(from - domain_start_,
200  to - domain_start_) +
201  domain_start_;
202  }
203 
204  private:
205  const int64_t domain_start_;
206  const int64_t domain_end_;
207  const RangeMinimumIndexQuery<int64_t, std::less<int64_t>> index_rmq_min_;
208  const RangeMinimumIndexQuery<int64_t, std::greater<int64_t>> index_rmq_max_;
209 
210  DISALLOW_COPY_AND_ASSIGN(CachedRangeMinMaxIndexFunction);
211 };
212 } // namespace
213 
215  std::function<int64_t(int64_t)> f) {
216  return new LinearRangeIntToIntFunction(std::move(f));
217 }
218 
220  const std::function<int64_t(int64_t)>& f, int64_t domain_start,
221  int64_t domain_end) {
222  return new CachedRangeIntToIntFunction(f, domain_start, domain_end);
223 }
224 
226  const std::function<int64_t(int64_t)>& f, int64_t domain_start,
227  int64_t domain_end) {
228  return new CachedRangeMinMaxIndexFunction(f, domain_start, domain_end);
229 }
230 } // 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:895
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:894
#define CHECK_LT(val1, val2)
Definition: base/logging.h:708
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:896
int64_t value
static const int64_t kint64max
static const int64_t kint64min
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:29
Collection of objects used to extend the Constraint Solver library.
RangeIntToIntFunction * MakeCachedIntToIntFunction(const std::function< int64_t(int64_t)> &f, int64_t domain_start, int64_t domain_end)
RangeMinMaxIndexFunction * MakeCachedRangeMinMaxIndexFunction(const std::function< int64_t(int64_t)> &f, int64_t domain_start, int64_t domain_end)
RangeIntToIntFunction * MakeBareIntToIntFunction(std::function< int64_t(int64_t)> f)