@@ -1,6 +1,7 | |||
|
1 | 1 | #ifndef SCIQLOP_FUZZINGUTILS_H |
|
2 | 2 | #define SCIQLOP_FUZZINGUTILS_H |
|
3 | 3 | |
|
4 | #include <algorithm> | |
|
4 | 5 | #include <random> |
|
5 | 6 | |
|
6 | 7 | /** |
@@ -16,10 +17,17 public: | |||
|
16 | 17 | /// Generates a random int between [min, max] |
|
17 | 18 | int generateInt(int min, int max); |
|
18 | 19 | |
|
19 | /// Returns a random element among the elements of a container. If the container is empty, | |
|
20 | /// returns an element built by default | |
|
20 | /** | |
|
21 | * Returns a random element among the elements of a container. An item may be more likely to be | |
|
22 | * selected if it has an associated weight greater than other items | |
|
23 | * @param container the container from which to retrieve an element | |
|
24 | * @param weights the weight associated to each element of the container. The vector must have | |
|
25 | * the same size of the container for the weights to be effective | |
|
26 | * @param nbDraws the number of random draws to perform | |
|
27 | * @return the random element retrieved, an element built by default if the container is empty | |
|
28 | */ | |
|
21 | 29 | template <typename T, typename ValueType = typename T::value_type> |
|
22 | ValueType randomChoice(const T &container); | |
|
30 | ValueType randomChoice(const T &container, const std::vector<double> &weights = {}); | |
|
23 | 31 | |
|
24 | 32 | private: |
|
25 | 33 | std::mt19937 m_Mt; |
@@ -28,14 +36,28 private: | |||
|
28 | 36 | }; |
|
29 | 37 | |
|
30 | 38 | template <typename T, typename ValueType> |
|
31 | ValueType RandomGenerator::randomChoice(const T &container) | |
|
39 | ValueType RandomGenerator::randomChoice(const T &container, const std::vector<double> &weights) | |
|
32 | 40 | { |
|
33 | 41 | if (container.empty()) { |
|
34 | 42 | return ValueType{}; |
|
35 | 43 | } |
|
36 | 44 | |
|
37 | auto randomIndex = generateInt(0, container.size() - 1); | |
|
38 | return container.at(randomIndex); | |
|
45 | // Generates weights for each element: if the weights passed in parameter are malformed (the | |
|
46 | // number of weights defined is inconsistent with the number of elements in the container, or | |
|
47 | // all weights are zero), default weights are used | |
|
48 | auto nbIndexes = container.size(); | |
|
49 | std::vector<double> indexWeights(nbIndexes); | |
|
50 | if (weights.size() != nbIndexes || std::all_of(weights.cbegin(), weights.cend(), | |
|
51 | [](const auto &val) { return val == 0.; })) { | |
|
52 | std::fill(indexWeights.begin(), indexWeights.end(), 1.); | |
|
53 | } | |
|
54 | else { | |
|
55 | std::copy(weights.begin(), weights.end(), indexWeights.begin()); | |
|
56 | } | |
|
57 | ||
|
58 | // Performs a draw to determine the index to return | |
|
59 | std::discrete_distribution<> d{indexWeights.cbegin(), indexWeights.cend()}; | |
|
60 | return container.at(d(m_Mt)); | |
|
39 | 61 | } |
|
40 | 62 | |
|
41 | 63 | #endif // SCIQLOP_FUZZINGUTILS |
General Comments 0
You need to be logged in to leave comments.
Login now