@@ -1,6 +1,7 | |||||
1 | #ifndef SCIQLOP_FUZZINGUTILS_H |
|
1 | #ifndef SCIQLOP_FUZZINGUTILS_H | |
2 | #define SCIQLOP_FUZZINGUTILS_H |
|
2 | #define SCIQLOP_FUZZINGUTILS_H | |
3 |
|
3 | |||
|
4 | #include <algorithm> | |||
4 | #include <random> |
|
5 | #include <random> | |
5 |
|
6 | |||
6 | /** |
|
7 | /** | |
@@ -16,10 +17,17 public: | |||||
16 | /// Generates a random int between [min, max] |
|
17 | /// Generates a random int between [min, max] | |
17 | int generateInt(int min, int max); |
|
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 | /** | |
20 | /// returns an element built by default |
|
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 | template <typename T, typename ValueType = typename T::value_type> |
|
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 | private: |
|
32 | private: | |
25 | std::mt19937 m_Mt; |
|
33 | std::mt19937 m_Mt; | |
@@ -28,14 +36,28 private: | |||||
28 | }; |
|
36 | }; | |
29 |
|
37 | |||
30 | template <typename T, typename ValueType> |
|
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 | if (container.empty()) { |
|
41 | if (container.empty()) { | |
34 | return ValueType{}; |
|
42 | return ValueType{}; | |
35 | } |
|
43 | } | |
36 |
|
44 | |||
37 | auto randomIndex = generateInt(0, container.size() - 1); |
|
45 | // Generates weights for each element: if the weights passed in parameter are malformed (the | |
38 | return container.at(randomIndex); |
|
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 | #endif // SCIQLOP_FUZZINGUTILS |
|
63 | #endif // SCIQLOP_FUZZINGUTILS |
General Comments 0
You need to be logged in to leave comments.
Login now