Skip to content

Commit

Permalink
roc-streaminggh-751 documented code
Browse files Browse the repository at this point in the history
  • Loading branch information
novertia committed Jul 19, 2024
1 parent 93078c1 commit 0342c08
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 20 deletions.
86 changes: 66 additions & 20 deletions src/internal_modules/roc_core/mov_quantile.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,16 @@
namespace roc {
namespace core {

//! Rolling window moving quantile
//!@remarks
//! Efficiently implements moving quantile using partition heap based on approach
//! described in https://aakinshin.net/posts/partitioning-heaps-quantile-estimator/.
//! It follows the quantile estimator strategy mentioned in the document
//! @tparam T defines a sample type.
template <typename T> class MovQuantile {
public:
const size_t win_len_;
const size_t percentile_;
size_t old_heap_root_index_;
const size_t heap_root_;
size_t heap_size_;
size_t max_heap_index_;
size_t min_heap_index_;
size_t elem_index_;
bool win_filled_;
bool valid_;
Array<T> heap_;
Array<size_t> elem_index_heap_index_;
Array<size_t> heap_index_elem_index_;

MovQuantile(IArena& arena, const size_t win_len, const size_t percentile)
//! Initialize
: win_len_(win_len)
, percentile_(percentile)
, old_heap_root_index_(0)
Expand Down Expand Up @@ -66,10 +59,14 @@ template <typename T> class MovQuantile {
}
valid_ = true;
}

//! Check that initial allocation succeeded.
bool is_valid() {
return valid_;
}

//! Swaps 2 heap elements along with their mapping in element to heap index and heap
//! to element index
void swap(size_t index_1, size_t index_2) {
size_t elem_index_1 = heap_index_elem_index_[index_1];
size_t elem_index_2 = heap_index_elem_index_[index_2];
Expand All @@ -85,6 +82,8 @@ template <typename T> class MovQuantile {
elem_index_heap_index_[elem_index_2] = index_1;
}

//! Recursively swaps parent and element in min heap partition until the parent is
//! smaller or element reaches root index.
void min_heapify_up(size_t heap_index) {
if (heap_index == heap_root_) {
return;
Expand All @@ -95,7 +94,11 @@ template <typename T> class MovQuantile {
min_heapify_up(parent);
}
}

//! Recursively swaps parent and element in max heap partition until the parent is
//! larger or element reaches root index.
//! @remarks
//! The root index in max heap partition is larger than all its child index so parent
//! index formulae has been adjusted accordingly
void max_heapify_up(size_t heap_index) {
// sift up
if (heap_index == heap_root_) {
Expand All @@ -107,7 +110,8 @@ template <typename T> class MovQuantile {
max_heapify_up(parent);
}
}

//! Recursively swaps children and element in min heap partition until the children
//! are smaller or there are no children
void min_heapify_down(size_t heap_index) {
size_t largest = heap_index;

Expand All @@ -123,7 +127,10 @@ template <typename T> class MovQuantile {
min_heapify_down(largest);
}
}

//! Recursively swaps children and element in max heap partition until the children
//! are larger or there are no children.
//! @remarks
//! Similar adjustment to child index calculation like in max_heapify_up
void max_heapify_down(size_t heap_index) {
size_t largest = heap_index;

Expand All @@ -141,7 +148,9 @@ template <typename T> class MovQuantile {
max_heapify_down(largest);
}
}

//! Maintains property of the partition heap when an element in inserted or swapped.
//! @remarks
//! The element could be inserted or changed in min_heap, max_heap or the root.
void heapify(size_t heap_index) {
if (heap_index < heap_root_) {
size_t parent = heap_root_ - ((heap_root_ - heap_index - 1) / 2);
Expand All @@ -164,7 +173,12 @@ template <typename T> class MovQuantile {
}
}
}

//! Insert or swaps elements in the partition heap
//! @remarks
//! Case 1: The window is filled. The element in heap is changed whose
//! element_index%window_length is equal to arrived element. heapify is called post
//! that Case 2: The window in not filled. In this case we insert element in max_heap,
//! min_heap or root based on the current percentile index
void add(const T& x) {
if (elem_index_ == win_len_)
win_filled_ = true;
Expand Down Expand Up @@ -204,10 +218,42 @@ template <typename T> class MovQuantile {

elem_index_ = elem_index_ + 1;
}

//! Returns the moving quantile
T sliding_quantile() {
return heap_[heap_root_];
}

//! Length of the sliding window
const size_t win_len_;
//! Percentile of the window elements
const size_t percentile_;

//! Used to check the window filling logic
size_t old_heap_root_index_;
//! Index which seperates max and min heap and also act as their root
const size_t heap_root_;

//! Maintains current heap size
size_t heap_size_;
//! Maintians the index to which max_heap extends
size_t max_heap_index_;
//! Maintians the index to which min_heap extends
size_t min_heap_index_;

//! Maintians current element index
size_t elem_index_;

//! Window filled check
bool win_filled_;
//! Maintians initialization success
bool valid_;

//! Maintians the parititon heap
Array<T> heap_;
//! Maintians the element index to heap index mapping
Array<size_t> elem_index_heap_index_;
//! Maintains the heap index to element index mapping
Array<size_t> heap_index_elem_index_;
};

} // namespace core
Expand Down
2 changes: 2 additions & 0 deletions src/tests/roc_core/test_mov_quantile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ TEST(movquantile, testing_median) {
TEST(movquantile, testing_upper_side) {
const size_t n = 11;
MovQuantile<int64_t> quant(arena, n, 78);
CHECK(quant.is_valid());
quant.add(18);
quant.add(18);
quant.add(22);
Expand All @@ -112,6 +113,7 @@ TEST(movquantile, testing_upper_side) {
TEST(movquantile, test_maximum) {
const size_t n = 7;
MovQuantile<int64_t> quant(arena, n, 100);
CHECK(quant.is_valid());
quant.add(21);
quant.add(14);
quant.add(38);
Expand Down

0 comments on commit 0342c08

Please sign in to comment.