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>
|
||||
|
||||
|
||||
/* 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);
|
||||
|
@ -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);
|
||||
|
||||
|
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");
|
||||
|
||||
// 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);
|
||||
|
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
|
||||
* 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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user