Polyfit
fit a polynomial
polyfit.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 
00096 #include <config.h>
00097 
00098 #include <stdlib.h>
00099 #include <stdio.h>
00100 #include <assert.h>
00101 #include <inttypes.h>
00102 #include <math.h>
00103 
00104 #include <jwsc/base/error.h>
00105 #include <jwsc/base/option.h>
00106 #include <jwsc/vector/vector.h>
00107 #include <jwsc/matrix/matrix.h>
00108 #include <jwsc/matrix/matrix_io.h>
00109 #include <jwsc/matrix/matrix_math.h>
00110 #include <jwsc/stat/regress.h>
00111 
00112 
00113 #define  NUM_OPTS_NO_ARG    2
00114 #define  NUM_OPTS_WITH_ARG  4
00115 
00116 #define  DEFAULT_SEED    289375
00117 #define  DEFAULT_SIGMA   1.0f
00118 #define  DEFAULT_DEGREE  1
00119 
00120 #define  DEFAULT_RANSAC_ENABLED  0
00121 #define  DEFAULT_RANSAC_N        0
00122 #define  DEFAULT_RANSAC_K        0
00123 #define  DEFAULT_RANSAC_T        0
00124 #define  DEFAULT_RANSAC_D        0
00125 
00126 
00128 static Option_no_arg opts_no_arg[NUM_OPTS_NO_ARG];
00129 
00131 static Option_with_arg opts_with_arg[NUM_OPTS_WITH_ARG];
00132 
00134 static uint32_t seed = DEFAULT_SEED;
00135 
00137 static float sigma = DEFAULT_SIGMA;
00138 
00140 static uint32_t degree = DEFAULT_DEGREE;
00141 
00143 static struct
00144 {
00145     uint8_t enabled;
00146     uint32_t n;
00147     uint32_t k;
00148     float    t;
00149     uint32_t d;
00150 }
00151 ransac = { DEFAULT_RANSAC_ENABLED, DEFAULT_RANSAC_N, DEFAULT_RANSAC_K, DEFAULT_RANSAC_T, DEFAULT_RANSAC_D };
00152 
00153 
00155 static void print_usage(void)
00156 {
00157     fprintf(stderr, "usage: polyfit OPTIONS\n");
00158     fprintf(stderr, "where OPTIONS is one or more of the following:\n");
00159     print_options(stderr, 25, NUM_OPTS_NO_ARG, opts_no_arg, NUM_OPTS_WITH_ARG, 
00160             opts_with_arg);
00161 }
00162 
00164 static Error* process_help_opt(void)
00165 {
00166     print_usage();
00167     exit(EXIT_SUCCESS);
00168 }
00169 
00171 static Error* process_version_opt(void)
00172 {
00173     fprintf(stderr, "%s\n", POLYFIT_PACKAGE_STRING);
00174     exit(EXIT_SUCCESS);
00175 }
00176 
00178 static Error* process_seed_opt(Option_arg arg)
00179 {
00180     if (arg == NULL)
00181     {
00182         return JWSC_EARG("Option 'seed' requires an argument");
00183     }
00184     if (sscanf(arg, "%u", &seed) != 1)
00185     {
00186         return JWSC_EARG("Option 'seed' requires an argument");
00187     }
00188     return NULL;
00189 }
00190 
00192 static Error* process_sigma_opt(Option_arg arg)
00193 {
00194     if (arg == NULL)
00195     {
00196         return JWSC_EARG("Option 'sigma' requires an argument");
00197     }
00198     if (sscanf(arg, "%f", &sigma) != 1 || sigma <= 0)
00199     {
00200         return JWSC_EARG("Option 'sigma' must be > 0");
00201     }
00202     return NULL;
00203 }
00204 
00206 static Error* process_degree_opt(Option_arg arg)
00207 {
00208     if (arg == NULL)
00209     {
00210         return JWSC_EARG("Option 'degree' requires an argument");
00211     }
00212     if (sscanf(arg, "%u", &degree) != 1)
00213     {
00214         return JWSC_EARG("Option 'degree' requires an argument");
00215     }
00216     return NULL;
00217 }
00218 
00220 static Error* process_ransac_opt(Option_arg arg)
00221 {
00222     if (arg == NULL)
00223     {
00224         return JWSC_EARG("Option 'ransac' requires an argument");
00225     }
00226     if (sscanf(arg, "%u,%u,%f,%u", &(ransac.n), &(ransac.k), &(ransac.t), 
00227                 &(ransac.d)) != 4)
00228     {
00229         return JWSC_EARG("Option 'ransac' has format n,k,t,d");
00230     }
00231     ransac.enabled = 1;
00232     return NULL;
00233 }
00234 
00235 
00236 
00237 
00239 int main(int argc, const char** argv)
00240 {
00241     int      argi;
00242     uint32_t i;
00243     uint32_t row;
00244 
00245     float sse;
00246 
00247     Option_string        l_name;
00248     Option_flag          s_name;
00249     Option_desc          desc;
00250     Option_func_no_arg   fnoarg;
00251     Option_func_with_arg farg;
00252 
00253     Matrix_f* M = NULL;
00254     Matrix_f* x = NULL;
00255     Vector_f* y = NULL;
00256     Vector_f* w = NULL;
00257     Vector_f* r = NULL;
00258     Error*    err;
00259 
00260     i      = 0;
00261     l_name = "help";
00262     s_name = 'h';
00263     desc   = "Prints program usage.";
00264     fnoarg = process_help_opt;
00265     init_option_no_arg(&(opts_no_arg[i++]), l_name, s_name, desc, fnoarg);
00266 
00267     l_name = "version";
00268     s_name = 'v';
00269     desc   = "Prints program version.";
00270     fnoarg = process_version_opt;
00271     init_option_no_arg(&(opts_no_arg[i++]), l_name, s_name, desc, fnoarg);
00272 
00273     i      = 0;
00274     l_name = "seed";
00275     s_name = 0;
00276     desc   = "Random seed.";
00277     farg   = process_seed_opt;
00278     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00279 
00280     l_name = "sigma";
00281     s_name = 's';
00282     desc   = "Gaussian sigma.";
00283     farg   = process_sigma_opt;
00284     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00285 
00286     l_name = "degree";
00287     s_name = 'd';
00288     desc   = "Polynomial degree.";
00289     farg   = process_degree_opt;
00290     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00291 
00292     l_name = "ransac";
00293     s_name = 0;
00294     desc   = "RANSAC robust regression options. Has format n,k,t,d to represent: (n) Number of points to start with, (k) Iterations, (t) Goodness-of-fit threshold for adding a point, and (d) Min number of points needed for a good fit.";
00295     farg   = process_ransac_opt;
00296     init_option_with_arg(&(opts_with_arg[i++]), l_name, s_name, desc, farg);
00297 
00298     if ((err = process_options(argc, argv, &argi, NUM_OPTS_NO_ARG, opts_no_arg, 
00299                     NUM_OPTS_WITH_ARG, opts_with_arg)) != NULL)
00300     {
00301         print_error_msg_exit("polyfit", err->msg);
00302     }
00303 
00304     srand(seed); rand(); rand();
00305 
00306 
00307     if ((err = read_matrix_fp_f(&M, stdin)) != NULL)
00308     {
00309         print_error_msg_exit("polyfit", err->msg);
00310     }
00311 
00312     assert(M->num_cols == 2);
00313 
00314     create_vector_f(&y, M->num_rows);
00315     for (row = 0; row < M->num_rows; row++)
00316     {
00317         y->elts[ row ] = M->elts[ row ][ 1 ];
00318     }
00319 
00320     create_matrix_f(&x, M->num_rows, degree+1);
00321     for (row = 0; row < M->num_rows; row++)
00322     {
00323         for (i = 0; i <= degree; i++)
00324         {
00325             x->elts[ row ][ i ] = pow(M->elts[ row ][ 0 ], i);
00326         }
00327     }
00328 
00329     if (ransac.enabled)
00330     {
00331         if ((err = linear_least_squares_ransac_regress_f(&w, x, y, 
00332                         ransac.n, ransac.k, ransac.t, ransac.d)))
00333         {
00334             print_error_msg_exit("polyfit", err->msg);
00335         }
00336     }
00337     else
00338     {
00339         if ((err = linear_least_squares_regress_f(&w, x, y)))
00340         {
00341             print_error_msg_exit("polyfit", err->msg);
00342         }
00343     }
00344 
00345     //write_formatted_vector_fp_f(w, "%.3e", stdout);
00346     fprintf(stdout, "y%d(x) = %.6e", degree, w->elts[ 0 ]);
00347     for (i = 1; i <= degree; i++)
00348     {
00349         fprintf(stdout, " + %.6e*x**%d", w->elts[ i ], i);
00350     }
00351     fprintf(stdout, "\n");
00352 
00353     // Compute the SSE of the residuals
00354     multiply_matrix_and_vector_f(&r, x, w);
00355     sse = 0;
00356     for (i = 0; i < y->num_elts; i++)
00357     {
00358         sse += (y->elts[ i ] - r->elts[ i ])*(y->elts[ i ] - r->elts[ i ]);
00359     }
00360 
00361     fprintf(stdout, "SSE: %f\n", sse);
00362 
00363 
00364     free_matrix_f(M);
00365     free_matrix_f(x);
00366     free_vector_f(y);
00367     free_vector_f(w);
00368     free_vector_f(r);
00369 
00370     return EXIT_SUCCESS;
00371 }