Iros
 
Loading...
Searching...
No Matches
sample.h
Go to the documentation of this file.
1#pragma once
2
9
10namespace di::container {
11namespace detail {
13 template<concepts::InputIterator It, concepts::SentinelFor<It> Sent, concepts::WeaklyIncrementable Out,
14 typename Gen, typename SSizeType = meta::IteratorSSizeType<It>>
18 constexpr auto operator()(It first, Sent last, Out out, meta::TypeIdentity<SSizeType> n, Gen&& generator) const
19 -> Out {
21 using Param = Distribution::Param;
22
23 auto distribution = Distribution {};
24
25 if constexpr (concepts::ForwardIterator<It>) {
26 // Implement selection sampling.
27
28 auto count = container::distance(first, last);
29 for (auto to_sample = container::min(count, n); to_sample != 0; --first) {
30 // Generate a random number between [0, count).
31 // Only keep the current element if the random number
32 // chosen is less than the number of samples which have
33 // not yet been generated.
34 if (distribution(generator, Param(0, --count)) < to_sample) {
35 *out = *first;
36 ++out;
37 --to_sample;
38 }
39 }
40 return out;
41 } else {
42 // Implement reservoir sampling, storing extra elements in the output iterator's storage.
43 // This is Algorithm R, as described on wikipedia: https://en.wikipedia.org/wiki/Reservoir_sampling.
44
45 // Copy the first n elements into the reservoir. If the input size is less than n,
46 // we will have no more work to do.
47 SSizeType reservoir_size = 0;
48 for (; first != last && reservoir_size < n; ++first, ++reservoir_size) {
49 out[reservoir_size] = *first;
50 }
51
52 // Overwrite the reservoir with new elements if they get selected by the algorithm.
53 for (auto size_so_far = reservoir_size; first != last; ++first, ++size_so_far) {
54 auto chosen_index = distribution(generator, Param(0, size_so_far));
55 if (chosen_index < n) {
56 out[chosen_index] = *first;
57 }
58 }
59
60 return out;
61 }
62 }
63
64 template<concepts::InputContainer Con, concepts::WeaklyIncrementable Out, typename Gen>
68 constexpr auto operator()(Con&& container, Out out, meta::ContainerSSizeType<Con> n, Gen&& generator) const
69 -> Out {
70 return (*this)(container::begin(container), container::end(container), util::move(out), n, generator);
71 }
72 };
73}
74
75constexpr inline auto sample = detail::SampleFunction {};
76}
Definition uniform_int_distribution.h:10
Definition forward_container.h:8
Definition forward_iterator.h:10
Definition indirectly_copyable.h:9
Definition random_access_iterator.h:12
Definition uniform_random_bit_generator.h:10
Definition sequence.h:13
Definition sequence.h:12
constexpr auto min
Definition min.h:47
constexpr auto distance
Definition distance.h:44
constexpr auto count
Definition count.h:37
constexpr auto end
Definition end.h:47
constexpr auto sample
Definition sample.h:75
constexpr auto begin
Definition begin.h:44
IteratorSSizeType< ContainerIterator< T > > ContainerSSizeType
Definition container_ssize_type.h:8
Type< TypeConstant< T > > TypeIdentity
This is a helper template to prevent C++ from deducing the type of template argument.
Definition core.h:32