OR-Tools  9.1
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
20#include "ortools/base/macros.h"
22
23namespace operations_research {
24namespace {
25// This implementation basically calls the function as many times as needed for
26// each query.
27class 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
90std::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.
105class 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
176class 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:888
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:887
#define CHECK_LT(val1, val2)
Definition: base/logging.h:701
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:889
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)
STL namespace.