100 std::string
StatString()
const {
return stats_.StatString(); }
111 absl::BitGenRef random_;
112 std::vector<Index> equivalent_choices_;
133 HeapElement() =
default;
141 double operator<(
const HeapElement& other)
const {
142 return value > other.value;
146 std::vector<HeapElement> tops_;
149 struct QueryStats :
public StatsGroup {
152 get_maximum(
"get_maximum", this),
153 heap_size_on_hit(
"heap_size_on_hit", this),
154 random_choices(
"random_choices", this) {}
155 TimeDistribution get_maximum;
156 IntegerDistribution heap_size_on_hit;
157 IntegerDistribution random_choices;
162template <
typename Index>
167 is_candidate_.ClearAndResize(n);
170template <
typename Index>
172 is_candidate_.Clear(position);
175template <
typename Index>
182template <
typename Index>
185 DCHECK(!std::isnan(value));
186 DCHECK(tops_.empty());
187 is_candidate_.Set(position);
188 values_[position] = value;
191template <
typename Index>
194 DCHECK(!std::isnan(value));
195 is_candidate_.Set(position);
196 values_[position] = value;
197 if (value >= threshold_) UpdateTopK(position, value);
200template <
typename Index>
201inline Index DynamicMaximum<Index>::RandomizeIfManyChoices(
Index best) {
202 if (equivalent_choices_.empty())
return best;
203 equivalent_choices_.push_back(best);
204 stats_.random_choices.Add(equivalent_choices_.size());
206 return equivalent_choices_[std::uniform_int_distribution<int>(
207 0, equivalent_choices_.size() - 1)(random_)];
210template <
typename Index>
214 Index best_position(-1);
215 equivalent_choices_.clear();
225 if (!tops_.empty()) {
227 for (
const HeapElement e : tops_) {
229 if (!is_candidate_[e.index])
continue;
230 if (values_[e.index] != e.value)
continue;
232 tops_[new_size++] = e;
233 if (e.value >= best_value) {
234 if (e.value == best_value) {
235 equivalent_choices_.push_back(e.index);
238 equivalent_choices_.clear();
239 best_value = e.value;
240 best_position = e.index;
243 tops_.resize(new_size);
245 stats_.heap_size_on_hit.Add(new_size);
246 return RandomizeIfManyChoices(best_position);
252 DCHECK(tops_.empty());
253 const auto values = values_.const_view();
254 for (
const Index position : is_candidate_) {
259 if (value < threshold_)
continue;
260 UpdateTopK(position, value);
262 if (value >= best_value) {
263 if (value == best_value) {
264 equivalent_choices_.push_back(position);
267 equivalent_choices_.clear();
269 best_position = position;
273 return RandomizeIfManyChoices(best_position);
276template <
typename Index>
277inline void DynamicMaximum<Index>::UpdateTopK(
Index position,
280 DCHECK_GE(value, threshold_);
286 constexpr int k = 31;
287 static_assert(((k + 1) & k) == 0,
"k + 1 should be a power of 2.");
290 if (tops_.size() < k) {
291 tops_.emplace_back(position, value);
292 if (tops_.size() == k) {
293 std::make_heap(tops_.begin(), tops_.end());
294 threshold_ = tops_[0].value;
308 if (value == tops_[0].value) {
309 if (absl::Bernoulli(random_, 0.5)) {
310 tops_[0].index = position;
319 std::pop_heap(tops_.begin(), tops_.end());
320 tops_.back() = HeapElement(position, value);
321 std::push_heap(tops_.begin(), tops_.end());
322 threshold_ = tops_[0].value;
330 DCHECK_EQ(tops_.size(), k);
331 constexpr int limit = k / 2;
333 const int left_child = 2 *
i + 1;
334 const int right_child = left_child + 1;
335 const Fractional l_value = tops_[left_child].value;
336 const Fractional r_value = tops_[right_child].value;
337 if (l_value > r_value) {
338 if (value <= r_value)
break;
339 tops_[
i] = tops_[right_child];
342 if (value <= l_value)
break;
343 tops_[
i] = tops_[left_child];
347 tops_[
i] = HeapElement(position, value);
348 threshold_ = tops_[0].value;
349 DCHECK(std::is_heap(tops_.begin(), tops_.end()));