Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
range_query_function.cc
Go to the documentation of this file.
1// Copyright 2010-2024 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/types.h"
25
26namespace operations_research {
27namespace {
28// This implementation basically calls the function as many times as needed for
29// each query.
30class LinearRangeIntToIntFunction : public RangeIntToIntFunction {
31 public:
32 explicit LinearRangeIntToIntFunction(
33 std::function<int64_t(int64_t)> base_function)
34 : base_function_(std::move(base_function)) {}
35
36 // This type is neither copyable nor movable.
37 LinearRangeIntToIntFunction(const LinearRangeIntToIntFunction&) = delete;
38 LinearRangeIntToIntFunction& operator=(const LinearRangeIntToIntFunction&) =
39 delete;
40
41 int64_t Query(int64_t argument) const override {
42 return base_function_(argument);
43 }
44
45 int64_t RangeMin(int64_t range_begin, int64_t range_end) const override {
46 DCHECK_LT(range_begin, range_end);
47 int64_t min_val = kint64max;
48 for (int64_t i = range_begin; i < range_end; ++i) {
49 min_val = std::min(min_val, base_function_(i));
50 }
51 return min_val;
52 }
53
54 int64_t RangeMax(int64_t range_begin, int64_t range_end) const override {
55 DCHECK_LT(range_begin, range_end);
56 int64_t max_val = kint64min;
57 for (int64_t i = range_begin; i < range_end; ++i) {
58 max_val = std::max(max_val, base_function_(i));
59 }
60 return max_val;
61 }
62
63 int64_t RangeFirstInsideInterval(int64_t range_begin, int64_t range_end,
64 int64_t interval_begin,
65 int64_t interval_end) const override {
66 // domain_start_ <= range_begin < range_end <= domain_start_+array().size()
67 DCHECK_LT(range_begin, range_end);
68 DCHECK_LT(interval_begin, interval_end);
69 int64_t i = range_begin;
70 for (; i < range_end; ++i) {
71 const int64_t value = base_function_(i);
72 if (interval_begin <= value && value < interval_end) break;
73 }
74 return i;
75 }
76
77 int64_t RangeLastInsideInterval(int64_t range_begin, int64_t range_end,
78 int64_t interval_begin,
79 int64_t interval_end) const override {
80 // domain_start_ <= range_begin < range_end <= domain_start_+array().size()
81 DCHECK_NE(range_begin, kint64max);
82 DCHECK_LT(range_begin, range_end);
83 DCHECK_LT(interval_begin, interval_end);
84 int64_t i = range_end - 1;
85 for (; i >= range_begin; --i) {
86 const int64_t value = base_function_(i);
87 if (interval_begin <= value && value < interval_end) break;
88 }
89 return i;
90 }
91
92 private:
93 std::function<int64_t(int64_t)> base_function_;
94};
95
96std::vector<int64_t> FunctionToVector(const std::function<int64_t(int64_t)>& f,
97 int64_t domain_start,
98 int64_t domain_end) {
99 CHECK_LT(domain_start, domain_end);
100 std::vector<int64_t> output(domain_end - domain_start, 0);
101 for (int64_t i = 0; i < domain_end - domain_start; ++i) {
102 output[i] = f(i + domain_start);
103 }
104 return output;
105}
106
107// This implementation caches the underlying function and improves on the
108// non-cached version in two ways:
109// 1. It caches the values returned by the function.
110// 2. It creates a data structure for quick answer to range queries.
111class CachedRangeIntToIntFunction : public RangeIntToIntFunction {
112 public:
113 CachedRangeIntToIntFunction(
114 const std::function<int64_t(int64_t)>& base_function,
115 int64_t domain_start, int64_t domain_end)
116 : domain_start_(domain_start),
117 rmq_min_(FunctionToVector(base_function, domain_start, domain_end)),
118 rmq_max_(rmq_min_.array()) {
119 CHECK_LT(domain_start, domain_end);
120 }
121
122 // This type is neither copyable nor movable.
123 CachedRangeIntToIntFunction(const CachedRangeIntToIntFunction&) = delete;
124 CachedRangeIntToIntFunction& operator=(const CachedRangeIntToIntFunction&) =
125 delete;
126
127 int64_t Query(int64_t argument) const override {
128 DCHECK_LE(domain_start_, argument);
129 DCHECK_LE(argument, domain_start_ + static_cast<int64_t>(array().size()));
130 return array()[argument - domain_start_];
131 }
132 int64_t RangeMin(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_min_.GetMinimumFromRange(from - domain_start_,
137 to - domain_start_);
138 }
139 int64_t RangeMax(int64_t from, int64_t to) const override {
140 DCHECK_LE(domain_start_, from);
141 DCHECK_LT(from, to);
142 DCHECK_LE(to, domain_start_ + static_cast<int64_t>(array().size()));
143 return rmq_max_.GetMinimumFromRange(from - domain_start_,
144 to - domain_start_);
145 }
146 int64_t RangeFirstInsideInterval(int64_t range_begin, int64_t range_end,
147 int64_t interval_begin,
148 int64_t interval_end) const override {
149 // domain_start_ <= range_begin < range_end <= domain_start_+array().size()
150 DCHECK_LE(domain_start_, range_begin);
151 DCHECK_LT(range_begin, range_end);
152 DCHECK_LE(range_end, domain_start_ + array().size());
153 DCHECK_LT(interval_begin, interval_end);
154 int64_t i = range_begin;
155 for (; i < range_end; ++i) {
156 const int64_t value = array()[i - domain_start_];
157 if (interval_begin <= value && value < interval_end) break;
158 }
159 return i;
160 }
161 int64_t RangeLastInsideInterval(int64_t range_begin, int64_t range_end,
162 int64_t interval_begin,
163 int64_t interval_end) const override {
164 // domain_start_ <= range_begin < range_end <= domain_start_+array().size()
165 DCHECK_LE(domain_start_, range_begin);
166 DCHECK_LT(range_begin, range_end);
167 DCHECK_LE(range_end, domain_start_ + array().size());
168 DCHECK_LT(interval_begin, interval_end);
169 int64_t i = range_end - 1;
170 for (; i >= range_begin; --i) {
171 const int64_t value = array()[i - domain_start_];
172 if (interval_begin <= value && value < interval_end) break;
173 }
174 return i;
175 }
176
177 private:
178 const std::vector<int64_t>& array() const { return rmq_min_.array(); }
179
180 const int64_t domain_start_;
181 const RangeMinimumQuery<int64_t, std::less<int64_t>> rmq_min_;
182 const RangeMinimumQuery<int64_t, std::greater<int64_t>> rmq_max_;
183};
184
185class CachedRangeMinMaxIndexFunction : public RangeMinMaxIndexFunction {
186 public:
187 CachedRangeMinMaxIndexFunction(const std::function<int64_t(int64_t)>& f,
188 int64_t domain_start, int64_t domain_end)
189 : domain_start_(domain_start),
190 domain_end_(domain_end),
191 index_rmq_min_(FunctionToVector(f, domain_start, domain_end)),
192 index_rmq_max_(index_rmq_min_.array()) {
193 CHECK_LT(domain_start, domain_end);
194 }
195
196 // This type is neither copyable nor movable.
197 CachedRangeMinMaxIndexFunction(const CachedRangeMinMaxIndexFunction&) =
198 delete;
199 CachedRangeMinMaxIndexFunction& operator=(
200 const CachedRangeMinMaxIndexFunction&) = delete;
201
202 inline int64_t RangeMinArgument(int64_t from, int64_t to) const override {
203 DCHECK_LE(domain_start_, from);
204 DCHECK_LT(from, to);
205 DCHECK_LE(to, domain_end_);
206 return index_rmq_min_.GetMinimumIndexFromRange(from - domain_start_,
207 to - domain_start_) +
208 domain_start_;
209 }
210 inline int64_t RangeMaxArgument(int64_t from, int64_t to) const override {
211 DCHECK_LE(domain_start_, from);
212 DCHECK_LT(from, to);
213 DCHECK_LE(to, domain_end_);
214 return index_rmq_max_.GetMinimumIndexFromRange(from - domain_start_,
215 to - domain_start_) +
216 domain_start_;
217 }
218
219 private:
220 const int64_t domain_start_;
221 const int64_t domain_end_;
222 const RangeMinimumIndexQuery<int64_t, std::less<int64_t>> index_rmq_min_;
223 const RangeMinimumIndexQuery<int64_t, std::greater<int64_t>> index_rmq_max_;
224};
225} // namespace
226
228 std::function<int64_t(int64_t)> f) {
229 return new LinearRangeIntToIntFunction(std::move(f));
230}
231
233 const std::function<int64_t(int64_t)>& f, int64_t domain_start,
234 int64_t domain_end) {
235 return new CachedRangeIntToIntFunction(f, domain_start, domain_end);
236}
237
239 const std::function<int64_t(int64_t)>& f, int64_t domain_start,
240 int64_t domain_end) {
241 return new CachedRangeMinMaxIndexFunction(f, domain_start, domain_end);
242}
243} // namespace operations_research
IntegerValue size
int64_t value
In SWIG mode, we don't want anything besides these top-level includes.
RangeIntToIntFunction * MakeCachedIntToIntFunction(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)
RangeMinMaxIndexFunction * MakeCachedRangeMinMaxIndexFunction(const std::function< int64_t(int64_t)> &f, int64_t domain_start, int64_t domain_end)
STL namespace.
trees with all degrees equal to
static const int64_t kint64max
Definition types.h:32
static const int64_t kint64min
Definition types.h:31