Muller
sample Muller's potential
muller.c
Go to the documentation of this file.
00001 /*
00002  * This work is licensed under a Creative Commons 
00003  * Attribution-Noncommercial-Share Alike 3.0 United States License.
00004  * 
00005  *    http://creativecommons.org/licenses/by-nc-sa/3.0/us/
00006  * 
00007  * You are free:
00008  * 
00009  *    to Share - to copy, distribute, display, and perform the work
00010  *    to Remix - to make derivative works
00011  * 
00012  * Under the following conditions:
00013  * 
00014  *    Attribution. You must attribute the work in the manner specified by the
00015  *    author or licensor (but not in any way that suggests that they endorse you
00016  *    or your use of the work).
00017  * 
00018  *    Noncommercial. You may not use this work for commercial purposes.
00019  * 
00020  *    Share Alike. If you alter, transform, or build upon this work, you may
00021  *    distribute the resulting work only under the same or similar license to
00022  *    this one.
00023  * 
00024  * For any reuse or distribution, you must make clear to others the license
00025  * terms of this work. The best way to do this is by including this header.
00026  * 
00027  * Any of the above conditions can be waived if you get permission from the
00028  * copyright holder.
00029  * 
00030  * Apart from the remix rights granted under this license, nothing in this
00031  * license impairs or restricts the author's moral rights.
00032  */
00033 
00034 
00087 #include <config.h>
00088 
00089 #include <stdlib.h>
00090 #include <stdio.h>
00091 #include <inttypes.h>
00092 #include <string.h>
00093 
00094 #include <jwsc/base/error.h>
00095 #include <jwsc/base/option.h>
00096 #include <jwsc/math/constants.h>
00097 #include <jwsc/stat/dynamics.h>
00098 
00099 #include "sampler.h"
00100 
00101 
00102 #define  NUM_OPTS_NO_ARG      2
00103 #define  NUM_OPTS_WITH_ARG    15
00104 
00105 #define  DEFAULT_SEED         289375
00106 #define  DEFAULT_ITERATIONS   1000
00107 #define  DEFAULT_HYBRID_LEAP_ITER 100
00108 #define  DEFAULT_START_X      0
00109 #define  DEFAULT_START_Y      0
00110 #define  DEFAULT_X_SIGMA      0.1
00111 #define  DEFAULT_X_MIN       -3.0
00112 #define  DEFAULT_X_MAX        1.5
00113 #define  DEFAULT_Y_SIGMA      0.1
00114 #define  DEFAULT_Y_MIN       -1.0
00115 #define  DEFAULT_Y_MAX        3.0
00116 #define  DEFAULT_DELTA_T      0.01
00117 #define  DEFAULT_ALPHA        0.9
00118 #define  DEFAULT_KICK         0
00119 #define  DEFAULT_HYPER_GAMMA  1.0e-5
00120 #define  DEFAULT_HYPER_ETA    1.0e-2
00121 #define  DEFAULT_HYPER_BIAS   150.0
00122 #define  DEFAULT_HYPER_SCALE  0.25
00123 #define  DEFAULT_SAMPLER      MH
00124 
00125 
00129 typedef enum
00130 {
00131     MH,
00132     LANGE,
00133     HYPER,
00134     STOCH,
00135     HYBRID
00136 }
00137 Sampler_type;
00138 
00139 
00141 static Option_no_arg opts_no_arg[NUM_OPTS_NO_ARG];
00142 
00144 static Option_with_arg opts_with_arg[NUM_OPTS_WITH_ARG];
00145     
00147 static uint32_t seed = DEFAULT_SEED;
00148 
00150 static uint32_t iterations = DEFAULT_ITERATIONS;
00151 
00153 static uint32_t hybrid_leap_iter = DEFAULT_HYBRID_LEAP_ITER;
00154 
00156 static double start_x = DEFAULT_START_X;
00157 
00159 static double start_y = DEFAULT_START_Y;
00160 
00162 static double x_sigma = DEFAULT_X_SIGMA;
00163 
00165 static double x_min = DEFAULT_X_MIN;
00166 
00168 static double x_max = DEFAULT_X_MAX;
00169 
00171 static double y_sigma = DEFAULT_Y_SIGMA;
00172 
00174 static double y_min = DEFAULT_Y_MIN;
00175 
00177 static double y_max = DEFAULT_Y_MAX;
00178 
00180 static double delta_t = DEFAULT_DELTA_T;
00181 
00183 static double alpha = DEFAULT_ALPHA;
00184 
00189 static uint32_t kick = DEFAULT_KICK;
00190 
00192 static double hyper_bias = DEFAULT_HYPER_BIAS;
00193 
00195 static double hyper_scale = DEFAULT_HYPER_SCALE;
00196 
00198 static double hyper_gamma = DEFAULT_HYPER_GAMMA;
00199 
00201 static double hyper_eta = DEFAULT_HYPER_ETA;
00202 
00204 static Sampler_type sampler = DEFAULT_SAMPLER;
00205 
00206 
00207 
00209 static void print_usage(void)
00210 {
00211     fprintf(stderr, "usage: muller OPTIONS\n");
00212     fprintf(stderr, "where OPTIONS is one or more of the following:\n");
00213     print_options(stderr, 25, NUM_OPTS_NO_ARG, opts_no_arg, NUM_OPTS_WITH_ARG,
00214             opts_with_arg);
00215 }
00216 
00218 static Error* process_help_opt(void)
00219 {
00220     print_usage();
00221     exit(EXIT_SUCCESS);
00222 }
00223 
00225 static Error* process_version_opt(void)
00226 {
00227     fprintf(stderr, "%s\n", MULLER_PACKAGE_STRING);
00228     exit(EXIT_SUCCESS);
00229 }
00230 
00232 static Error* process_seed_opt(Option_arg arg)
00233 {
00234     if (arg == NULL)
00235     {
00236         return JWSC_EARG("Option 'seed' requires an argument");
00237     }
00238     if (sscanf(arg, "%u", &seed) != 1)
00239     {
00240         return JWSC_EARG("Option 'seed' requires an argument");
00241     }
00242     return NULL;
00243 }
00244 
00246 static Error* process_iterations_opt(Option_arg arg)
00247 {
00248     if (arg == NULL)
00249     {
00250         return JWSC_EARG("Option 'iterations' requires an argument");
00251     }
00252     if (sscanf(arg, "%u", &iterations) != 1)
00253     {
00254         return JWSC_EARG("Option 'iterations' requires an argument");
00255     }
00256     return NULL;
00257 }
00258 
00260 static Error* process_hybrid_leap_iter_opt(Option_arg arg)
00261 {
00262     if (arg == NULL)
00263     {
00264         return JWSC_EARG("Option 'hybrid-leap-iter' requires an argument");
00265     }
00266     if (sscanf(arg, "%u", &hybrid_leap_iter) != 1)
00267     {
00268         return JWSC_EARG("Option 'hybrid-leap-iter' requires an argument");
00269     }
00270     return NULL;
00271 }
00272 
00274 static Error* process_start_x_opt(Option_arg arg)
00275 {
00276     if (arg == NULL)
00277     {
00278         return JWSC_EARG("Option 'start-x' requires an argument");
00279     }
00280     if (sscanf(arg, "%lf", &start_x) != 1)
00281     {
00282         return JWSC_EARG("Option 'start-x' must be > 0");
00283     }
00284     return NULL;
00285 }
00286 
00288 static Error* process_start_y_opt(Option_arg arg)
00289 {
00290     if (arg == NULL)
00291     {
00292         return JWSC_EARG("Option 'start-y' requires an argument");
00293     }
00294     if (sscanf(arg, "%lf", &start_y) != 1)
00295     {
00296         return JWSC_EARG("Option 'start-y' must be > 0");
00297     }
00298     return NULL;
00299 }
00300 
00302 static Error* process_delta_t_opt(Option_arg arg)
00303 {
00304     if (arg == NULL)
00305     {
00306         return JWSC_EARG("Option 'delta-t' requires an argument");
00307     }
00308     if (sscanf(arg, "%lf", &delta_t) != 1 || delta_t <= 0)
00309     {
00310         return JWSC_EARG("Option 'delta-t' must be > 0");
00311     }
00312     return NULL;
00313 }
00314 
00316 static Error* process_alpha_opt(Option_arg arg)
00317 {
00318     if (arg == NULL)
00319     {
00320         return JWSC_EARG("Option 'alpha' requires an argument");
00321     }
00322     if (sscanf(arg, "%lf", &alpha) != 1 || alpha < 0 || alpha > 1)
00323     {
00324         return JWSC_EARG("Option 'alpha' must be in [0,1]");
00325     }
00326     return NULL;
00327 }
00328 
00330 static Error* process_kick_opt(Option_arg arg)
00331 {
00332     if (arg == NULL)
00333     {
00334         return JWSC_EARG("Option 'kick' requires an argument");
00335     }
00336     if (sscanf(arg, "%u", &kick) != 1)
00337     {
00338         return JWSC_EARG("Option 'kick' requires an argument");
00339     }
00340     return NULL;
00341 }
00342 
00344 static Error* process_x_lim_opt(Option_arg arg)
00345 {
00346     if (arg == NULL)
00347     {
00348         return JWSC_EARG("Option 'x-lim' requires an argument");
00349     }
00350     if (sscanf(arg, "%lf,%lf", &x_min, &x_max) != 2)
00351     {
00352         return JWSC_EARG("Option 'x-lim' has format min,max");
00353     }
00354     if (x_max < x_min)
00355     {
00356         return JWSC_EARG("Option 'x-lim' max must be >= min");
00357     }
00358     return NULL;
00359 }
00360 
00362 static Error* process_x_sigma_opt(Option_arg arg)
00363 {
00364     if (arg == NULL)
00365     {
00366         return JWSC_EARG("Option 'x-sigma' requires an argument");
00367     }
00368     if (sscanf(arg, "%lf", &x_sigma) != 1 || x_sigma <= 1.0e-8)
00369     {
00370         return JWSC_EARG("Option 'x-sigma' must be > 0");
00371     }
00372     return NULL;
00373 }
00374 
00376 static Error* process_y_lim_opt(Option_arg arg)
00377 {
00378     if (arg == NULL)
00379     {
00380         return JWSC_EARG("Option 'y-lim' requires an argument");
00381     }
00382     if (sscanf(arg, "%lf,%lf", &y_min, &y_max) != 2)
00383     {
00384         return JWSC_EARG("Option 'y-lim' has format min,max");
00385     }
00386     if (y_max < y_min)
00387     {
00388         return JWSC_EARG("Option 'y-lim' max must be >= min");
00389     }
00390     return NULL;
00391 }
00392 
00394 static Error* process_y_sigma_opt(Option_arg arg)
00395 {
00396     if (arg == NULL)
00397     {
00398         return JWSC_EARG("Option 'y-sigma' requires an argument");
00399     }
00400     if (sscanf(arg, "%lf", &y_sigma) != 1 || y_sigma <= 1.0e-8)
00401     {
00402         return JWSC_EARG("Option 'y-sigma' must be > 0");
00403     }
00404     return NULL;
00405 }
00406 
00408 static Error* process_hyper_bias_opt(Option_arg arg)
00409 {
00410     if (arg == NULL)
00411     {
00412         return JWSC_EARG("Option 'hyper-bias' requires an argument");
00413     }
00414     if (sscanf(arg, "%lf", &hyper_bias) != 1)
00415     {
00416         return JWSC_EARG("Option 'hyper-bias' requires an argument");
00417     }
00418     return NULL;
00419 }
00420 
00422 static Error* process_hyper_scale_opt(Option_arg arg)
00423 {
00424     if (arg == NULL)
00425     {
00426         return JWSC_EARG("Option 'hyper-scale' requires an argument");
00427     }
00428     if (sscanf(arg, "%lf", &hyper_scale) != 1 || hyper_scale <= 1.0e-8)
00429     {
00430         return JWSC_EARG("Option 'hyper-scale' must be > 0");
00431     }
00432     return NULL;
00433 }
00434 
00436 static Error* process_sampler_opt(Option_arg arg)
00437 {
00438     if (arg == NULL)
00439     {
00440         return JWSC_EARG("Option 'sampler' requires an argument");
00441     }
00442     if (strncmp(arg, "mh", 2) == 0)
00443     {
00444         sampler = MH;
00445     }
00446     else if (strncmp(arg, "lange", 5) == 0)
00447     {
00448         sampler = LANGE;
00449     }
00450     else if (strncmp(arg, "hyper", 5) == 0)
00451     {
00452         sampler = HYPER;
00453     }
00454     else if (strncmp(arg, "stoch", 5) == 0)
00455     {
00456         sampler = STOCH;
00457     }
00458     else if (strncmp(arg, "hybrid", 6) == 0)
00459     {
00460         sampler = HYBRID;
00461     }
00462     else
00463     {
00464         return JWSC_EARG("Option 'sampler' must be one of {mh, lange, hyper, stoch, hybrid}");
00465     }
00466     return NULL;
00467 }
00468 
00469 
00470 
00471 
00473 int main(int argc, const char** argv)
00474 {
00475     int      argi;
00476     uint32_t i;
00477 
00478     Params p;
00479 
00480     Error*   err;
00481 
00482     Option_string        l_name;
00483     Option_flag          s_name;
00484     Option_desc          desc;
00485     Option_func_no_arg   fnoarg;
00486     Option_func_with_arg farg;
00487 
00488 
00489     i      = 0;
00490     l_name = "help";
00491     s_name = 'h';
00492     desc   = "Prints program usage.";
00493     fnoarg = process_help_opt;
00494     init_option_no_arg(&(opts_no_arg[i++]), l_name, s_name, desc, fnoarg);
00495 
00496     l_name = "version";
00497     s_name = 'v';
00498     desc   = "Prints program version.";
00499     fnoarg = process_version_opt;
00500     init_option_no_arg(&(opts_no_arg[i++]), l_name, s_name, desc, fnoarg);
00501 
00502     i      = 0;
00503     l_name = "seed";
00504     s_name = 0;
00505     desc   = "Random seed.";
00506     farg   = process_seed_opt;
00507     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00508 
00509     l_name = "iterations";
00510     s_name = 0;
00511     desc   = "Number of sampling iterations.";
00512     farg   = process_iterations_opt;
00513     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00514 
00515     l_name = "hybrid-leap-iter";
00516     s_name = 0;
00517     desc   = "Number of hybrid Monte Carlo leapfrog iterations.";
00518     farg   = process_hybrid_leap_iter_opt;
00519     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00520 
00521     l_name = "start-x";
00522     s_name = 0;
00523     desc   = "Starting x-coord position.";
00524     farg   = process_start_x_opt;
00525     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00526 
00527     l_name = "start-y";
00528     s_name = 0;
00529     desc   = "Starting y-coord position.";
00530     farg   = process_start_y_opt;
00531     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00532 
00533     l_name = "delta-t";
00534     s_name = 0;
00535     desc   = "Stochastic dynamics integration step-size for Langevin Monte Carlo.";
00536     farg   = process_delta_t_opt;
00537     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00538 
00539     l_name = "alpha";
00540     s_name = 0;
00541     desc   = "Stochastic dynamics step-size for Langevin Monte Carlo.";
00542     farg   = process_alpha_opt;
00543     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00544 
00545     l_name = "kick";
00546     s_name = 0;
00547     desc   = "Stochastic dynamics frequency to kick the particle by resetting the momenta. Zero disables any kicking. Must be > 0.";
00548     farg   = process_kick_opt;
00549     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00550 
00551     l_name = "x-sigma";
00552     s_name = 0;
00553     desc   = "Gaussian sigma for MH proposal of x. Must be > 0.";
00554     farg   = process_x_sigma_opt;
00555     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00556 
00557     l_name = "x-lim";
00558     s_name = 0;
00559     desc   = "Limits over the range of x. Has format min,max";
00560     farg   = process_x_lim_opt;
00561     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00562 
00563     l_name = "y-sigma";
00564     s_name = 0;
00565     desc   = "Gaussian sigma for MH proposal of y. Must be > 0.";
00566     farg   = process_y_sigma_opt;
00567     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00568 
00569     l_name = "y-lim";
00570     s_name = 0;
00571     desc   = "Limits over the range of y. Has format min,max.";
00572     farg   = process_y_lim_opt;
00573     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00574 
00575     l_name = "sampler";
00576     s_name = 0;
00577     desc   = "Type of sampler to use. Must be one of {mh, lange, hyper, stoch, hybrid}.";
00578     farg   = process_sampler_opt;
00579     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00580 
00581     l_name = "hyper-bias";
00582     s_name = 0;
00583     desc   = "Bias parameter for hyper sampling.";
00584     farg   = process_hyper_bias_opt;
00585     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00586 
00587     l_name = "hyper-scale";
00588     s_name = 0;
00589     desc   = "Scale parameter for hyper sampling.";
00590     farg   = process_hyper_scale_opt;
00591     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00592 
00593 
00594     if ((err = process_options(argc, argv, &argi, NUM_OPTS_NO_ARG, opts_no_arg,
00595                     NUM_OPTS_WITH_ARG, opts_with_arg)) != NULL)
00596     {
00597         print_error_msg_exit("muller", err->msg);
00598     }
00599 
00600     srand(seed); rand(); rand();
00601 
00602     if (start_x == DEFAULT_START_X)
00603     {
00604         start_x = sample_uniform_pdf_d(x_min, x_max);
00605     }
00606     if (start_y == DEFAULT_START_Y)
00607     {
00608         start_y = sample_uniform_pdf_d(y_min, y_max);
00609     }
00610 
00611     p.x = start_x;
00612     p.y = start_y;
00613 
00614     if (sampler == MH)
00615     {
00616         if ((err = metropolis_hastings(iterations, start_x, start_y, x_sigma,
00617                         x_min, x_max, y_sigma, y_min, y_max)) != NULL)
00618         {
00619             print_error_msg_exit("muller", err->msg);
00620         }
00621     }
00622     else if (sampler == LANGE)
00623     {
00624         if ((err = langevin_1_d(iterations, delta_t, &p, get_pt_from_params,
00625                         grad_energy_func, langevin_accept_sample)) 
00626                 != NULL)
00627         {
00628             print_error_msg_exit("muller", err->msg);
00629         }
00630     }
00631     else if (sampler == HYPER)
00632     {
00633         if ((err = langevin_hyperdynamics_1_d(iterations, delta_t, hyper_gamma,
00634                         hyper_eta, hyper_bias, hyper_scale, &p,
00635                         get_pt_from_params, set_params_from_pt, energy_func,
00636                         grad_energy_func, hyper_accept_sample)) != NULL)
00637         {
00638             print_error_msg_exit("muller", err->msg);
00639         }
00640     }
00641     else if (sampler == STOCH)
00642     {
00643         if ((err = stochastic_dynamics_1_d(iterations, delta_t, alpha, kick, &p,
00644                         get_pt_from_params, grad_energy_func,
00645                         stochastic_dynamics_accept_sample)) != NULL)
00646         {
00647             print_error_msg_exit("muller", err->msg);
00648         }
00649     }
00650     else if (sampler == HYBRID)
00651     {
00652         if ((err = hybrid_monte_carlo_1_d(iterations, hybrid_leap_iter,
00653                         delta_t, alpha, kick, &p, get_pt_from_params,
00654                         set_params_from_pt, energy_func, grad_energy_func,
00655                         hybrid_mc_accept_sample, NULL)) != NULL)
00656         {
00657             print_error_msg_exit("muller", err->msg);
00658         }
00659     }
00660 
00661     if (get_num_unhandled_errors() > 0)
00662     {
00663         print_error_msg_exit("muller", "Unhandled errors");
00664     }
00665 
00666     return EXIT_SUCCESS;
00667 }