Я кодирую функцию, которая вычисляет pmf для полиномиального распределения (https://en.wikipedia.org/wiki/Multinomial_distribution).
Я успешно закодировал функцию коэффициентов многочлена и хочу использовать это в вычислении многочленного распределения, но компиляция не удалась.
Моя текущая попытка:
#include <algorithm>
#include <cmath>
#include <cassert>
#include <utility>
#include <initializer_list>
#include <numeric>
template <typename N>
concept Unsigned = std::is_unsigned_v<N>;
template <typename N>
concept Integral = std::is_integral_v<N>;
template <typename R>
concept Floating = std::is_floating_point_v<R>;
template <Unsigned U>
constexpr U binom(U N, U K) {
assert(N >= K);
U result {1};
for (U i = U {1}; i <= N - K; i++) {
result *= i + K;
result /= i;
}
return result;
}
template <Unsigned U, Integral I>
constexpr U multinom (U N, I K) {
assert(N == K);
return U {1};
}
template <Unsigned U, Integral I, Integral... Is>
constexpr U multinom (U N, I K1, Is... Ks) {
assert(N >= static_cast<U>(K1));
return binom(N, static_cast<U>(K1)) * multinom(N - static_cast<U>(K1), Ks...);
}
template <Floating F1, Floating F2>
constexpr bool almost_equal(F1 f1, F2 f2) {
return std::fabs(f1 - f2) < std::min({1.0e-4, f1 * 1.0e-3, f2 * 1.0e-3});
}
/*template <Unsigned U, Integral I, Floating F>
constexpr F multinom_pmf(U N, std::initializer_list<std::pair<I, F>> args) {
assert(almost_equal(1.0, std::accumulate(args.begin(), args.end(), 0.0, [](auto& a, auto& b) {return a + b.second;})));
}*/
template <Unsigned U, Integral I, Floating F>
constexpr F multinom_pmf (U N, std::pair<I, F>... args) {
assert(almost_equal(1.0, std::accumulate(args.begin(), args.end(), 0.0, [](auto& a, auto& b) {return a + b.second;})));
// ???
}
int main() {
static_assert(multinom<size_t>(5, 5) == 1);
static_assert(multinom<size_t>(5, 3, 2) == 10);
static_assert(multinom<size_t>(6, 2, 2, 2) == 90);
}
Желаемый интерфейс:
multinom_pmf<>(N, pair<I, F>... args) = multinom<>(N, /* first of args */) * std::pow(/* second of args */, /* first of args */) * ...
ex)
multinom_pmf<>(5, {3, 0.6}, {2, 0.4}) = multinom<>(5, 3, 2) * std::pow(0.6, 3) * std::pow(0.4, 2) = 0.3456
multinom_pmf<>(6, {2, 0.4}, {2, 0.35}, {2, 0.25}) = multinom<>(6, 2, 2, 2) * pow(0.4, 2) * pow(0.35, 2) * pow(0.25, 2) = 0.11025
Я хочу, чтобы функция могла проверить, что
N == sum of first of args (which would be done inside multinom() call)
1.0 == sum of second of args
Как я могу улучшить свои попытки? Заранее спасибо.