Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
k_partition_of_r_generator.h
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#pragma once
5
6#include "../namespaces.h"
7
8#include <catch/catch.hpp>
9
10#include <random>
11#include <numeric>
12#include <algorithm>
13
16
18 public:
19 KPartitionOfRGenerator(double r, std::size_t k)
20 : random_engine{std::random_device{}()},
22 k{k},
23 r{r},
25 {
26 assert(r >= 0.0);
27 assert(k >= 1);
28
29 static_cast<void>(next());
30 }
31
32 std::vector<double> const& get() const override { return current_partition; }
33
34 bool next() override {
35 if (k == 1) current_partition[0] = r;
36 else {
37 // REMARK: The following wasn't formally proved
38 // but is based on intuition.
39 // It is probably erroneous but is expected to be
40 // good enough for our case.
41
42 // REMARK: We aim to provide a non skewed
43 // distribution for the elements of the partition.
44 //
45 // The reasoning for this is to ensure that our
46 // testing surface has a good chance of hitting
47 // many of the available elements between the many
48 // runs.
49 //
50 // To approximate this, a specific algorithm was chosen.
51 // The following code can be intuitively seen as doing the following:
52 //
53 // Consider an interval [0.0, r] on the real line, where r > 0.0.
54 //
55 // k - 1 > 0 elements of the interval are chosen,
56 // partitioning the interval into disjoint
57 // sub-intervals.
58 //
59 // ---------------------------------------------------------------------------------------------------------------------
60 // | | | | |
61 // 0 k_1 k_2 k_3 r
62 // | | | | |
63 // _______--------------------_______________________________________________________-----------------------------------
64 // k_1 - 0 k_2 - k_1 k_3 - k_2 r - k_3
65 // p1 p2 p3 p4
66 //
67 // The length of each sub interval is chosen as one of the elements of the partition.
68 //
69 // Trivially, the sum of the chosen elements is r.
70 //
71 // Furthermore, as long as the distribution used
72 // to choose the elements of the original interval
73 // is uniform, the probability of each partition
74 // being produced should tend to being uniform
75 // itself.
76 std::generate(current_partition.begin(), current_partition.end() - 1, [this](){ return interval_distribution(random_engine); });
77
78 current_partition.back() = r;
79
80 std::sort(current_partition.begin(), current_partition.end());
81 std::adjacent_difference(current_partition.begin(), current_partition.end(), current_partition.begin());
82 }
83
84 return true;
85 }
86
87 private:
88 std::mt19937 random_engine;
89 std::uniform_real_distribution<double> interval_distribution;
90
91 std::size_t k;
92 double r;
93
94 std::vector<double> current_partition;
95 };
96
97 } // end QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
98
99 /*!
100 * Returns a generator that generates collections of \a k elements
101 * whose sum is \a r.
102 *
103 * \a r must be a real number greater or euqal to zero and \a k
104 * must be a natural number greater than zero.
105 *
106 * The generated partitions tends to be uniformely distributed
107 * over the set of partitions of r.
108 */
109 inline Catch::Generators::GeneratorWrapper<std::vector<double>> k_partition_of_r(double r, std::size_t k) {
110 return Catch::Generators::GeneratorWrapper<std::vector<double>>(std::unique_ptr<Catch::Generators::IGenerator<std::vector<double>>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::KPartitionOfRGenerator(r, k)));
111 }
112
113} // end QDOC_CATCH_GENERATORS_ROOT_NAMESPACE
Catch::Generators::GeneratorWrapper< std::vector< double > > k_partition_of_r(double r, std::size_t k)
Returns a generator that generates collections of k elements whose sum is r.
#define QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
Definition namespaces.h:8
#define QDOC_CATCH_GENERATORS_ROOT_NAMESPACE
Definition namespaces.h:6
#define assert