Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_sparse_table.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
69# ifndef TPL_SPARSE_TABLE_H
70# define TPL_SPARSE_TABLE_H
71
72# include <bit>
73# include <cassert>
74# include <cstdlib>
75# include <concepts>
76# include <functional>
77# include <initializer_list>
78# include <type_traits>
79# include <vector>
80# include <utility>
81# include <algorithm>
82# include <ah-concepts.H>
83# include <tpl_array.H>
84# include <tpl_dynList.H>
85# include <ahFunction.H>
86# include <ah-errors.H>
87
88namespace Aleph
89{
90 namespace sparse_table_detail
91 {
92 // Arithmetic functors: never idempotent over numbers other than bool.
93 template <typename F>
94 inline constexpr bool is_arithmetic_functor = false;
95
96 template <typename U>
97 inline constexpr bool is_arithmetic_functor<std::plus<U>> = true;
98 template <typename U>
99 inline constexpr bool is_arithmetic_functor<std::minus<U>> = true;
100 template <typename U>
101 inline constexpr bool is_arithmetic_functor<std::multiplies<U>> = true;
102 template <typename U>
103 inline constexpr bool is_arithmetic_functor<std::divides<U>> = true;
104 template <typename U>
105 inline constexpr bool is_arithmetic_functor<std::modulus<U>> = true;
106 template <typename U>
107 inline constexpr bool is_arithmetic_functor<std::bit_xor<U>> = true;
108 template <typename U>
109 inline constexpr bool is_arithmetic_functor<Aleph::plus<U>> = true;
110 template <typename U>
111 inline constexpr bool is_arithmetic_functor<Aleph::minus<U>> = true;
112 template <typename U>
113 inline constexpr bool is_arithmetic_functor<Aleph::multiplies<U>> = true;
114 template <typename U>
115 inline constexpr bool is_arithmetic_functor<Aleph::divides<U>> = true;
116 template <typename U>
117 inline constexpr bool is_arithmetic_functor<Aleph::modulus<U>> = true;
118 } // namespace sparse_table_detail
119
136 template <typename F, typename T>
137 inline constexpr bool is_known_non_idempotent_op =
138 sparse_table_detail::is_arithmetic_functor<std::remove_cvref_t<F>> and
139 std::is_arithmetic_v<std::remove_cv_t<T>> and
140 not std::is_same_v<std::remove_cv_t<T>, bool>;
141
155 template <typename F, typename T>
156 concept IdempotentOp =
158
167 template <typename F, typename T>
169
177 template <std::totally_ordered T>
178 struct Min_Op
179 {
180 constexpr T operator()(const T & a, const T & b) const noexcept
181 {
182 return a <= b ? a : b;
183 }
184 };
185
193 template <std::totally_ordered T>
194 struct Max_Op
195 {
196 constexpr T operator()(const T & a, const T & b) const noexcept
197 {
198 return a >= b ? a : b;
199 }
200 };
201
232 template <typename T, class Op>
233 requires SparseTableOp<Op, T>
235 {
236 Array<T> table; // flattened 2D: table[k * n + i]
237 Array<size_t> log_tbl; // log_tbl[len] = floor(log2(len)) for len in [1..n]
238 size_t n = 0; // number of logical elements
239 size_t levels = 0; // number of levels = floor(log2(n)) + 1
240
241 Op op;
242
244 T & at(const size_t k, const size_t i) { return table(k * n + i); }
245 const T & at(const size_t k, const size_t i) const { return table(k * n + i); }
246
248 static constexpr size_t compute_levels(const size_t nn) noexcept
249 {
250 return nn == 0 ? 0 : static_cast<size_t>(std::bit_width(nn));
251 }
252
254 static constexpr size_t compute_cells(const size_t nn) noexcept
255 {
256 return nn == 0 ? 1 : compute_levels(nn) * nn;
257 }
258
261 {
262 if (n == 0)
263 return;
264
266 log_tbl(0) = 0;
267 log_tbl(1) = 0;
268 for (size_t i = 2; i <= n; ++i)
269 log_tbl(i) = log_tbl(i / 2) + 1;
270 }
271
274 {
275 // table[k][i] = Op(table[k-1][i], table[k-1][i + 2^(k-1)])
276 for (size_t k = 1; k < levels; ++k)
277 {
278 const size_t half = size_t{1} << (k - 1);
279 const size_t limit = n - (size_t{1} << k) + 1;
280 for (size_t i = 0; i < limit; ++i)
281 at(k, i) = op(at(k - 1, i), at(k - 1, i + half));
282 }
283 }
284
286 template <class Getter>
288 {
289 // Level 0: intervals of length 1
290 for (size_t i = 0; i < n; ++i)
291 at(0, i) = getter(i);
292
294 }
295
297 template <class AlephIt>
299 {
300 size_t i = 0;
301 for (; it.has_curr(); it.next_ne())
302 at(0, i++) = it.get_curr();
303
305 }
306
307 public:
309 using Item_Type = T;
310
318 Gen_Sparse_Table(const size_t num, const T & init_val,
319 Op oper = Op())
320 : table(Array<T>::create(compute_cells(num))),
321 n(num), levels(compute_levels(num)), op(oper)
322 {
324 if (n > 0)
325 fill_and_build([&init_val](size_t) { return init_val; });
326 }
327
336 Gen_Sparse_Table(std::initializer_list<T> il, Op oper = Op())
337 : table(Array<T>::create(compute_cells(il.size()))),
339 {
341 if (n > 0)
342 {
343 auto it = il.begin();
344 fill_and_build([&it](size_t) { return *it++; });
345 }
346 }
347
354 : table(Array<T>::create(compute_cells(values.size()))),
356 {
358 if (n > 0)
359 fill_and_build([&values](size_t i) { return values(i); });
360 }
361
367 Gen_Sparse_Table(const std::vector<T> & values, Op oper = Op())
368 : table(Array<T>::create(compute_cells(values.size()))),
370 {
372 if (n > 0)
373 fill_and_build([&values](size_t i) { return values[i]; });
374 }
375
382 : table(Array<T>::create(compute_cells(values.size()))),
384 {
386 if (n > 0)
387 fill_from_aleph_it(values.get_it());
388 }
389
391
395
397
401
413 T query(const size_t l, const size_t r) const
414 {
416 << "Gen_Sparse_Table::query: r=" << r << " >= n=" << n;
418 << "Gen_Sparse_Table::query: l=" << l << " > r=" << r;
419
420 const size_t k = log_tbl(r - l + 1);
421 return op(at(k, l), at(k, r - (size_t{1} << k) + 1));
422 }
423
431 T get(const size_t i) const
432 {
434 << "Gen_Sparse_Table::get: index " << i << " >= size " << n;
435
436 return at(0, i);
437 }
438
440 [[nodiscard]] constexpr size_t size() const noexcept { return n; }
441
443 [[nodiscard]] constexpr bool is_empty() const noexcept { return n == 0; }
444
446 [[nodiscard]] constexpr size_t num_levels() const noexcept
447 {
448 return levels;
449 }
450
456 {
457 auto ret = Array<T>::create(n);
458 for (size_t i = 0; i < n; ++i)
459 ret(i) = at(0, i);
460 return ret;
461 }
462
464 void swap(Gen_Sparse_Table & other) noexcept
465 {
466 table.swap(other.table);
467 log_tbl.swap(other.log_tbl);
468 std::swap(n, other.n);
469 std::swap(levels, other.levels);
470 std::swap(op, other.op);
471 }
472 };
473
474
492 template <std::totally_ordered T>
494 : public Gen_Sparse_Table<T, Min_Op<T>>
495 {
497 using Base::Base; // inherit all constructors
498 };
499
517 template <std::totally_ordered T>
519 : public Gen_Sparse_Table<T, Max_Op<T>>
520 {
522 using Base::Base; // inherit all constructors
523 };
524
525} // end namespace Aleph
526
527# endif /* TPL_SPARSE_TABLE_H */
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:584
Standard functor implementations and comparison objects.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:196
void swap(Array &s) noexcept
Swap this with s
Definition tpl_array.H:232
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
Sparse Table over an arbitrary associative and idempotent binary operation.
void build_upper_levels()
Build levels k >= 1 from already-populated level 0.
T get(const size_t i) const
Retrieve the value a[i] in O(1).
constexpr size_t num_levels() const noexcept
Number of precomputed levels (floor(log2(n)) + 1).
Array< T > values() const
Reconstruct all original values into an Array.
void fill_and_build(Getter getter)
Fill level 0 from a 0-based indexed getter and build higher levels.
constexpr size_t size() const noexcept
Number of logical elements.
Gen_Sparse_Table(std::initializer_list< T > il, Op oper=Op())
Construct from an initializer list in O(n log n) time.
Gen_Sparse_Table(const std::vector< T > &values, Op oper=Op())
Construct from a std::vector<T> in O(n log n) time.
static constexpr size_t compute_cells(const size_t nn) noexcept
Number of flattened cells needed to store all levels.
T & at(const size_t k, const size_t i)
Access table[k][i] (0-based row k, 0-based column i).
void fill_from_aleph_it(AlephIt it)
Fill level 0 from an Aleph-style iterator and build higher levels.
Gen_Sparse_Table(const size_t num, const T &init_val, Op oper=Op())
Construct a sparse table with num elements, all equal to init_val.
Gen_Sparse_Table(const Gen_Sparse_Table &)=default
const T & at(const size_t k, const size_t i) const
static constexpr size_t compute_levels(const size_t nn) noexcept
Compute levels = floor(log2(n)) + 1; 0 if n == 0.
constexpr bool is_empty() const noexcept
True if the table contains no elements.
Gen_Sparse_Table(const DynList< T > &values, Op oper=Op())
Construct from a DynList<T> in O(n log n) time.
T query(const size_t l, const size_t r) const
Range query over [l, r] in O(1).
T Item_Type
The type of the element stored in the table.
void swap(Gen_Sparse_Table &other) noexcept
Swap this table with other in O(1).
Gen_Sparse_Table(Gen_Sparse_Table &&) noexcept(std::is_nothrow_move_constructible_v< Array< T > > &&std::is_nothrow_move_constructible_v< Op >)=default
void build_log_table()
Precompute the log lookup table for lengths [0..n].
Gen_Sparse_Table(const Array< T > &values, Op oper=Op())
Construct from an Array<T> in O(n log n) time.
A binary functor closed over T.
A closed binary operation not known to break idempotency.
Binary operation compatible with Sparse Table queries.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
constexpr bool is_arithmetic_functor
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
constexpr bool is_known_non_idempotent_op
True if F is known not to be idempotent over T.
STL namespace.
Functor returning the maximum of two values.
constexpr T operator()(const T &a, const T &b) const noexcept
Sparse Table for range maximum queries.
Functor returning the minimum of two values.
constexpr T operator()(const T &a, const T &b) const noexcept
Sparse Table for range minimum queries.
static int * k
gsl_rng * r
Dynamic array container with automatic resizing.
Alias for htlist.H (DynList implementation).
DynList< int > l