ex-1: generalise numeric_mode to take any pdf
This commit is contained in:
parent
ff56757258
commit
dce8cfb8b6
@ -8,9 +8,9 @@
|
|||||||
#include <gsl/gsl_integration.h>
|
#include <gsl/gsl_integration.h>
|
||||||
|
|
||||||
|
|
||||||
/* This is a wrapper needed by `landau_cdf` because
|
/* This is a wrapper needed by `landau_cdf` and
|
||||||
* the numerical integration expects a function
|
* other optimisation functions because the GSL
|
||||||
* with parameters.
|
* routines expect a function with parameters.
|
||||||
*/
|
*/
|
||||||
double landau_pdf(double x, void* params) {
|
double landau_pdf(double x, void* params) {
|
||||||
return gsl_ran_landau_pdf(x);
|
return gsl_ran_landau_pdf(x);
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/* This is a wrapper needed by `landau_cdf` because
|
/* This is a wrapper needed by `landau_cdf` and
|
||||||
* the numerical integration expects a function
|
* other optimisation functions because the GSL
|
||||||
* with parameters.
|
* routines expect a function with parameters.
|
||||||
*/
|
*/
|
||||||
double landau_pdf(double x, void* params);
|
double landau_pdf(double x, void* params);
|
||||||
|
|
||||||
|
13
ex-1/main.c
13
ex-1/main.c
@ -77,9 +77,18 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
fprintf(stderr, "\n\n# Mode comparison\n");
|
fprintf(stderr, "\n\n# Mode comparison\n");
|
||||||
|
|
||||||
// print the results
|
/* A structure used by the optimisation
|
||||||
double mode_e = numeric_mode(min, max);
|
* 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);
|
uncert mode_o = bootstrap_mode(r, sample, samples, 100);
|
||||||
|
|
||||||
|
// print the results
|
||||||
fprintf(stderr, "\n## Results\n");
|
fprintf(stderr, "\n## Results\n");
|
||||||
fprintf(stderr, "expected mode: %.7f\n", mode_e);
|
fprintf(stderr, "expected mode: %.7f\n", mode_e);
|
||||||
fprintf(stderr, "observed mode: %.4f±%.4f\n", mode_o.n, mode_o.s);
|
fprintf(stderr, "observed mode: %.4f±%.4f\n", mode_o.n, mode_o.s);
|
||||||
|
53
ex-1/tests.c
53
ex-1/tests.c
@ -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
|
/* This is a high-order function (ie a function that operates
|
||||||
* maximized.
|
* 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) {
|
double negate_func(double x, void * fp) {
|
||||||
return (-1) * gsl_ran_landau_pdf(x);
|
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
|
* The min,max parameters are the initial search
|
||||||
* interval for the optimisation.
|
* interval for the optimisation.
|
||||||
*/
|
*/
|
||||||
double numeric_mode(double min, double max) {
|
double numeric_mode(double min, double max,
|
||||||
// create function
|
gsl_function *pdf) {
|
||||||
gsl_function pdf;
|
|
||||||
pdf.function = &neg_landau_pdf;
|
/* Negate the PDF to maximise it by
|
||||||
pdf.params = NULL;
|
* using a GSL minimisation method.
|
||||||
|
* (There usually are no maximisation methods)
|
||||||
|
*/
|
||||||
|
gsl_function npdf;
|
||||||
|
npdf.function = &negate_func;
|
||||||
|
npdf.params = pdf;
|
||||||
|
|
||||||
// initialize minimization
|
// initialize minimization
|
||||||
double guess = 0;
|
double guess = 0;
|
||||||
@ -71,11 +93,11 @@ double numeric_mode(double min, double max) {
|
|||||||
int max_iter = 100;
|
int max_iter = 100;
|
||||||
double prec = 1e-7;
|
double prec = 1e-7;
|
||||||
int status;
|
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 * 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 {
|
do {
|
||||||
iter++;
|
iter++;
|
||||||
status = gsl_min_fminimizer_iterate(s);
|
status = gsl_min_fminimizer_iterate(s);
|
||||||
@ -86,9 +108,12 @@ double numeric_mode(double min, double max) {
|
|||||||
|
|
||||||
} while (status == GSL_CONTINUE && iter < max_iter);
|
} 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);
|
fprintf(stderr, "mode error: %.3g\n", max - min);
|
||||||
|
|
||||||
// Free memory
|
// free memory
|
||||||
gsl_min_fminimizer_free(s);
|
gsl_min_fminimizer_free(s);
|
||||||
return guess;
|
return guess;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
* from a Landau distribution.
|
* from a Landau distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <gsl/gsl_roots.h>
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/* Kolmogorov distribution CDF
|
/* Kolmogorov distribution CDF
|
||||||
@ -16,7 +18,8 @@ double kolmogorov_cdf(double D, int n);
|
|||||||
* The min,max parameters are the initial search
|
* The min,max parameters are the initial search
|
||||||
* interval for the optimisation.
|
* 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
|
/* Numerically computes the FWHM of Landau
|
||||||
|
Loading…
Reference in New Issue
Block a user