ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
PivotIntegration.h
Go to the documentation of this file.
1#ifndef PIVOT_INTEGRATION_H
2#define PIVOT_INTEGRATION_H
3
4/**
5 * @file PivotIntegration.h
6 * @brief Shared 1-D quadrature core for the pivot-conjunction and
7 * order-statistic closed forms.
8 *
9 * The exact evaluators for guard-partition shapes all reduce to the same
10 * one-dimensional integral over a pivot RV's support — the layer-cake
11 * order-statistic means, the RV-vs-RV conditional moments, the
12 * pivot-conjunction moments @f$\int x^k f_X \prod_j W_j\,dx@f$ in
13 * @c src/Expectation.cpp, and the analytic @f$2^k@f$ joint table over a
14 * shared-pivot island in @c src/HybridEvaluator.cpp. This header holds
15 * the numeric core they share: the composite-Simpson driver (with the
16 * common NaN-aborts-to-NaN convention, so an undefined density/CDF makes
17 * the caller decline to Monte Carlo), the panel-count constant, the
18 * @c binomial helper, and the central-moment binomial expansion over a
19 * raw-moment closure.
20 */
21
22#include <cmath>
23#include <limits>
24#include <optional>
25
26namespace provsql {
27
28/** Panel count shared by every composite-Simpson quadrature over a
29 * distribution's integration range: exact for the low-degree polynomial
30 * integrands of the Uniform cases, high-accuracy otherwise. */
31constexpr int kSimpsonPanels = 4000;
32
33/**
34 * @brief Composite-Simpson @f$\int_{lo}^{hi} f(x)\,dx@f$ with @p N panels.
35 *
36 * @p N must be even (every caller passes @c kSimpsonPanels). A NaN from
37 * @p f aborts the quadrature and returns NaN — the callers' shared
38 * convention for "a density / CDF is undefined here, decline to MC".
39 */
40template <typename F>
41double simpsonIntegrate(double lo, double hi, int N, F &&f)
42{
43 const double h = (hi - lo) / N;
44 double acc = 0.0;
45 for (int i = 0; i <= N; ++i) {
46 const double x = lo + i * h;
47 const double v = f(x);
48 if (std::isnan(v)) return std::numeric_limits<double>::quiet_NaN();
49 const double coeff = (i == 0 || i == N) ? 1.0 : (i % 2 == 1 ? 4.0 : 2.0);
50 acc += coeff * v;
51 }
52 return acc * h / 3.0;
53}
54
55/** @brief Binomial coefficient @f$\binom{n}{k}@f$ as a double (exact for
56 * the small orders the moment expansions use). */
57inline double binomial(unsigned n, unsigned k)
58{
59 if (k > n) return 0.0;
60 if (k > n - k) k = n - k;
61 double r = 1.0;
62 for (unsigned i = 1; i <= k; ++i) {
63 r *= static_cast<double>(n - i + 1);
64 r /= static_cast<double>(i);
65 }
66 return r;
67}
68
69/**
70 * @brief Central moment of order @p k from a raw-moment closure:
71 * @f$E[(X-\mu)^k] = \sum_{i=0}^{k} \binom{k}{i} (-\mu)^{k-i} E[X^i]@f$.
72 *
73 * @p raw maps a moment order to the (conditional) raw moment, returning
74 * @c std::nullopt when it cannot be resolved — which propagates, so the
75 * caller falls back exactly as it would for the raw moment itself.
76 * @c raw(0) must be @c 1.
77 */
78template <typename Raw>
79std::optional<double> centralFromRaw(unsigned k, Raw &&raw)
80{
81 auto mu_opt = raw(1);
82 if (!mu_opt) return std::nullopt;
83 const double mu = *mu_opt;
84 if (k == 1) return 0.0;
85 double total = 0.0;
86 for (unsigned i = 0; i <= k; ++i) {
87 auto m_i = raw(i);
88 if (!m_i) return std::nullopt;
89 total += binomial(k, i)
90 * std::pow(-mu, static_cast<double>(k - i)) * (*m_i);
91 }
92 return total;
93}
94
95} // namespace provsql
96
97#endif /* PIVOT_INTEGRATION_H */
std::optional< double > centralFromRaw(unsigned k, Raw &&raw)
Central moment of order k from a raw-moment closure: .
double simpsonIntegrate(double lo, double hi, int N, F &&f)
Composite-Simpson with N panels.
double binomial(unsigned n, unsigned k)
Binomial coefficient as a double (exact for the small orders the moment expansions use).
constexpr int kSimpsonPanels
Panel count shared by every composite-Simpson quadrature over a distribution's integration range: exa...