70#include <pixie/memory_usage.h>
71#include <pixie/rmm/btree.h>
73#include <pixie/rmq/utils/succinct_monotone_stack.h>
102template <
class Index = std::size_t,
103 std::size_t HighCacheLines = 4,
104 std::size_t LowFanout = 32>
105class RmMPlusMinusOne {
107 static_assert(std::is_unsigned_v<Index>,
108 "RmMPlusMinusOne index type must be unsigned");
110 static constexpr std::size_t npos = std::numeric_limits<std::size_t>::max();
111 static constexpr Index invalid_index = std::numeric_limits<Index>::max();
112 static constexpr std::size_t kBlockSize =
113 pixie::experimental::RmMBTree<HighCacheLines, LowFanout>::kBlockBits;
115 RmMPlusMinusOne() =
default;
126 std::size_t depth_count) {
127 build(bits, depth_count);
137 std::size_t depth_count,
138 std::size_t one_count) {
139 build(bits, depth_count, one_count);
145 void build(std::span<const std::uint64_t> bits, std::size_t depth_count) {
146 build(bits, depth_count, std::nullopt);
152 void build(std::span<const std::uint64_t> bits,
153 std::size_t depth_count,
154 std::optional<std::size_t> one_count) {
156 depth_count_ = depth_count;
159 if (depth_count_ == 0) {
162 if (depth_count_ >
static_cast<std::size_t
>(invalid_index)) {
163 throw std::length_error(
"RMQ rmM btree index type is too small");
165 rmm_ = RmM(words_, depth_count_ - 1,
166 RankSelectSupport<>::SelectSupport::kSelect0, one_count);
172 std::size_t
size()
const {
return depth_count_; }
177 bool empty()
const {
return depth_count_ == 0; }
185 std::size_t
arg_min(std::size_t left, std::size_t right)
const {
186 if (left >= right || right > depth_count_) {
189 if (right == left + 1) {
193 const std::size_t bit_left = left;
194 const std::size_t bit_right = right - 2;
195 const auto minimum_after_left =
196 rmm_.range_min_query_result(bit_left, bit_right);
197 if (minimum_after_left.value >= 0) {
201 const std::size_t bit_position = minimum_after_left.position;
202 return bit_position == RmM::npos ? npos : bit_position + 1;
208 std::size_t
select0(std::size_t rank)
const {
return rmm_.select0(rank); }
213 std::size_t
rank0(std::size_t end_position)
const {
214 return rmm_.rank0(end_position);
224 return sizeof(*this) + pixie::nested_owned_memory_bytes(rmm_);
230 std::span<const std::uint64_t> words_;
231 std::size_t depth_count_ = 0;
251 class Compare = std::less<T>,
252 class Index = std::size_t,
253 std::size_t HighCacheLines = 4,
254 std::size_t LowFanout = 32>
256 :
public RmqBase<CartesianRmM<T, Compare, Index, HighCacheLines, LowFanout>,
259 static_assert(std::is_unsigned_v<Index>,
260 "CartesianRmM index type must be unsigned");
262 static constexpr std::size_t npos =
265 static constexpr Index invalid_index = std::numeric_limits<Index>::max();
267 CartesianRmM() =
default;
275 explicit CartesianRmM(std::span<const T> values, Compare compare = Compare())
276 : values_(values), compare_(compare) {
281 : values_(other.values_),
282 compare_(other.compare_),
283 bp_bits_(other.bp_bits_),
284 bp_bit_count_(other.bp_bit_count_) {
288 CartesianRmM& operator=(
const CartesianRmM& other) {
289 if (
this == &other) {
292 values_ = other.values_;
293 compare_ = other.compare_;
294 bp_bits_ = other.bp_bits_;
295 bp_bit_count_ = other.bp_bit_count_;
300 CartesianRmM(CartesianRmM&& other) noexcept
301 : values_(other.values_),
302 compare_(std::move(other.compare_)),
303 bp_bits_(std::move(other.bp_bits_)),
304 bp_bit_count_(other.bp_bit_count_) {
305 other.values_ = std::span<const T>();
306 other.bp_bit_count_ = 0;
310 CartesianRmM& operator=(CartesianRmM&& other)
noexcept {
311 if (
this == &other) {
314 values_ = other.values_;
315 compare_ = std::move(other.compare_);
316 bp_bits_ = std::move(other.bp_bits_);
317 bp_bit_count_ = other.bp_bit_count_;
318 other.values_ = std::span<const T>();
319 other.bp_bit_count_ = 0;
327 std::size_t
size_impl()
const {
return values_.size(); }
338 if (left >= right || right > values_.size()) {
341 const std::size_t first_close = bp_support_.select0(left + 1);
342 const std::size_t last_close = bp_support_.select0(right);
343 if (first_close == BpSupport::npos || last_close == BpSupport::npos ||
344 first_close > last_close) {
348 const std::size_t shifted_min =
349 bp_support_.arg_min(first_close + 1, last_close + 2);
350 if (shifted_min == npos || shifted_min == 0) {
353 const std::size_t answer = bp_support_.rank0(shifted_min) - 1;
354 return answer < values_.size() ? answer : npos;
365 std::span<const std::uint64_t>
bp_words()
const {
return bp_bits_; }
375 return sizeof(*this) + pixie::vector_capacity_bytes(bp_bits_) +
376 pixie::nested_owned_memory_bytes(bp_support_);
385 bp_support_ = BpSupport();
387 if (values_.empty()) {
390 if (values_.size() > (
static_cast<std::size_t
>(invalid_index) - 1) / 2) {
391 throw std::length_error(
"Cartesian rmM RMQ index type is too small");
394 bp_bit_count_ = 2 * values_.size();
395 bp_bits_.assign((bp_bit_count_ + 63) / 64, 0);
400 void build_bp_bits() {
401 utils::SuccinctIncreasingStack stack(values_.size());
402 std::size_t write_position = bp_bit_count_;
403 std::vector<std::uint64_t>& words = bp_bits_;
404 const auto prepend_open = [&]() {
406 words[write_position >> 6] |= std::uint64_t{1} << (write_position & 63);
409 for (std::size_t i = values_.size(); i-- > 0;) {
410 while (!stack.empty() &&
411 !compare_(values_[stack_index(stack.top())], values_[i])) {
415 stack.push(stack_key(i));
419 while (write_position != 0) {
428 std::size_t stack_key(std::size_t value_index)
const {
429 return values_.size() - 1 - value_index;
436 std::size_t stack_index(std::size_t key)
const {
437 return values_.size() - 1 - key;
440 void reset_bp_index() {
441 bp_support_ = BpSupport();
442 if (bp_bit_count_ == 0) {
445 bp_support_ = BpSupport(std::span<const std::uint64_t>(bp_bits_),
446 bp_bit_count_ + 1, values_.size());
449 std::span<const T> values_;
451 std::vector<std::uint64_t> bp_bits_;
452 std::size_t bp_bit_count_ = 0;
453 BpSupport bp_support_;
Cache-aligned btree implementation of the range min-max index.
Definition btree.h:83
Ferrada-Navarro Cartesian-tree RMQ using rmM support.
Definition cartesian_rmm.h:257
std::size_t memory_usage_bytes_impl() const
Return owned auxiliary memory usage in bytes.
Definition cartesian_rmm.h:374
std::size_t size_impl() const
Return the number of indexed values.
Definition cartesian_rmm.h:327
std::span< const std::uint64_t > bp_words() const
Return the packed BP words used by the RMQ encoding.
Definition cartesian_rmm.h:365
std::size_t bp_bit_count() const
Return the number of BP bits in the Cartesian-tree RMQ encoding.
Definition cartesian_rmm.h:360
CartesianRmM(std::span< const T > values, Compare compare=Compare())
Build a Cartesian-tree RMQ index over values.
Definition cartesian_rmm.h:275
std::size_t arg_min_impl(std::size_t left, std::size_t right) const
Return the first minimum position in [left, right).
Definition cartesian_rmm.h:337
T value_at_impl(std::size_t position) const
Return the value at an indexed position.
Definition cartesian_rmm.h:332
CRTP facade for static range-minimum-query indexes.
Definition rmq.h:28
Depth RMQ adapter over the experimental rmM btree.
Definition cartesian_rmm.h:105
RmMPlusMinusOne(std::span< const std::uint64_t > bits, std::size_t depth_count)
Build an rmM-backed ±1 RMQ over external packed delta bits.
Definition cartesian_rmm.h:125
void build(std::span< const std::uint64_t > bits, std::size_t depth_count)
Rebuild this adapter over external packed delta bits.
Definition cartesian_rmm.h:145
bool empty() const
Whether the indexed depth sequence is empty.
Definition cartesian_rmm.h:177
std::size_t memory_usage_bytes() const
Return owned auxiliary memory usage in bytes.
Definition cartesian_rmm.h:223
std::size_t size() const
Return the number of indexed depth positions.
Definition cartesian_rmm.h:172
std::size_t arg_min(std::size_t left, std::size_t right) const
Return the first minimum depth position in [left, right).
Definition cartesian_rmm.h:185
void build(std::span< const std::uint64_t > bits, std::size_t depth_count, std::optional< std::size_t > one_count)
Rebuild this adapter with an optional exact count of +1 delta bits.
Definition cartesian_rmm.h:152
std::size_t rank0(std::size_t end_position) const
Count closing parentheses in the prefix [0, end_position).
Definition cartesian_rmm.h:213
RmMPlusMinusOne(std::span< const std::uint64_t > bits, std::size_t depth_count, std::size_t one_count)
Build with an exact count of +1 delta bits.
Definition cartesian_rmm.h:136
std::size_t select0(std::size_t rank) const
Return the one-based rank-th closing parenthesis position.
Definition cartesian_rmm.h:208
Common interface for static range-minimum-query indexes.