Bayes-Laplace Rule
Name
UxHwDoubleBayesLaplace, UxHwFloatBayesLaplace — Perform Bayesian inference with distributional arithmetic.
Synopsis
#include <uxhw.h>
double UxHwDoubleBayesLaplace(
double (*statisticalModel)(void *, double),
void * modelParams,
double prior,
double observedData,
size_t numberOfObservations
);
float UxHwFloatBayesLaplace(
float (*statisticalModel)(void *, float),
void * modelParams,
float prior,
float observedData,
size_t numberOfObservations
);
Description
Performs Bayesian inference to calculate and return the posterior distribution of the parameter using Bayes' rule (also known as Bayes-Laplace rule):
where is the prior, is the likelihood, and is the posterior. The function returns the normalized posterior. If is a discrete distribution, the normalizing constant (the marginal likelihood) is replaced by:
The parameter and each observation are scalar (one-dimensional) values, and observations are assumed to be independent and identically distributed according to .
Parameters
-
statisticalModel— A pointer to a function that calculates the distribution . Takes parameters ofmodelParamsand a particle valuedtheta. For a giventheta, this function returns a distribution for the given observations. -
modelParams— A pointer to additional parameters required by the distribution (such as known variances or calibration constants). PassNULLif none. -
prior— The prior distribution of the parameter , which must be one-dimensional. This can be a parametric distribution (e.g.,UxHwDoubleUniformDist(),UxHwDoubleGaussDist()) or an empirical distribution created from samples (e.g.,UxHwDoubleDistFromSamples()). -
observedData— The empirical distribution of observed data:- For a single observation, pass the measured value directly (treated as a point-mass distribution).
- For multiple observations, create a distribution using
UxHwDoubleDistFromSamples(samples, count).
-
numberOfObservations— The number of independent observations inobservedData. This parameter scales the joint likelihood across multiple observations, such that is correctly computed as .
Return Values
Returns the posterior distribution .
✏️ Example: Inferring the Mean from Noisy Measurements
#include <uxhw.h>
#include <stdio.h>
typedef struct
{
double sigma;
} ModelParameters;
/*
* Likelihood: P(observation | theta) modeled as Gaussian noise.
*/
double
measurementModel(void * args, double theta)
{
ModelParameters * p = (ModelParameters *)args;
return UxHwDoubleGaussDist(theta, p->sigma);
}
typedef enum
{
kNumObservations = 5,
} ObservationConstants;
int
main(void)
{
/*
* Prior: theta uniformly distributed between 0 and 2.
*/
double prior = UxHwDoubleUniformDist(0.0, 2.0);
/*
* Observed measurements
*/
double measurements[kNumObservations] = {0.9, 0.95, 0.99, 1.1, 1.2};
double observedData = UxHwDoubleDistFromSamples(measurements, kNumObservations);
/*
* Likelihood standard deviation
*/
ModelParameters params = {.sigma = 0.4};
/*
* Compute posterior distribution over theta
*/
double posterior = UxHwDoubleBayesLaplace(
&measurementModel,
¶ms,
prior,
observedData,
kNumObservations
);
printf("Prior: %lf\n", prior);
printf("Posterior: %lf\n", posterior);
return 0;
}
✏️ Advanced Example: Importance Sampling via Bayesian Inference
Importance sampling draws samples from a tractable proposal distribution and reweights them to produce an approximation of a target distribution , using the importance weight:
Bayes' rule provides a natural way to perform this reweighting. Treating the proposal as the prior and choosing a likelihood proportional to , the posterior becomes:
so UxHwDoubleBayesLaplace() calculates the target distribution directly. The proportionality constant in is included within the marginal likelihood normalization.
In the example below, the target is and the proposal is . The likelihood is constructed as , whose density at is and is proportional to the importance weight.
#include <uxhw.h>
#include <stdio.h>
#include <math.h>
/*
* Importance Sampling: Target p(x) = Gaussian( µ = 5.0, σ = 5.0)
* Proposal q(x) = Uniform[0, 10]
* Weight w(x) = p(x) / q(x)
*/
typedef struct
{
double mu;
double sigma;
double proposalDensity;
} ImportanceSamplingParameters;
double
importanceWeightModel(void * params, double x)
{
ImportanceSamplingParameters * p = (ImportanceSamplingParameters *) params;
/*
* Target distribution: p(x) = Gaussian(5.0, 5.0)
*/
double targetDensity = exp(-0.5 * pow((x - p->mu) / p->sigma, 2.0))
/ (p->sigma * sqrt(2.0 * M_PI));
/*
* Importance weight: w(x) = p(x) / q(x)
*/
double weight = targetDensity / p->proposalDensity;
/*
* Return a likelihood that is proportional to the importance weight.
* Given that the density of N(0, sigma) at 0 is 1 / (sigma * sqrt(2*pi)),
* setting sigma = 1/weight makes the likelihood proportional to the weight.
*/
double sigma = 1.0 / weight;
return UxHwDoubleGaussDist(0.0, sigma);
}
int
main(void)
{
/*
* Proposal distribution (our "prior"): Uniform[0, 10]
* Easy to sample from, but wrong shape
*/
ImportanceSamplingParameters params = {.mu = 5.0, .sigma = 5.0, .proposalDensity = 0.1};
double proposal = UxHwDoubleUniformDist(0.0, 10.0);
printf("Proposal mean: %lf (uniform 0-10)\n", proposal);
/*
* Apply importance sampling via Bayes' rule:
* The likelihood reweights uniform samples to match Gaussian(5.0, 5.0)
*/
double target = UxHwDoubleBayesLaplace(
&importanceWeightModel,
¶ms,
proposal,
0.0, /* reference point for likelihood evaluation */
1
);
printf("Target mean: %lf (should be ~5.0)\n", target);
return 0;
}
Comparison with Other Inference Methods
This distributional approach computes the posterior directly without assuming any unimodality, smoothness, or parametric form for the posterior. This differentiates it from other inference methods, such as Markov Chain Monte Carlo, which requires sampling and convergence diagnostics; variational inference, which approximates the posterior within a chosen parametric family (e.g., mean-field); and the Laplace approximation, which assumes a unimodal posterior with a smooth density.