21template<
typename T,
template<
typename>
typename Derived>
27#define CDERIVED (*static_cast<const derived_type*>(this))
41 return out << static_cast<const derived_type&>(S);
44 void dump(std::ostream &out)
const { out << *
this << std::endl; }
52 static_assert(std::is_arithmetic_v<T>,
"type T must be an arithmetic type");
56 std::common_type<T>>::type;
70 throw std::invalid_argument(
"invalid range");
72 throw std::invalid_argument(
"number of steps must not be zero");
74 const int save_round = std::fegetround();
75 std::fesetround(FE_TOWARDZERO);
77 std::fesetround(save_round);
98 throw std::out_of_range(
"n must be between 0 and num_steps()");
99 if constexpr (std::is_integral_v<value_type>) {
100 const typename std::make_unsigned_t<value_type>
delta = std::round(n *
step());
115 std::vector<value_type> vec;
118 for (
unsigned i = 0; i <=
num_steps(); ++i)
119 vec.push_back(
at(i));
126 return out <<
"linear space from " << S.
lo() <<
" to " << S.
hi() <<
" with " << S.
num_steps() <<
" steps of "
130 void dump(std::ostream &out)
const { out << *
this << std::endl; }
135template<
typename... Spaces>
150 return std::apply([](
auto&... space) {
151 return ((space.num_steps() + 1) * ... );
160 out <<
"grid search with";
162 std::apply([&out](
auto&... space) {
163 ((out <<
"\n " << space), ...);
169 void dump(std::ostream &out)
const { out << *
this << std::endl; }
174 template<std::size_t... I>
175 std::tuple<
typename Spaces::value_type...>
176 make_args(std::array<unsigned, NUM_SPACES> &counters, std::index_sequence<I...>)
const {
177 return std::apply([&counters](
auto&... space) {
178 return std::make_tuple(space(counters[I])...);
183template<
typename... Spaces>
186 std::array<unsigned, NUM_SPACES> counters;
187 std::fill(counters.begin(), counters.end(), 0
U);
188 const std::array<unsigned, NUM_SPACES> num_steps = std::apply([](
auto&... space) {
189 return std::array<unsigned, NUM_SPACES>{ space.num_steps()... };
193 auto args = make_args(counters, std::index_sequence_for<Spaces...>{});
194 std::apply(fn,
args);
196 std::size_t idx = NUM_SPACES - 1;
198 while (counters[idx] == num_steps[idx]) {
199 if (idx == 0)
goto finished;
and arithmetic< U > and same_signedness< T, U > U
static constexpr std::size_t NUM_SPACES
std::function< void(typename Spaces::value_type...)> callback_type
M_LCOV_EXCL_START friend std::ostream & operator<<(std::ostream &out, const GridSearch &GS)
std::tuple< typename Spaces::value_type... > make_args(std::array< unsigned, NUM_SPACES > &counters, std::index_sequence< I... >) const
std::size_t num_points() const
GridSearch(Spaces... spaces)
void dump(std::ostream &out) const
constexpr std::size_t num_spaces() const
void operator()(callback_type fn) const
std::tuple< Spaces... > spaces_
void search(callback_type fn) const
M_LCOV_EXCL_START friend std::ostream & operator<<(std::ostream &out, const LinearSpace &S)
static LinearSpace Ascending(value_type lowest, value_type highest, unsigned num_steps)
LinearSpace(value_type lowest, value_type highest, unsigned num_steps, bool is_ascending=true)
void dump(std::ostream &out) const
std::vector< value_type > sequence() const
static LinearSpace Descending(value_type lowest, value_type highest, unsigned num_steps)
value_type at(unsigned n) const
difference_type delta() const
unsigned num_steps() const
typename std::conditional_t< std::is_integral_v< T >, std::make_signed< T >, std::common_type< T > >::type difference_type
value_type operator()(unsigned n) const
unsigned num_steps() const
M_LCOV_EXCL_START friend std::ostream & operator<<(std::ostream &out, const Space &S)
std::vector< value_type > sequence() const
Derived< T > derived_type
value_type operator()(unsigned n) const
void dump(std::ostream &out) const
value_type at(unsigned n) const