Skip to content
Snippets Groups Projects

Improve numerical stability of conditional_ppf

1 unresolved thread
Files
2
+ 34
7
@@ -78,13 +78,24 @@ double bayestar_distance_conditional_cdf(
}
typedef struct {
double p, mu, norm;
} conditional_ppf_params;
static void conditional_ppf_fdf(double r, void *params, double *f, double *df)
{
const double p = ((double*) params)[0];
const double mu = ((double *) params)[1];
const double norm = ((double *) params)[2];
*f = bayestar_distance_conditional_cdf(r, mu, 1, norm) - p;
*df = bayestar_distance_conditional_pdf(r, mu, 1, norm);
const conditional_ppf_params *p = (conditional_ppf_params *)params;
const double _f = bayestar_distance_conditional_cdf(r, p->mu, 1, p->norm);
const double _df = bayestar_distance_conditional_pdf(r, p->mu, 1, p->norm);
if (p->p > 0.5)
{
*f = log(1 - _f) - log(1 - p->p);
*df = -_df / (1 - _f);
} else {
*f = log(_f) - log(p->p);
*df = _df / _f;
}
}
@@ -104,6 +115,22 @@ static double conditional_ppf_df(double r, void *params)
}
static double conditional_ppf_initial_guess(double p, double mu)
{
/* Initial guess: ignore r^2 term;
* distribution becomes truncated Gaussian */
const double lo = gsl_cdf_ugaussian_P(-mu);
const double z = gsl_cdf_ugaussian_Pinv(p + (1 - p) * gsl_cdf_ugaussian_P(-mu)) + mu;
if (z > 0)
return z;
else if (mu > 0)
return mu; /* Fallback 1: mean */
else
return 0.5; /* Fallback 2: constant value */
}
double bayestar_distance_conditional_ppf(
double p, double mu, double sigma, double norm)
{
@@ -121,9 +148,9 @@ double bayestar_distance_conditional_ppf(
/* Set up variables for tracking progress toward the solution. */
static const int max_iter = 50;
double params[] = {p, mu, norm};
conditional_ppf_params params = {p, mu, norm};
int iter = 0;
double z = mu > 0 ? mu : 0.5; /* FIXME: better initial guess? */
double z = conditional_ppf_initial_guess(p, mu);
int status;
/* Set up solver (on stack). */
Loading