A Survey of Gaussian Convolution Algorithms
gaussian_bench.c
Go to the documentation of this file.
1 
153 #include <ctype.h>
154 #include <stdio.h>
155 #include <stdlib.h>
156 #include <string.h>
157 #include <math.h>
158 #include "basic.h"
159 #include "strategy_gaussian_conv.h"
160 #include "filter_util.h"
161 
163 #define OUTPUT_FILE "impulse.txt"
164 
165 #ifndef M_SQRT2PI
166 
167 #define M_SQRT2PI 2.50662827463100050241576528481104525
168 #endif
169 
170 
173 {
174  puts("Gaussian benchmark, P. Getreuer 2012-2013");
175 #ifdef NUM_SINGLE
176  puts("Configuration: single-precision computation");
177 #else
178  puts("Configuration: double-precision computation");
179 #endif
180  puts("\nSyntax: gaussian_bench [bench type] [options] [output]\n");
181  puts("Bench type:");
182  puts(" speed measure computation time");
183  puts(" accuracy measure L^infty operator norm error");
184  puts(" impulse impulse response, written to " OUTPUT_FILE "\n");
185  puts("Options:");
186  puts(" -a <algo> algorithm to use, choices are");
187  puts(" fir FIR approximation, tol = kernel accuracy");
188  puts(" dct DCT-based convolution");
189  puts(" box box filtering, K = # passes");
190  puts(" sii stacked integral images, K = # boxes");
191  puts(" am_orig Alvarez-Mazorra original method,");
192  puts(" K = # passes, tol = boundary accuracy");
193  puts(" am Alvarez-Mazorra using regression on q,");
194  puts(" K = # passes, tol = boundary accuracy");
195  puts(" deriche Deriche recursive filtering,");
196  puts(" K = order, tol = boundary accuracy");
197  puts(" vyv Vliet-Young-Verbeek recursive filtering,");
198  puts(" K = order, tol = boundary accuracy");
199  puts(" -s <number> sigma, standard deviation of the Gaussian");
200  puts(" -K <number> specifies number of steps (box, sii, am)");
201  puts(" -t <number> accuracy tolerance (fir, am, deriche, vyv)");
202  puts(" -N <number> signal length\n");
203  puts(" -r <number> (speed bench) number of runs");
204  puts(" -n <number> (impulse bench) position of the impulse\n");
205 }
206 
208 typedef struct
209 {
210  const char *bench_type;
211  long N;
212  long num_runs;
213  long n0;
214  const char *algo;
215  double sigma;
216  int K;
217  double tol;
219 
220 int parse_params(program_params *param, int argc, char **argv);
221 
222 int speed_test(program_params p, num *output, num *input)
223 {
224  gconv *g = NULL;
225  unsigned long time_start, time_stop;
226  long run;
227 
228  if (!(g = gconv_plan(output, input, p.N, 1,
229  p.algo, p.sigma, p.K, p.tol)))
230  return 0;
231 
232  time_start = millisecond_timer();
233 
234  for (run = 0; run < p.num_runs; ++run)
235  gconv_execute(g);
236 
237  time_stop = millisecond_timer();
238  printf("%.5e\n",
239  ((double)(time_stop - time_start)) / p.num_runs);
240  gconv_free(g);
241  return 1;
242 }
243 
244 void make_impulse_signal(num *signal, long N, long n0)
245 {
246  long n;
247 
248  for (n = 0; n < N; ++n)
249  signal[n] = 0;
250 
251  signal[n0] = 1;
252 }
253 
254 int accuracy_test(program_params p, num *output, num *input)
255 {
256  double *error_sums = NULL;
257  num *output0 = NULL;
258  gconv *g0 = NULL, *g = NULL;
259  double linf_norm = 0.0;
260  long m, n;
261  int success = 0;
262 
263  if (!(error_sums = (double *)malloc(sizeof(double) * p.N))
264  || !(output0 = (num *)malloc(sizeof(num) * p.N))
265  || !(g0 = gconv_plan(output0, input, p.N, 1,
266  "fir", p.sigma, p.K, 1e-15))
267  || !(g = gconv_plan(output, input, p.N, 1,
268  p.algo, p.sigma, p.K, p.tol)))
269  goto fail;
270 
271  for (n = 0; n < p.N; ++n)
272  error_sums[n] = 0.0;
273 
274  for (n = 0; n < p.N; ++n)
275  {
276  make_impulse_signal(input, p.N, n);
277  gconv_execute(g0);
278  gconv_execute(g);
279 
280  for (m = 0; m < p.N; ++m)
281  error_sums[m] += fabs((double)output0[m] - (double)output[m]);
282  }
283 
284  for (n = 0; n < p.N; ++n)
285  if (error_sums[n] > linf_norm)
286  linf_norm = error_sums[n];
287 
288  printf("%.8e\n", linf_norm);
289  success = 1;
290 fail:
291  gconv_free(g0);
292  gconv_free(g);
293  if (output0)
294  free(output0);
295  if (error_sums)
296  free(error_sums);
297  return success;
298 }
299 
300 int write_output(const char *filename, num *output, num *exact, long N)
301 {
302  FILE *f;
303  long n;
304 
305  if (!(f = fopen(filename, "wt")))
306  return 0;
307 
308  fprintf(f, "# n\toutput value\texact value\n");
309 
310  for (n = 0; n < N; ++n)
311  fprintf(f, "%ld\t%.16e\t%.16e\n", n, output[n], exact[n]);
312 
313  fclose(f);
314  return 1;
315 }
316 
317 int impulse_test(program_params p, num *output, num *input)
318 {
319  num *exact = NULL;
320  gconv *g = NULL, *g_exact = NULL;
321  int success = 0;
322 
323  if (!(exact = (num *)malloc(sizeof(num) * p.N))
324  || !(g = gconv_plan(output, input, p.N, 1,
325  p.algo, p.sigma, p.K, p.tol))
326  || !(g_exact = gconv_plan(exact, input, p.N, 1,
327  "fir", p.sigma, p.K, 1e-15)))
328  goto fail;
329 
330  make_impulse_signal(input, p.N, p.n0);
331  gconv_execute(g);
332  gconv_execute(g_exact);
333 
334  if (!write_output(OUTPUT_FILE, output, exact, p.N))
335  goto fail;
336 
337  success = 1;
338 fail:
339  gconv_free(g_exact);
340  gconv_free(g);
341  if (exact)
342  free(exact);
343  return success;
344 }
345 
346 int main(int argc, char **argv)
347 {
348  program_params param;
349  num *input = NULL;
350  num *output = NULL;
351  int success = 0;
352 
353  if (!parse_params(&param, argc, argv))
354  return 1;
355 
356  /* Create input signal */
357  if (!(input = (num *)malloc(sizeof(num) * param.N))
358  || !(output = (num *)malloc(sizeof(num) * param.N)))
359  {
360  fprintf(stderr, "Out of memory\n");
361  goto fail;
362  }
363 
364  if (!strcmp(param.bench_type, "speed"))
365  {
366  if (!speed_test(param, output, input))
367  goto fail;
368  }
369  else if (!strcmp(param.bench_type, "accuracy"))
370  {
371  if (!accuracy_test(param, output, input))
372  goto fail;
373  }
374  else if (!strcmp(param.bench_type, "impulse"))
375  {
376  if (!impulse_test(param, output, input))
377  goto fail;
378  }
379  else
380  {
381  fprintf(stderr, "Invalid bench type \"%s\"\n", param.bench_type);
382  goto fail;
383  }
384 
385  success = 1;
386 fail:
387  if (!success)
388  fprintf(stderr, "Bench %s failed\n", param.bench_type);
389 
390  if (output)
391  free(output);
392  if (input)
393  free(input);
394  return !success;
395 }
396 
397 int parse_params(program_params *param, int argc, char **argv)
398 {
399  static const char *default_algo = (const char *)"exact";
400  char *option_string;
401  char option_char;
402  int i;
403 
404  if (argc < 2)
405  {
406  print_usage();
407  return 0;
408  }
409 
410  param->bench_type = argv[1];
411 
412  /* Set parameter defaults. */
413  param->N = 100;
414  param->n0 = -1;
415  param->num_runs = 10;
416  param->sigma = 5;
417  param->algo = default_algo;
418  param->K = 3;
419  param->tol = 1e-2;
420 
421  for (i = 2; i < argc;)
422  {
423  if (argv[i] && argv[i][0] == '-')
424  {
425  if ((option_char = argv[i][1]) == 0)
426  {
427  fprintf(stderr, "Invalid parameter format.\n");
428  return 0;
429  }
430 
431  if (argv[i][2])
432  option_string = &argv[i][2];
433  else if (++i < argc)
434  option_string = argv[i];
435  else
436  {
437  fprintf(stderr, "Invalid parameter format.\n");
438  return 0;
439  }
440 
441  switch (option_char)
442  {
443  case 'a': /* Read algorithm. */
444  param->algo = option_string;
445  break;
446  case 's': /* Read sigma parameter. */
447  param->sigma = atof(option_string);
448 
449  if (param->sigma < 0)
450  {
451  fprintf(stderr, "sigma must be positive.\n");
452  return 0;
453  }
454  break;
455  case 'K': /* Read number of steps. */
456  param->K = atoi(option_string);
457 
458  if (param->K <= 0)
459  {
460  fprintf(stderr, "K must be positive.\n");
461  return 0;
462  }
463  break;
464  case 't': /* Read tolerance. */
465  param->tol = atof(option_string);
466 
467  if (param->tol < 0)
468  {
469  fprintf(stderr, "Tolerance must be positive.\n");
470  return 0;
471  }
472  break;
473  case 'N': /* Input length. */
474  param->N = atoi(option_string);
475 
476  if (param->N < 0)
477  {
478  fprintf(stderr, "Signal length must be positive.\n");
479  return 0;
480  }
481  break;
482  case 'r': /* Read number of runs. */
483  param->num_runs = (long)atof(option_string);
484 
485  if (param->num_runs <= 0)
486  {
487  fprintf(stderr, "Number of runs must be positive.\n");
488  return 0;
489  }
490  break;
491  case 'n': /* Impulse position. */
492  param->n0 = atoi(option_string);
493  break;
494  case '-':
495  print_usage();
496  return 0;
497  default:
498  if (isprint(option_char))
499  fprintf(stderr, "Unknown option \"-%c\".\n", option_char);
500  else
501  fprintf(stderr, "Unknown option.\n");
502 
503  return 0;
504  }
505 
506  i++;
507  }
508  else
509  i++;
510  }
511 
512  if (param->n0 < 0 || param->n0 >= param->N)
513  param->n0 = (param->N + 1) / 2;
514 
515  return 1;
516 }