test_sample.cpp
Go to the documentation of this file.
1 // Copyright 2024 Ekumen, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <gtest/gtest.h>
16 
17 #include <array>
18 #include <cstddef>
19 #include <tuple>
20 #include <type_traits>
21 #include <unordered_map>
22 #include <vector>
23 
24 #include <range/v3/algorithm/count.hpp>
25 #include <range/v3/algorithm/find.hpp>
26 #include <range/v3/range/access.hpp>
27 #include <range/v3/range/concepts.hpp>
28 #include <range/v3/range/conversion.hpp>
29 #include <range/v3/range/dangling.hpp>
30 #include <range/v3/range/primitives.hpp>
31 #include <range/v3/view/const.hpp>
32 #include <range/v3/view/take_exactly.hpp>
33 
35 #include "beluga/primitives.hpp"
37 #include "beluga/views/sample.hpp"
38 
39 namespace {
40 
41 TEST(SampleView, FromEmptyRange) {
42  auto input = std::vector<int>{};
43  ASSERT_DEBUG_DEATH(beluga::views::sample(input), "Assertion");
44 }
45 
46 TEST(SampleView, ConceptChecksFromContiguousRange) {
47  auto input = std::array{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
48  auto output = beluga::views::sample(input);
49 
50  static_assert(ranges::common_range<decltype(input)>);
51  static_assert(!ranges::common_range<decltype(output)>);
52 
53  static_assert(!ranges::viewable_range<decltype(input)>);
54  static_assert(ranges::viewable_range<decltype(output)>);
55 
56  static_assert(ranges::forward_range<decltype(input)>);
57  static_assert(!ranges::forward_range<decltype(output)>);
58 
59  static_assert(ranges::sized_range<decltype(input)>);
60  static_assert(!ranges::sized_range<decltype(output)>);
61 
62  static_assert(ranges::bidirectional_range<decltype(input)>);
63  static_assert(!ranges::bidirectional_range<decltype(output)>);
64 
65  static_assert(ranges::random_access_range<decltype(input)>);
66  static_assert(!ranges::random_access_range<decltype(output)>);
67 
68  static_assert(ranges::contiguous_range<decltype(input)>);
69  static_assert(!ranges::contiguous_range<decltype(output)>);
70 
71  static_assert(ranges::range<decltype(output)>);
72  static_assert(ranges::semiregular<decltype(output)>);
73  static_assert(ranges::enable_view<decltype(output)>);
74 }
75 
76 TEST(SampleView, UniformDistributionSingleElement) {
77  auto input = std::array{5};
78  auto output = input | beluga::views::sample | ranges::views::take_exactly(20);
79  ASSERT_EQ(ranges::count(output, 5), 20);
80 }
81 
82 TEST(SampleView, DiscreteDistributionSingleElement) {
83  auto input = std::array{5};
84  auto weights = std::array{1.0};
85  auto output = beluga::views::sample(input, weights) | ranges::views::take_exactly(20);
86  ASSERT_EQ(ranges::count(output, 5), 20);
87 }
88 
89 TEST(SampleView, DiscreteDistributionSingleElementFromParticleRange) {
90  auto input = std::array{std::make_tuple(5, beluga::Weight(5.0))};
91  // NOTE: We convert to std::vector because `sample` does not produce a forward range,
92  // and thus does not support iterating over the whole sequence twice.
93  auto output = input | beluga::views::sample | ranges::views::take_exactly(20) | ranges::to<std::vector>;
94  ASSERT_EQ(ranges::count(output | beluga::views::states, 5), 20);
95  ASSERT_EQ(ranges::count(output | beluga::views::weights, beluga::Weight(1.0)), 20);
96 }
97 
98 TEST(SampleView, DiscreteDistributionWeightZero) {
99  auto input = std::array{42, 5};
100  auto weights = std::array{0.0, 1.0};
101  auto output = beluga::views::sample(input, weights) | ranges::views::take_exactly(20);
102  ASSERT_EQ(ranges::count(output, 5), 20);
103 }
104 
105 TEST(SampleView, DoubleDereference) {
106  auto engine = std::mt19937{std::random_device()()};
107  auto input = std::array{10, 42, 39, 20, 50};
108  auto output = beluga::views::sample(input, engine);
109  auto it = ranges::begin(output);
110  ++it;
111  auto value = *it;
112  ASSERT_EQ(value, *it);
113  ASSERT_EQ(value, *it);
114 }
115 
116 TEST(SampleView, NonBorrowedRange) {
117  auto input = std::array{42};
118  const auto create_view = [&]() { return input | beluga::views::sample; };
119  auto it = ranges::find(create_view(), 42);
120  static_assert(std::is_same_v<decltype(it), ranges::dangling>); // the iterator is dangling since transform is not a
121  // borrowed range
122 }
123 
124 TEST(SampleView, EngineArgument) {
125  auto engine = std::mt19937{std::random_device()()};
126  auto input = std::array{5};
127  auto weights = std::array{1.0};
128  auto particles = std::array{std::make_tuple(5, beluga::Weight(1.0))};
129  [[maybe_unused]] auto view1 = beluga::views::sample(engine);
130  [[maybe_unused]] auto view2 = input | view1;
131  [[maybe_unused]] auto view3 = particles | view1;
132  [[maybe_unused]] auto view4 = beluga::views::sample(input, engine);
133  [[maybe_unused]] auto view5 = beluga::views::sample(input, weights, engine);
134  [[maybe_unused]] auto view6 = beluga::views::sample(particles, engine);
135 }
136 
137 TEST(SampleView, DiscreteDistributionProbability) {
138  const auto size = 100'000;
139 
140  const auto input = beluga::TupleVector<std::tuple<int, beluga::Weight>>{
141  std::make_tuple(1, beluga::Weight(0.3)), //
142  std::make_tuple(2, beluga::Weight(0.1)), //
143  std::make_tuple(3, beluga::Weight(0.4)), //
144  std::make_tuple(4, beluga::Weight(0.2))};
145 
146  auto output = input | //
147  ranges::views::const_ | //
148  beluga::views::sample | //
149  ranges::views::take_exactly(size);
150 
151  std::unordered_map<int, std::size_t> buckets;
152  for (auto [value, weight] : output) {
153  ++buckets[value];
154  ASSERT_EQ(weight, 1.0);
155  }
156 
157  ASSERT_EQ(ranges::size(buckets), 4);
158 
159  ASSERT_NEAR(static_cast<double>(buckets[1]) / size, 0.3, 0.01);
160  ASSERT_NEAR(static_cast<double>(buckets[2]) / size, 0.1, 0.01);
161  ASSERT_NEAR(static_cast<double>(buckets[3]) / size, 0.4, 0.01);
162  ASSERT_NEAR(static_cast<double>(buckets[4]) / size, 0.2, 0.01);
163 }
164 
165 TEST(SampleView, FromRandomDistributionFalse) {
166  auto distribution = std::bernoulli_distribution{0.0};
167  auto output = beluga::views::sample(distribution) | ranges::views::take_exactly(10);
168  ASSERT_EQ(ranges::count(output, false), 10);
169 }
170 
171 TEST(SampleView, FromRandomDistributionTrue) {
172  auto distribution = std::bernoulli_distribution{1.0};
173  auto output = beluga::views::sample(distribution) | ranges::views::take_exactly(10);
174  ASSERT_EQ(ranges::count(output, true), 10);
175 }
176 
177 } // namespace
primitives.hpp
Implementation of library primitives to abstract member access.
tuple_vector.hpp
Implementation of a tuple of containers.
particles.hpp
Implementation of views related to particle ranges.
beluga::Numeric
Helper for creating strongly typed numeric types.
Definition: strongly_typed_numeric.hpp:38
beluga::views::weights
constexpr auto weights
Definition: particles.hpp:34
sample.hpp
Implementation of a sample (with replacement) range adaptor object.
beluga::views::states
constexpr auto states
Definition: particles.hpp:30
beluga::views::sample
constexpr ranges::views::view_closure< detail::sample_fn > sample
Definition: sample.hpp:240
beluga::TEST
TEST(Bresenham, MultiPassGuarantee)
Definition: test_bresenham.cpp:27


beluga
Author(s):
autogenerated on Tue Jul 16 2024 02:59:53