ex-1: generalise numeric_mode to take any pdf

This commit is contained in:
Michele Guerini Rocco 2020-04-06 16:57:00 +02:00
parent ff56757258
commit dce8cfb8b6
5 changed files with 60 additions and 23 deletions

View File

@ -8,9 +8,9 @@
#include <gsl/gsl_integration.h>
/* This is a wrapper needed by `landau_cdf` because
* the numerical integration expects a function
* with parameters.
/* This is a wrapper needed by `landau_cdf` and
* other optimisation functions because the GSL
* routines expect a function with parameters.
*/
double landau_pdf(double x, void* params) {
return gsl_ran_landau_pdf(x);

View File

@ -5,9 +5,9 @@
#pragma once
/* This is a wrapper needed by `landau_cdf` because
* the numerical integration expects a function
* with parameters.
/* This is a wrapper needed by `landau_cdf` and
* other optimisation functions because the GSL
* routines expect a function with parameters.
*/
double landau_pdf(double x, void* params);

View File

@ -77,9 +77,18 @@ int main(int argc, char** argv) {
fprintf(stderr, "\n\n# Mode comparison\n");
// print the results
double mode_e = numeric_mode(min, max);
/* A structure used by the optimisation
* routines in numeric_mode and others
* functions below.
*/
gsl_function pdf;
pdf.function = &landau_pdf;
pdf.params = NULL;
double mode_e = numeric_mode(min, max, &pdf);
uncert mode_o = bootstrap_mode(r, sample, samples, 100);
// print the results
fprintf(stderr, "\n## Results\n");
fprintf(stderr, "expected mode: %.7f\n", mode_e);
fprintf(stderr, "observed mode: %.4f±%.4f\n", mode_o.n, mode_o.s);

View File

@ -45,12 +45,29 @@ double kolmogorov_cdf(double D, int n) {
}
/* This is a wrapper needed by `numeric_mode` because
* the minimization expects a function to be minimized and not
* maximized.
/* This is a high-order function (ie a function that operates
* on functions) in disguise. It takes a function f and produces
* a function that computes -f. In lambda calculus it would be
* the map λf.λx -f(x).
*
* Since there is no notion of lambda functions in C (the
* standard one, at least) we use a trick involving the
* gsl_function struct: `negate_func(x, fp)` takes a point `x`
* and a gsl_function `fp` as the usual void pointer `params`.
* It then calls the function `fp.function` with `x` and their
* `fp.params` and return the negated result.
*
* So, given a `gsl_function f` its negated function is
* contructed as follows:
*
* gsl_function nf;
* nf.function = &negate_func;
* nf.params = &f;
*/
double neg_landau_pdf(double x, void* params) {
return (-1) * gsl_ran_landau_pdf(x);
double negate_func(double x, void * fp) {
gsl_function f = *((gsl_function*) fp);
return -f.function(x, f.params);
}
@ -59,11 +76,16 @@ double neg_landau_pdf(double x, void* params) {
* The min,max parameters are the initial search
* interval for the optimisation.
*/
double numeric_mode(double min, double max) {
// create function
gsl_function pdf;
pdf.function = &neg_landau_pdf;
pdf.params = NULL;
double numeric_mode(double min, double max,
gsl_function *pdf) {
/* Negate the PDF to maximise it by
* using a GSL minimisation method.
* (There usually are no maximisation methods)
*/
gsl_function npdf;
npdf.function = &negate_func;
npdf.params = pdf;
// initialize minimization
double guess = 0;
@ -71,11 +93,11 @@ double numeric_mode(double min, double max) {
int max_iter = 100;
double prec = 1e-7;
int status;
const gsl_min_fminimizer_type * T = gsl_min_fminimizer_goldensection;
const gsl_min_fminimizer_type * T = gsl_min_fminimizer_brent;
gsl_min_fminimizer * s = gsl_min_fminimizer_alloc(T);
gsl_min_fminimizer_set(s, &pdf, guess, min, max);
gsl_min_fminimizer_set(s, &npdf, guess, min, max);
// minimization
// minimisation
do {
iter++;
status = gsl_min_fminimizer_iterate(s);
@ -86,9 +108,12 @@ double numeric_mode(double min, double max) {
} while (status == GSL_CONTINUE && iter < max_iter);
/* The error is simply given by the width of
* the final interval containing the solution
*/
fprintf(stderr, "mode error: %.3g\n", max - min);
// Free memory
// free memory
gsl_min_fminimizer_free(s);
return guess;
}

View File

@ -3,6 +3,8 @@
* from a Landau distribution.
*/
#include <gsl/gsl_roots.h>
#pragma once
/* Kolmogorov distribution CDF
@ -16,7 +18,8 @@ double kolmogorov_cdf(double D, int n);
* The min,max parameters are the initial search
* interval for the optimisation.
*/
double numeric_mode(double min, double max);
double numeric_mode(double min, double max,
gsl_function *pdf);
/* Numerically computes the FWHM of Landau