MakeWithRandomValues.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// Helper functions for data structures used in unit tests
6 
7 #pragma once
8 
9 #include <complex>
10 #include <cstddef> // for std::nullptr_t
11 #include <limits>
12 #include <random>
13 
14 #include "DataStructures/SpinWeighted.hpp"
16 #include "Utilities/Gsl.hpp"
18 #include "Utilities/Requires.hpp"
19 #include "Utilities/TypeTraits.hpp"
20 
21 namespace TestHelpers_detail {
22 /// \cond HIDDEN_SYMBOLS
23 template <typename T, typename = std::nullptr_t>
24 struct FillWithRandomValuesImpl;
25 
26 template <typename T>
27 struct FillWithRandomValuesImpl<T, Requires<cpp17::is_fundamental_v<T>>> {
28  template <typename UniformRandomBitGenerator,
29  typename RandomNumberDistribution>
30  static void apply(
31  const gsl::not_null<T*> data,
33  const gsl::not_null<RandomNumberDistribution*> distribution) noexcept {
34  static_assert(
35  cpp17::is_same_v<T, typename RandomNumberDistribution::result_type>,
36  "Mismatch between data type and random number type.");
37  *data = (*distribution)(*generator);
38  }
39 };
40 
41 template <typename T>
42 struct FillWithRandomValuesImpl<std::complex<T>> {
43  template <typename UniformRandomBitGenerator,
44  typename RandomNumberDistribution>
45  static void apply(
46  const gsl::not_null<std::complex<T>*> data,
48  const gsl::not_null<RandomNumberDistribution*> distribution) noexcept {
49  static_assert(
50  cpp17::is_same_v<T, typename RandomNumberDistribution::result_type>,
51  "Mismatch between data type and random number type.");
52  data->real((*distribution)(*generator));
53  data->imag((*distribution)(*generator));
54  }
55 };
56 
57 template <typename T, int Spin>
58 struct FillWithRandomValuesImpl<SpinWeighted<T, Spin>> {
59  template <typename UniformRandomBitGenerator,
60  typename RandomNumberDistribution>
61  static void apply(
64  const gsl::not_null<RandomNumberDistribution*> distribution) noexcept {
65  FillWithRandomValuesImpl<T>::apply(&(data->data()), generator,
66  distribution);
67  }
68 };
69 
70 template <typename T>
71 struct FillWithRandomValuesImpl<
72  T, Requires<not tt::is_maplike_v<T> and tt::is_iterable_v<T>>> {
73  template <typename UniformRandomBitGenerator,
74  typename RandomNumberDistribution>
75  static void apply(
76  const gsl::not_null<T*> data,
78  const gsl::not_null<RandomNumberDistribution*> distribution) noexcept {
79  for (auto& d : *data) {
80  FillWithRandomValuesImpl<std::decay_t<decltype(d)>>::apply(&d, generator,
81  distribution);
82  }
83  }
84 };
85 
86 template <typename... Tags>
87 struct FillWithRandomValuesImpl<Variables<tmpl::list<Tags...>>,
89  template <typename UniformRandomBitGenerator,
90  typename RandomNumberDistribution>
91  static void apply(
92  const gsl::not_null<Variables<tmpl::list<Tags...>>*> data,
94  const gsl::not_null<RandomNumberDistribution*> distribution) noexcept {
96  (FillWithRandomValuesImpl<std::decay_t<decltype(get<Tags>(*data))>>::
97  apply(&get<Tags>(*data), generator, distribution),
98  cpp17::void_type{})...);
99  }
100 };
101 /// \endcond
102 } // namespace TestHelpers_detail
103 
104 // {@
105 /// \ingroup TestingFrameworkGroup
106 ///
107 /// \brief A uniform distribution function object which redirects appropriately
108 /// to either the `std::uniform_int_distribution` or the
109 /// `std::uniform_real_distribution`. This also provides a convenience
110 /// constructor which takes a 2-element array for the bounds for either
111 /// floating point or int distributions.
112 template <typename T>
114  : public tmpl::conditional_t<
115  cpp17::is_integral_v<T>,
116  std::uniform_int_distribution<std::remove_const_t<T>>,
117  std::uniform_real_distribution<std::remove_const_t<T>>> {
118  using base = tmpl::conditional_t<
119  cpp17::is_integral_v<T>,
122  static_assert(cpp17::is_integral_v<T> or cpp17::is_floating_point_v<T>,
123  "UniformCustomDistribution currently supports only floating"
124  "point and integral values");
125 
126  public:
127  using base::base;
128  template <typename Bound>
129  explicit UniformCustomDistribution(std::array<Bound, 2> arr) noexcept
130  : base(arr[0], arr[1]) {}
131  using base::operator=;
132  using base::operator();
133 };
134 // @}
135 
136 /// \ingroup TestingFrameworkGroup
137 /// \brief Fill an existing data structure with random values
138 template <typename T, typename UniformRandomBitGenerator,
139  typename RandomNumberDistribution>
141  const gsl::not_null<T*> data,
143  const gsl::not_null<RandomNumberDistribution*> distribution) noexcept {
145  distribution);
146 }
147 
148 // @{
149 /// \ingroup TestingFrameworkGroup
150 /// \brief Make a data structure and fill it with random values
151 ///
152 /// \details Given an object of type `T`, create an object of type `ReturnType`
153 /// whose elements are initialized to random values using the given random
154 /// number generator and random number distribution.
155 ///
156 /// \requires the type `ReturnType` to be creatable using
157 /// `make_with_value<ReturnType>(T)`
158 template <typename ReturnType, typename T, typename UniformRandomBitGenerator,
159  typename RandomNumberDistribution>
162  const gsl::not_null<RandomNumberDistribution*> distribution,
163  const T& used_for_size) noexcept {
164  auto result = make_with_value<ReturnType>(
165  used_for_size,
167  tt::get_fundamental_type_t<ReturnType>>::signaling_NaN());
168  fill_with_random_values(make_not_null(&result), generator, distribution);
169  return result;
170 }
171 // distributions are sufficiently small to justify providing a convenience
172 // function that receives them by value, which is useful when obtaining pointers
173 // is inconvenient (e.g. for distributions that are obtained as
174 // rvalues). Generators should never be copied, as doing so will cause
175 // duplication of the pseudorandom numbers and performance hits due to the
176 // nontrivial size.
177 // clang-tidy: seems to erroneously believe this is a function declaration
178 // rather than a definition.
179 template <typename ReturnType, typename T, typename UniformRandomBitGenerator,
180  typename RandomNumberDistribution>
182  const gsl::not_null<UniformRandomBitGenerator*> generator, // NOLINT
183  RandomNumberDistribution distribution, const T& used_for_size) noexcept {
184  return make_with_random_values<ReturnType>(
185  generator, make_not_null(&distribution), used_for_size);
186 }
187 // @}
188 
189 /// \ingroup TestingFrameworkGroup
190 /// \brief Make a fixed-size data structure and fill with random values
191 ///
192 /// \details Given a template argument type `T`, create an object of the same
193 /// type, fills it with random values, and returns the result. Acts as a
194 /// convenience function to avoid users needing to put in constructors with
195 /// `signaling_NaN()`s or `max()`s themselves when making with random values.
196 /// Used as
197 /// `make_with_random_values<Type>(make_not_null(&gen),make_not_null(&dist))`
198 template <typename T, typename UniformRandomBitGenerator,
199  typename RandomNumberDistribution>
202  const gsl::not_null<RandomNumberDistribution*> distribution) noexcept {
203  T result{};
204  fill_with_random_values(make_not_null(&result), generator, distribution);
205  return result;
206 }
constexpr bool is_iterable_v
Definition: TypeTraits.hpp:591
Mark a return type as being "void". In C++17 void is a regular type under certain circumstances...
Definition: TypeTraits.hpp:47
Definition: Digraph.hpp:11
ReturnType make_with_random_values(const gsl::not_null< UniformRandomBitGenerator *> generator, const gsl::not_null< RandomNumberDistribution *> distribution, const T &used_for_size) noexcept
Make a data structure and fill it with random values.
Definition: MakeWithRandomValues.hpp:160
void fill_with_random_values(const gsl::not_null< T *> data, const gsl::not_null< UniformRandomBitGenerator *> generator, const gsl::not_null< RandomNumberDistribution *> distribution) noexcept
Fill an existing data structure with random values.
Definition: MakeWithRandomValues.hpp:140
Defines the type alias Requires.
constexpr auto apply(F &&f, const DataBox< BoxTags > &box, Args &&... args)
Apply the function f with argument Tags TagsList from DataBox box
Definition: DataBox.hpp:1595
A collection of useful type traits.
Definition: TensorExpression.hpp:115
T data(T... args)
T is_fundamental_v
Make a spin-weighted type T with spin-weight Spin. Mathematical operators are restricted to addition...
Definition: SpinWeighted.hpp:24
Defines class Variables.
Definition: DataBoxTag.hpp:29
constexpr bool is_maplike_v
Definition: TypeTraits.hpp:988
Defines functions and classes from the GSL.
gsl::not_null< T * > make_not_null(T *ptr) noexcept
Construct a not_null from a pointer. Often this will be done as an implicit conversion, but it may be necessary to perform the conversion explicitly when type deduction is desired.
Definition: Gsl.hpp:863
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t ...
Definition: Requires.hpp:67
C++ STL code present in C++17.
Definition: Array.hpp:16
Defines type traits, some of which are future STL type_traits header.
A uniform distribution function object which redirects appropriately to either the std::uniform_int_d...
Definition: MakeWithRandomValues.hpp:113
Definition: MakeWithRandomValues.hpp:21
Require a pointer to not be a nullptr
Definition: ConservativeFromPrimitive.hpp:12
constexpr void expand_pack(Ts &&...) noexcept
Allows zero-cost unordered expansion of a parameter.
Definition: TMPL.hpp:545
Defines make_with_value.