Polyfit
fit a polynomial
polygen.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 
00046 #include <config.h>
00047 
00048 #include <stdlib.h>
00049 #include <stdio.h>
00050 #include <assert.h>
00051 #include <inttypes.h>
00052 #include <math.h>
00053 
00054 #include <jwsc/base/error.h>
00055 #include <jwsc/base/option.h>
00056 #include <jwsc/vector/vector.h>
00057 #include <jwsc/vector/vector_io.h>
00058 #include <jwsc/matrix/matrix.h>
00059 #include <jwsc/matrix/matrix_io.h>
00060 #include <jwsc/matrix/matrix_math.h>
00061 #include <jwsc/prob/pdf.h>
00062 #include <jwsc/prob/mv_pdf.h>
00063 #include <jwsc/stat/regress.h>
00064 
00065 
00066 #define  NUM_OPTS_NO_ARG    2
00067 #define  NUM_OPTS_WITH_ARG  9
00068 
00069 #define  DEFAULT_SEED             289375
00070 #define  DEFAULT_SIGMA            1.0f
00071 #define  DEFAULT_DEGREE           1
00072 #define  DEFAULT_NUM_PTS          100
00073 #define  DEFAULT_W_MU             0.0
00074 #define  DEFAULT_W_SIGMA          0.1
00075 #define  DEFAULT_W_MIN           -2
00076 #define  DEFAULT_W_MAX            2
00077 #define  DEFAULT_X_MIN           -10
00078 #define  DEFAULT_X_MAX            10
00079 #define  DEFAULT_OUTLIER          0
00080 #define  DEFAULT_OUTLIER_SIGMA    6.0f
00081 
00082 
00084 static Option_no_arg opts_no_arg[NUM_OPTS_NO_ARG];
00085 
00087 static Option_with_arg opts_with_arg[NUM_OPTS_WITH_ARG];
00088 
00090 static uint32_t seed = DEFAULT_SEED;
00091 
00093 static float sigma = DEFAULT_SIGMA;
00094 
00096 static uint32_t degree = DEFAULT_DEGREE;
00097 
00099 static uint32_t num_pts = DEFAULT_NUM_PTS;
00100 
00102 static float w_mu = DEFAULT_W_MU;
00103 
00105 static float w_sigma = DEFAULT_W_SIGMA;
00106 
00108 static float w_min = DEFAULT_W_MIN;
00109 
00111 static float w_max = DEFAULT_W_MAX;
00112 
00114 static float x_min = DEFAULT_X_MIN;
00115 
00117 static float x_max = DEFAULT_X_MAX;
00118 
00120 static float outlier = DEFAULT_OUTLIER;
00121 
00123 static float outlier_sigma = DEFAULT_OUTLIER_SIGMA;
00124 
00125 static enum { GAUSS=0, UNIFORM } w_sample_t;
00126 
00127 
00129 static void print_usage(void)
00130 {
00131     fprintf(stderr, "usage: polygen OPTIONS\n");
00132     fprintf(stderr, "where OPTIONS is one or more of the following:\n");
00133     print_options(stderr, 25, NUM_OPTS_NO_ARG, opts_no_arg, NUM_OPTS_WITH_ARG, 
00134             opts_with_arg);
00135 }
00136 
00138 static Error* process_help_opt(void)
00139 {
00140     print_usage();
00141     exit(EXIT_SUCCESS);
00142 }
00143 
00145 static Error* process_version_opt(void)
00146 {
00147     fprintf(stderr, "%s\n", POLYFIT_PACKAGE_STRING);
00148     exit(EXIT_SUCCESS);
00149 }
00150 
00152 static Error* process_seed_opt(Option_arg arg)
00153 {
00154     if (arg == NULL)
00155     {
00156         return JWSC_EARG("Option 'seed' requires an argument");
00157     }
00158     if (sscanf(arg, "%u", &seed) != 1)
00159     {
00160         return JWSC_EARG("Option 'seed' requires an argument");
00161     }
00162     return NULL;
00163 }
00164 
00166 static Error* process_sigma_opt(Option_arg arg)
00167 {
00168     if (arg == NULL)
00169     {
00170         return JWSC_EARG("Option 'sigma' requires an argument");
00171     }
00172     if (sscanf(arg, "%f", &sigma) != 1 || sigma <= 1.0e-6)
00173     {
00174         return JWSC_EARG("Option 'sigma' must be > 0");
00175     }
00176     return NULL;
00177 }
00178 
00180 static Error* process_degree_opt(Option_arg arg)
00181 {
00182     if (arg == NULL)
00183     {
00184         return JWSC_EARG("Option 'degree' requires an argument");
00185     }
00186     if (sscanf(arg, "%u", &degree) != 1)
00187     {
00188         return JWSC_EARG("Option 'degree' requires an argument");
00189     }
00190     return NULL;
00191 }
00192 
00194 static Error* process_num_pts_opt(Option_arg arg)
00195 {
00196     if (arg == NULL)
00197     {
00198         return JWSC_EARG("Option 'num-pts' requires an argument");
00199     }
00200     if (sscanf(arg, "%u", &num_pts) != 1)
00201     {
00202         return JWSC_EARG("Option 'num-pts' requires an argument");
00203     }
00204     return NULL;
00205 }
00206 
00208 static Error* process_w_gauss_opt(Option_arg arg)
00209 {
00210     if (arg == NULL)
00211     {
00212         return JWSC_EARG("Option 'w-gauss' requires an argument");
00213     }
00214     if (sscanf(arg, "%f,%f", &w_mu, &w_sigma) != 2)
00215     {
00216         return JWSC_EARG("Option 'w-gauss' has format mu,sigma");
00217     }
00218     if (w_sigma < 0.01)
00219     {
00220         return JWSC_EARG("Option 'w-uni': min > max");
00221     }
00222     w_sample_t = GAUSS;
00223     return NULL;
00224 }
00225 
00227 static Error* process_w_uni_opt(Option_arg arg)
00228 {
00229     if (arg == NULL)
00230     {
00231         return JWSC_EARG("Option 'w-uni' requires an argument");
00232     }
00233     if (sscanf(arg, "%f,%f", &w_min, &w_max) != 2)
00234     {
00235         return JWSC_EARG("Option 'w-uni' has format min,max");
00236     }
00237     if (w_min > w_max)
00238     {
00239         return JWSC_EARG("Option 'w-uni': min > max");
00240     }
00241     w_sample_t = UNIFORM;
00242     return NULL;
00243 }
00244 
00246 static Error* process_x_range_opt(Option_arg arg)
00247 {
00248     if (arg == NULL)
00249     {
00250         return JWSC_EARG("Option 'x-range' requires an argument");
00251     }
00252     if (sscanf(arg, "%f,%f", &x_min, &x_max) != 2)
00253     {
00254         return JWSC_EARG("Option 'x-range' has format min,max");
00255     }
00256     if (x_min > x_max)
00257     {
00258         return JWSC_EARG("Option 'x-range': min > max");
00259     }
00260     return NULL;
00261 }
00262 
00264 static Error* process_outlier_opt(Option_arg arg)
00265 {
00266     if (arg == NULL)
00267     {
00268         return JWSC_EARG("Option 'outlier' requires an argument");
00269     }
00270     if (sscanf(arg, "%f", &outlier) != 1 || outlier < 0 || outlier > 1)
00271     {
00272         return JWSC_EARG("Option 'outlier' must be in [0,1]");
00273     }
00274     return NULL;
00275 }
00276 
00278 static Error* process_outlier_sigma_opt(Option_arg arg)
00279 {
00280     if (arg == NULL)
00281     {
00282         return JWSC_EARG("Option 'outlier-sigma' requires an argument");
00283     }
00284     if (sscanf(arg, "%f", &outlier_sigma) != 1 || outlier_sigma <= 1.0e-6)
00285     {
00286         return JWSC_EARG("Option 'outlier-sigma' must be > 0");
00287     }
00288     return NULL;
00289 }
00290 
00291 
00292 static void sample_w(Vector_d** w_out)
00293 {
00294     uint32_t d;
00295     Vector_d* w_mu_v = 0;
00296     Matrix_d* w_sigma_m = 0;
00297 
00298     if (w_sample_t == GAUSS)
00299     {
00300         create_init_vector_d(&w_mu_v, degree+1, w_mu);
00301         create_identity_matrix_d(&w_sigma_m, degree+1);
00302         multiply_matrix_by_scalar_d(&w_sigma_m, w_sigma_m, w_sigma);
00303         assert(sample_mv_gaussian_pdf_d(w_out, w_mu_v, w_sigma_m) == 0);
00304     }
00305     else if (w_sample_t == UNIFORM)
00306     {
00307         create_vector_d(w_out, degree+1);
00308         for (d = 0; d <= degree; d++)
00309         {
00310             (*w_out)->elts[ d ] = sample_uniform_pdf_d(w_min, w_max);
00311         }
00312     }
00313     else
00314     {
00315         abort();
00316     }
00317 
00318     free_vector_d(w_mu_v);
00319     free_matrix_d(w_sigma_m);
00320 }
00321 
00322 
00324 int main(int argc, const char** argv)
00325 {
00326     int      argi;
00327     uint32_t i, d;
00328 
00329     Option_string        l_name;
00330     Option_flag          s_name;
00331     Option_desc          desc;
00332     Option_func_no_arg   fnoarg;
00333     Option_func_with_arg farg;
00334 
00335     Vector_d* w = NULL;
00336     Vector_d* x = NULL;
00337     Vector_d* y = NULL;
00338     Error*    err;
00339 
00340     i      = 0;
00341     l_name = "help";
00342     s_name = 'h';
00343     desc   = "Prints program usage.";
00344     fnoarg = process_help_opt;
00345     init_option_no_arg(&(opts_no_arg[i++]), l_name, s_name, desc, fnoarg);
00346 
00347     l_name = "version";
00348     s_name = 'v';
00349     desc   = "Prints program version.";
00350     fnoarg = process_version_opt;
00351     init_option_no_arg(&(opts_no_arg[i++]), l_name, s_name, desc, fnoarg);
00352 
00353     i      = 0;
00354     l_name = "seed";
00355     s_name = 0;
00356     desc   = "Random seed.";
00357     farg   = process_seed_opt;
00358     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00359 
00360     l_name = "w-gauss";
00361     s_name = 0;
00362     desc   = "Gaussian over w to generate points from. Has format mu,sigma.";
00363     farg   = process_w_gauss_opt;
00364     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00365 
00366     l_name = "w-uni";
00367     s_name = 0;
00368     desc   = "Uniform range over w to generate points from. Has format min,max.";
00369     farg   = process_w_uni_opt;
00370     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00371 
00372     l_name = "x-range";
00373     s_name = 0;
00374     desc   = "Range over x to generate points from.";
00375     farg   = process_x_range_opt;
00376     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00377 
00378     l_name = "sigma";
00379     s_name = 0;
00380     desc   = "Gaussian sigma for polynomial point generation.";
00381     farg   = process_sigma_opt;
00382     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00383 
00384     l_name = "outlier";
00385     s_name = 0;
00386     desc   = "Percentage of points to generate as outliers.";
00387     farg   = process_outlier_opt;
00388     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00389 
00390     l_name = "outlier-sigma";
00391     s_name = 0;
00392     desc   = "Gaussian sigma for polynomial outlier point generation.";
00393     farg   = process_outlier_sigma_opt;
00394     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00395 
00396     l_name = "degree";
00397     s_name = 'd';
00398     desc   = "Polynomial degree.";
00399     farg   = process_degree_opt;
00400     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00401 
00402     l_name = "num-pts";
00403     s_name = 'n';
00404     desc   = "Number of points to generate.";
00405     farg   = process_num_pts_opt;
00406     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00407 
00408     if ((err = process_options(argc, argv, &argi, NUM_OPTS_NO_ARG, opts_no_arg, 
00409                     NUM_OPTS_WITH_ARG, opts_with_arg)) != NULL)
00410     {
00411         print_error_msg_exit("polygen", err->msg);
00412     }
00413 
00414     srand(seed); rand(); rand();
00415 
00416     sample_w(&w);
00417     create_vector_d(&x, num_pts);
00418     create_vector_d(&y, num_pts);
00419 
00420     for (i = 0; i < num_pts; i++)
00421     {
00422         x->elts[ i ] = sample_uniform_pdf_d(x_min, x_max);
00423 
00424         if (outlier > sample_uniform_pdf_d(0, 1))
00425         {
00426             y->elts[ i ] = sample_gaussian_pdf_d(0, outlier_sigma, 
00427                     -6*outlier_sigma, 6*outlier_sigma);
00428             fprintf(stderr, "outlier[ %2d ]: %f, %f\n", i, x->elts[ i ], y->elts[ i ]);
00429         }
00430         else
00431         {
00432             y->elts[ i ] = sample_gaussian_pdf_d(0, sigma, -6*sigma, 6*sigma);
00433         }
00434 
00435 
00436         for (d = 0; d <= degree; d++)
00437         {
00438             y->elts[ i ] += w->elts[ d ] * pow(x->elts[ i ], d);
00439         }
00440 
00441         fprintf(stdout, "%13.6e  %13.6e\n", x->elts[ i ], y->elts[ i ]);
00442     }
00443 
00444     fprintf(stderr, "y(x) = %.6e", w->elts[ 0 ]);
00445     for (d = 1; d <= degree; d++)
00446     {
00447         fprintf(stderr, " + %.6e*x**%d", w->elts[ d ], d);
00448     }
00449     fprintf(stderr, "\n");
00450 
00451 
00452     free_vector_d(w);
00453     free_vector_d(x);
00454     free_vector_d(y);
00455 
00456     return EXIT_SUCCESS;
00457 }