#pragma once #include namespace intgemm { /* * Sequence of unsigned integers * * Examples: * sequence<1, 2, 3>() * sequence_pushback<4, sequence<1, 2, 3>>() = sequence<1, 2, 3, 4>() * sequence_popfront>() = sequence<2, 3>() * make_sequence<3>() = sequence<0, 1, 2>() */ template struct sequence { using type = sequence; }; template struct sequence_pushback; template struct sequence_pushback> : sequence {}; template struct sequence_popfront; template struct sequence_popfront> : sequence {}; namespace { // anonymous namespace template struct make_sequence_impl : sequence_pushback::type> {}; template <> struct make_sequence_impl<0> : sequence<> {}; } // anonymous namespace template using make_sequence = typename make_sequence_impl::type; /* * Make a subtuple */ template using subtuple_t = typename std::tuple::type...>; template constexpr subtuple_t make_subtuple(const Tuple& tuple, sequence) { return std::make_tuple(std::get(tuple)...); } /* * Factorial */ constexpr unsigned long long factorial(unsigned n) { return n <= 1 ? 1 : n * factorial(n - 1); } /* * e^x */ namespace { // anonymous namespace constexpr double exp_nonnegative(unsigned x) { return x == 0 ? 1.0 : (x == 1 ? 2.718281828459045 : exp_nonnegative(x / 2) * exp_nonnegative((x + 1) / 2)); } } // anonymous namespace constexpr double exp(int x) { return (x >= 0 ? exp_nonnegative(x) : 1.0 / exp_nonnegative(-x)); } }