in src/main/java/org/apache/datasketches/sampling/VarOptItemsSketch.java [865:920]
void decreaseKBy1() {
if (k_ <= 1) {
throw new SketchesStateException("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_) {
transitionFromWarmup();
}
} 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
final int oldGapIdx = h_;
final int oldFinalRIdx = (h_ + 1 + r_) - 1;
assert oldFinalRIdx == k_;
swapValues(oldFinalRIdx, oldGapIdx);
// 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.
final int pulledIdx = h_ - 1;
final T pulledItem = data_.get(pulledIdx);
final double pulledWeight = weights_.get(pulledIdx);
final boolean pulledMark = marks_.get(pulledIdx);
if (pulledMark) { --numMarksInH_; }
weights_.set(pulledIdx, -1.0); // to make bugs easier to spot
--h_;
--k_;
--n_; // will be re-incremented with the update
update(pulledItem, pulledWeight, pulledMark);
} else if ((h_ == 0) && (r_ > 0)) {
// pure reservoir mode, so can simply eject a randomly chosen sample from the reservoir
assert r_ >= 2;
final int rIdxToDelete = 1 + SamplingUtil.rand().nextInt(r_); // 1 for the gap
final int rightmostRIdx = (1 + r_) - 1;
swapValues(rIdxToDelete, rightmostRIdx);
weights_.set(rightmostRIdx, -1.0);
--k_;
--r_;
}
}