ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
Distribution.cpp File Reference

The family-agnostic side of the Distribution hierarchy: the registries (family descriptors / factories, pairwise comparator and closure rules), their dispatch drivers, and the generic comparator quadrature fallback. More...

#include "DistributionCommon.h"
#include <cmath>
#include <map>
#include <string>
#include <tuple>
#include <utility>
Include dependency graph for Distribution.cpp:

Go to the source code of this file.

Namespaces

namespace  provsql

Functions

double provsql::numericQuantile (const Distribution &d, double p)
 Numeric inverse CDF: monotone bisection of cdf() over the family's integration window.
std::unique_ptr< Distributionprovsql::makeDistribution (const DistributionSpec &spec)
 Construct the per-family Distribution for a parsed spec.
ComparatorRuleRegistry – pairwise §B.2 closed forms

Closed-form \(P(X < Y)\) for an ordered pair of independent RV families.

On continuous distributions every ordered comparator reduces to \(P(X < Y)\) or its complement, so rules are keyed on the family pair alone (no operator in the key). Pairwise behaviour deliberately stays out of the Distribution interface: family files self-register their rules at static initialisation through provsql::ComparatorRuleRegistrar, so adding a family touches no existing file, and a missing rule is not an error – the driver falls back to a family-agnostic quadrature.

void provsql::registerComparatorRule (const char *x, const char *y, ComparatorRule rule)
 Register the \(P(X < Y)\) closed form for a family pair.
double provsql::comparatorPairLess (const Distribution &X, const Distribution &Y)
 \(P(X < Y)\) for two independent RVs.
ClosureRuleRegistry – pairwise family-closure folds on PLUS

Closed-form folds of a sum of independent scalar terms into a single distribution (Normal + Normal, same-rate Exponential / Erlang chains).

Like the comparator rules, pairwise behaviour stays out of the Distribution interface: family files self-register at static initialisation via provsql::ClosureRuleRegistrar, keyed on the (ordered) pair of families that may meet in the sum, and a registry miss simply means the sum stays unfolded (Monte Carlo handles it).

A rule receives the whole term list rather than reducing pairwise so its accumulation arithmetic (e.g. one variance sum with a single final square root) is not perturbed by intermediate re-serialisation.

void provsql::registerClosureRule (const char *x, const char *y, ClosureRule rule)
 Register the sum-closure rule for a family pair (name-token keyed, like the comparator rules).
void provsql::registerProductRule (const char *x, const char *y, ProductRule rule)
 Register the product-closure rule for a family pair (name-token keyed, like the sum-closure rules).
void provsql::registerTransformRule (const char *transform, const char *family, TransformRule rule)
 Register the image rule for transform ("ln" / "exp" / ...; the evaluator maps its arith opcodes to these names, keeping this registry opcode-free) applied to family.
std::unique_ptr< Distributionprovsql::closeProductFactors (const std::vector< const Distribution * > &factors)
 Fold a product of independent factors into a single distribution when a registered closure covers every family present (same first-vs-each dispatch as closePlusTerms); nullptr on any miss.
std::unique_ptr< Distributionprovsql::closeTransform (const char *transform, const Distribution &x)
 The image distribution of transform applied to x, when a registered rule covers x's family; nullptr otherwise.
std::unique_ptr< Distributionprovsql::closePlusTerms (const std::vector< ClosureTerm > &terms)
 Fold PLUS(terms) into a single distribution when a registered closure covers every family in the sum.
ConjugateRuleRegistry – exact conjugate-prior posterior updates

One-observation Bayesian updates for conjugate prior/likelihood pairs: the exact posterior of a latent, wired into one parameter slot of an observed leaf, stays in the prior's family with updated parameters.

The conjugate-posterior recogniser (ConjugatePosterior.cpp) folds these rules over an and_agg evidence conjunction of gate_observe atoms, replacing likelihood-weighting importance sampling with the closed form where a rule chain covers every observation.

Like the comparator / closure registries, the rules stay out of the Distribution interface: the likelihood family's implementation file self-registers its rule(s) at static initialisation, keyed by name tokens (no cross-file static-init order dependence), and a registry miss is a silent decline – the caller falls back to importance sampling unchanged.

void provsql::registerConjugateRule (const char *likelihood_family, int wired_param, const char *prior_family, const ConjugateRule &rule)
 Register the conjugate update for observations of likelihood_family whose parameter wired_param (0 = p1, 1 = p2) is the latent, against a prior of prior_family.
const ConjugateRuleprovsql::lookupConjugateRule (const std::string &likelihood_family, int wired_param, const std::string &prior_family)
 Look up the conjugate rule for (likelihood family, wired parameter position, prior family); nullptr on a miss.
DistributionRegistry – family descriptor table

Family implementations self-register their descriptor at static initialisation: the on-disk name token (the part before the colon in a gate_rv extra), the parameter count, the display metadata, and the constructor.

makeDistribution and parse_distribution_spec dispatch through this table, so adding a family means one new implementation file with one registrar – no existing factory, parser, or header is touched.

void provsql::registerDistributionFamily (const DistributionFamily &descriptor)
 Register a family; called by the registrar at static init.
std::vector< const DistributionFamily * > provsql::listDistributionFamilies ()
 Every registered family, sorted by name token.
const DistributionFamilyprovsql::lookupDistributionFamily (const std::string &name)
 Look up a family by its on-disk name token.

Detailed Description

The family-agnostic side of the Distribution hierarchy: the registries (family descriptors / factories, pairwise comparator and closure rules), their dispatch drivers, and the generic comparator quadrature fallback.

The per-family closed forms live in one file per family next to this one (normal.cpp, uniform.cpp, exponential.cpp, erlang.cpp); each registers itself at static initialisation, so adding a family means adding a file – nothing here changes.

Definition in file Distribution.cpp.