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