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