QPot 0.12.2.dev1+g4043351
QPot.h
Go to the documentation of this file.
1
7#ifndef QPOT_H
8#define QPOT_H
9
10#include <algorithm>
11#include <stdexcept>
12#include <string>
13
17#define Q(x) #x
18#define QUOTE(x) Q(x)
19
20#define QPOT_WARNING_IMPL(message, file, line, function) \
21 std::cout << std::string(file) + ":" + std::to_string(line) + " (" + std::string(function) + \
22 ")" + ": " message ") \n\t";
23
24#define QPOT_ASSERT_IMPL(expr, file, line, function) \
25 if (!(expr)) { \
26 throw std::runtime_error( \
27 std::string(file) + ":" + std::to_string(line) + " (" + std::string(function) + ")" + \
28 ": assertion failed (" #expr ") \n\t"); \
29 }
51#ifdef QPOT_ENABLE_ASSERT
52#define QPOT_ASSERT(expr) QPOT_ASSERT_IMPL(expr, __FILE__, __LINE__, __FUNCTION__)
53#else
54#define QPOT_ASSERT(expr)
55#endif
56
70#ifdef QPOT_ENABLE_DEBUG
71#define QPOT_DEBUG(expr) QPOT_ASSERT_IMPL(expr, __FILE__, __LINE__, __FUNCTION__)
72#else
73#define QPOT_DEBUG(expr)
74#endif
75
81#define QPOT_REQUIRE(expr) QPOT_ASSERT_IMPL(expr, __FILE__, __LINE__, __FUNCTION__)
82
92#ifdef QPOT_ENABLE_WARNING_PYTHON
93#define QPOT_WARNING_PYTHON(message) QPOT_WARNING_IMPL(message, __FILE__, __LINE__, __FUNCTION__)
94#else
95#define QPOT_WARNING_PYTHON(message)
96#endif
97
117#ifndef QPOT_VERSION
118#define QPOT_VERSION "@PROJECT_VERSION@"
119#endif
120
124namespace QPot {
125
126namespace detail {
127
128inline std::string unquote(const std::string& arg)
129{
130 std::string ret = arg;
131 ret.erase(std::remove(ret.begin(), ret.end(), '\"'), ret.end());
132 return ret;
133}
134
135} // namespace detail
136
144inline std::string version()
145{
146 return detail::unquote(std::string(QUOTE(QPOT_VERSION)));
147}
148
159inline std::vector<std::string> version_dependencies()
160{
161 std::vector<std::string> ret;
162
163 ret.push_back("qpot=" + version());
164
165 ret.push_back(
166 "xtensor=" + detail::unquote(std::string(QUOTE(XTENSOR_VERSION_MAJOR))) + "." +
167 detail::unquote(std::string(QUOTE(XTENSOR_VERSION_MINOR))) + "." +
168 detail::unquote(std::string(QUOTE(XTENSOR_VERSION_PATCH))));
169
170#ifdef XSIMD_VERSION_MAJOR
171 ret.push_back(
172 "xsimd=" + detail::unquote(std::string(QUOTE(XSIMD_VERSION_MAJOR))) + "." +
173 detail::unquote(std::string(QUOTE(XSIMD_VERSION_MINOR))) + "." +
174 detail::unquote(std::string(QUOTE(XSIMD_VERSION_PATCH))));
175#endif
176
177#ifdef XTL_VERSION_MAJOR
178 ret.push_back(
179 "xtl=" + detail::unquote(std::string(QUOTE(XTL_VERSION_MAJOR))) + "." +
180 detail::unquote(std::string(QUOTE(XTL_VERSION_MINOR))) + "." +
181 detail::unquote(std::string(QUOTE(XTL_VERSION_PATCH))));
182#endif
183
184#if defined(XTENSOR_PYTHON_VERSION_MAJOR)
185 ret.push_back(
186 "xtensor-python=" + detail::unquote(std::string(QUOTE(XTENSOR_PYTHON_VERSION_MAJOR))) +
187 "." + detail::unquote(std::string(QUOTE(XTENSOR_PYTHON_VERSION_MINOR))) + "." +
188 detail::unquote(std::string(QUOTE(XTENSOR_PYTHON_VERSION_PATCH))));
189#endif
190
191 std::sort(ret.begin(), ret.end(), std::greater<std::string>());
192
193 return ret;
194}
195
196namespace iterator {
197
212template <class It, class T, class R = size_t>
213inline R
214lower_bound(const It first, const It last, const T& value, R guess = 0, size_t proximity = 10)
215{
216 if (proximity == 0) {
217 if (value <= *(first)) {
218 return 0;
219 }
220 return std::lower_bound(first, last, value) - first - 1;
221 }
222
223 if (*(first + guess) < value && value <= *(first + guess + 1)) {
224 return guess;
225 }
226
227 size_t l = guess > proximity ? guess - proximity : 0;
228 size_t r = std::min(guess + proximity, static_cast<size_t>(last - first - 1));
229
230 if (*(first + l) < value && *(first + r) >= value) {
231 return std::lower_bound(first + l, first + r, value) - first - 1;
232 }
233 else if (value <= *(first)) {
234 return 0;
235 }
236 else {
237 return std::lower_bound(first, last, value) - first - 1;
238 }
239}
240
241} // namespace iterator
242
243namespace inplace {
244
253template <class T, class V, class R>
254inline void lower_bound(const T& matrix, const V& value, R& index, size_t proximity = 10)
255{
256 QPOT_ASSERT(value.dimension() == matrix.dimension() - 1);
257 QPOT_ASSERT(value.dimension() == index.dimension());
258
259 auto nd = value.dimension();
260 auto stride = matrix.shape(nd);
261 auto n = value.size();
262
263#ifdef QPOT_ENABLE_ASSERT
264 for (decltype(nd) i = 0; i < nd; ++i) {
265 QPOT_ASSERT(matrix.shape(i) == value.shape(i));
266 QPOT_ASSERT(matrix.shape(i) == index.shape(i));
267 }
268#endif
269
270 for (decltype(n) i = 0; i < n; ++i) {
271 index.flat(i) = iterator::lower_bound(
272 &matrix.flat(i * stride),
273 &matrix.flat(i * stride) + stride,
274 value.flat(i),
275 index.flat(i),
276 proximity);
277 }
278}
279
287template <class V, class I>
288inline void cumsum_chunk(V& cumsum, const V& delta, const I& shift)
289{
290 QPOT_ASSERT(cumsum.dimension() >= 1);
291 QPOT_ASSERT(cumsum.dimension() == delta.dimension());
292
293 if (delta.size() == 0) {
294 return;
295 }
296
297 size_t dim = cumsum.dimension();
298 size_t n = cumsum.shape(dim - 1);
299 size_t ndelta = delta.shape(dim - 1);
300
301 for (size_t i = 0; i < shift.size(); ++i) {
302
303 if (shift.flat(i) == 0) {
304 continue;
305 }
306
307 auto* d = &delta.flat(i * ndelta);
308 auto* c = &cumsum.flat(i * n);
309
310 if (shift.flat(i) > 0) {
311 QPOT_ASSERT(shift.flat(i) <= n);
312 QPOT_ASSERT(ndelta >= shift.flat(i));
313 size_t nadd = static_cast<size_t>(shift.flat(i));
314 size_t nkeep = n - nadd;
315 auto offset = *(c + n - 1);
316 std::copy(c + n - nkeep, c + n, c);
317 std::copy(d, d + nadd, c + nkeep);
318 *(c + nkeep) += offset;
319 std::partial_sum(c + nkeep, c + n, c + nkeep);
320 }
321 else {
322 QPOT_ASSERT(-shift.flat(i) < n);
323 QPOT_ASSERT(ndelta > -shift.flat(i));
324 size_t nadd = static_cast<size_t>(-shift.flat(i));
325 size_t nkeep = n - nadd;
326 auto offset = *(c);
327 std::copy(c, c + nkeep, c + nadd);
328 std::copy(d, d + nadd + 1, c);
329 std::partial_sum(c, c + nadd + 1, c);
330 offset -= *(c + nadd);
331 std::transform(c, c + nadd + 1, c, [&](auto& v) { return v + offset; });
332 }
333 }
334}
335
336} // namespace inplace
337
352template <class T, class V, class R>
353inline R lower_bound(const T& matrix, const V& value, const R& index, size_t proximity = 10)
354{
355 R ret = index;
356 inplace::lower_bound(matrix, value, ret, proximity);
357 return ret;
358}
359
369template <class T, class V, class R>
370inline R lower_bound(const T& matrix, const V& value)
371{
372 R ret = xt::zeros<typename R::value_type>(value.shape());
373 inplace::lower_bound(matrix, value, ret, 0);
374 return ret;
375}
376
413template <class V, class I>
414inline V cumsum_chunk(const V& cumsum, const V& delta, const I& shift)
415{
416 V ret = cumsum;
417 inplace::cumsum_chunk(ret, delta, shift);
418 return ret;
419}
420
421} // namespace QPot
422
423#endif
#define QPOT_ASSERT(expr)
All assertions are implemented as:
Definition: QPot.h:54
#define QPOT_VERSION
Current version.
Definition: QPot.h:118
Function to find items in an increase range, and to store this range in chunks.
Definition: QPot.h:124
R lower_bound(const T &matrix, const V &value)
Iterating on the last axis of an nd-array (e.g.
Definition: QPot.h:370
std::string version()
Return version string, e.g.
Definition: QPot.h:144
std::vector< std::string > version_dependencies()
Return versions of this library and of all of its dependencies.
Definition: QPot.h:159
R lower_bound(const T &matrix, const V &value, const R &index, size_t proximity=10)
Iterating on the last axis of an nd-array (e.g.
Definition: QPot.h:353
V cumsum_chunk(const V &cumsum, const V &delta, const I &shift)
Update the chunk of a cumsum computed and stored in chunks.
Definition: QPot.h:414