in sampling/include/var_opt_sketch_impl.hpp [905:961]
void var_opt_sketch<T, A>::decrease_k_by_1() {
if (k_ <= 1) {
throw std::logic_error("Cannot decrease k below 1 in union");
}
if ((h_ == 0) && (r_ == 0)) {
// exact mode, but no data yet; this reduction is somewhat gratuitous
--k_;
} else if ((h_ > 0) && (r_ == 0)) {
// exact mode, but we have some data
--k_;
if (h_ > k_) {
transition_from_warmup();
}
} else if ((h_ > 0) && (r_ > 0)) {
// reservoir mode, but we have some exact samples.
// Our strategy will be to pull an item out of H (which we are allowed to do since it's
// still just data), reduce k, and then re-insert the item
// first, slide the R zone to the left by 1, temporarily filling the gap
const uint32_t old_gap_idx = h_;
const uint32_t old_final_r_idx = (h_ + 1 + r_) - 1;
if (old_final_r_idx != k_) throw std::logic_error("gadget in invalid state");
swap_values(old_final_r_idx, old_gap_idx);
filled_data_ = true; // we just filled the gap, and no need to check previous state
// now we pull an item out of H; any item is ok, but if we grab the rightmost and then
// reduce h_, the heap invariant will be preserved (and the gap will be restored), plus
// the push() of the item that will probably happen later will be cheap.
const uint32_t pulled_idx = h_ - 1;
double pulled_weight = weights_[pulled_idx];
bool pulled_mark = marks_[pulled_idx];
// will move the pulled item below; don't do antying to it here
if (pulled_mark) { --num_marks_in_h_; }
weights_[pulled_idx] = -1.0; // to make bugs easier to spot
--h_;
--k_;
--n_; // will be re-incremented with the update
update(std::move(data_[pulled_idx]), pulled_weight, pulled_mark);
} else if ((h_ == 0) && (r_ > 0)) {
// pure reservoir mode, so can simply eject a randomly chosen sample from the reservoir
if (r_ < 2) throw std::logic_error("r_ too small for pure reservoir mode");
const uint32_t r_idx_to_delete = 1 + next_int(r_); // 1 for the gap
const uint32_t rightmost_r_idx = (1 + r_) - 1;
swap_values(r_idx_to_delete, rightmost_r_idx);
weights_[rightmost_r_idx] = -1.0;
--k_;
--r_;
}
}