Loading...
Searching...
No Matches
weighted_selection.h
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (C) 2026 Artificial Intelligence Techniques, S.L. and Roberto López González
3
4#pragma once
5
7
8#include <algorithm>
9#include <cmath>
10#include <stdexcept>
11#include <utility>
12#include <vector>
13
14namespace opennn::detail
15{
16
17// Independent exponential priorities implement successive weighted sampling
18// without replacement. See Efraimidis, arXiv:1012.0256v2, sections 2 and 3.2.
19// Existing selections (elites) are retained, even when they exceed the quota.
20template<typename Uniform>
21void fill_weighted_selection(const VectorR& weights, Index quota, VectorB& selected, Uniform&& uniform)
22{
23 if (selected.size() != weights.size() || quota < 0 || quota > weights.size())
24 throw std::invalid_argument("Weighted selection: invalid mask or quota.");
25
26 Index available = 0;
27 for (Index i = 0; i < weights.size(); ++i)
28 {
29 if (!std::isfinite(weights(i)) || weights(i) < 0.0f)
30 throw std::invalid_argument("Weighted selection: weights must be finite and nonnegative.");
31 if (!selected(i) && weights(i) > 0.0f) ++available;
32 }
33
34 const Index needed = quota - selected.count();
35 if (needed <= 0) return;
36 if (needed > available)
37 throw std::invalid_argument("Weighted selection: insufficient positive weights.");
38
39 std::vector<std::pair<double, Index>> priorities;
40 priorities.reserve(size_t(available));
41 for (Index i = 0; i < weights.size(); ++i)
42 {
43 if (selected(i) || weights(i) == 0.0f) continue;
44 const double draw = double(uniform());
45 if (!std::isfinite(draw) || draw < 0.0 || draw > 1.0)
46 throw std::invalid_argument("Weighted selection: uniform draw must be in [0,1].");
47 const double interior = std::min(draw, std::nextafter(1.0, 0.0));
48 priorities.emplace_back(-std::log1p(-interior) / double(weights(i)), i);
49 }
50
51 // Index order resolves the rare ties from finite-precision random draws.
52 std::partial_sort(priorities.begin(), priorities.begin() + needed, priorities.end());
53 for (Index rank = 0; rank < needed; ++rank)
54 selected(priorities[size_t(rank)].second) = true;
55}
56
57}
Definition opennn_types.h:204
void fill_weighted_selection(const VectorR &weights, Index quota, VectorB &selected, Uniform &&uniform)
Definition weighted_selection.h:21
Eigen::Matrix< float, Eigen::Dynamic, 1 > VectorR
Definition opennn_types.h:335
Eigen::Matrix< bool, Eigen::Dynamic, 1 > VectorB
Definition opennn_types.h:337