FORS Pipeline Reference Manual  5.0.9
fors_polynomial.c
1 /* $Id: fors_polynomial.c,v 1.9 2013-02-15 10:55:19 cgarcia Exp $
2  *
3  * This file is part of the FORS Library
4  * Copyright (C) 2002-2010 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * $Author: cgarcia $
23  * $Date: 2013-02-15 10:55:19 $
24  * $Revision: 1.9 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include "fors_polynomial.h"
33 
34 #include "fors_utils.h"
35 
36 #include <cpl.h>
37 #include <math.h>
38 #include <string.h>
39 
40 /*----------------------------------------------------------------------------*/
44 /*----------------------------------------------------------------------------*/
45 
47 /*-----------------------------------------------------------------------------
48  Prototypes
49  -----------------------------------------------------------------------------*/
50 
51 static bool
52 fors_polynomial_is_coeff_set( const cpl_polynomial *p,
53  const cpl_size *powers);
54 
55 static bool
56 fors_polynomial_powers_next( const cpl_polynomial *p,
57  cpl_size *powers);
58 
59 /*-----------------------------------------------------------------------------
60  Private Implementation
61  -----------------------------------------------------------------------------*/
62 
63 /*----------------------------------------------------------------------------*/
64 #undef cleanup
65 #define cleanup
66 
72 /*----------------------------------------------------------------------------*/
73 static bool
74 fors_polynomial_is_coeff_set( const cpl_polynomial *p,
75  const cpl_size *powers)
76 {
77  cassure_automsg( p != NULL,
78  CPL_ERROR_NULL_INPUT,
79  return false);
80  cassure_automsg( powers != NULL,
81  CPL_ERROR_NULL_INPUT,
82  return false);
83 
84  return (fabs(cpl_polynomial_get_coeff(p, powers)) > DBL_EPSILON);
85 }
86 
87 /*----------------------------------------------------------------------------*/
88 #undef cleanup
89 #define cleanup
90 
96 /*----------------------------------------------------------------------------*/
97 static bool
98 fors_polynomial_powers_next(const cpl_polynomial *p,
99  cpl_size *powers)
100 {
101  int dim = 0,
102  ndims,
103  ndegs;
104  bool overflow = false;
105  cpl_errorstate errstat = cpl_errorstate_get();
106 
107  cassure_automsg( p != NULL,
108  CPL_ERROR_NULL_INPUT,
109  return true);
110  cassure_automsg( powers != NULL,
111  CPL_ERROR_NULL_INPUT,
112  return true);
113 
114  ndims = cpl_polynomial_get_dimension(p);
115  ndegs = cpl_polynomial_get_degree(p);
116  passure(cpl_errorstate_is_equal(errstat), return true);
117 
118  powers[dim]++;
119  while(dim < ndims && powers[dim] > ndegs) /* carry over */
120  {
121  powers[dim] = 0;
122  dim++;
123  overflow = (!(dim < ndims));
124  if (!overflow)
125  powers[dim]++;
126  }
127 
128  return overflow;
129 }
130 
131 /*-----------------------------------------------------------------------------
132  Public Implementation
133  -----------------------------------------------------------------------------*/
134 
135 /*----------------------------------------------------------------------------*/
136 #undef cleanup
137 #define cleanup \
138 do { \
139  if (pows != NULL) \
140  cpl_free(pows); \
141  pows = NULL; \
142 } while (0)
143 
148 /*----------------------------------------------------------------------------*/
149 int
150 fors_polynomial_count_coeff( const cpl_polynomial *p)
151 {
152  int ndims,
153  Ncoeff = 0;
154  cpl_size *pows = NULL;
155  bool overflow = false;
156  cpl_errorstate errstat = cpl_errorstate_get();
157 
158  cassure_automsg( p != NULL,
159  CPL_ERROR_NULL_INPUT,
160  return 0);
161 
162  ndims = cpl_polynomial_get_dimension(p);
163  passure(cpl_errorstate_is_equal(errstat), return 0);
164 
165  pows = cpl_calloc(ndims, sizeof(*pows));
166 
167  while (!overflow)
168  {
169  if (fors_polynomial_is_coeff_set(p, pows))
170  Ncoeff++;
171 
172  overflow = fors_polynomial_powers_next(p, pows);
173  }
174 
175  passure(cpl_errorstate_is_equal(errstat), return 0);
176  cleanup;
177 
178  return Ncoeff;
179 }
180 
181 /*----------------------------------------------------------------------------*/
182 #undef cleanup
183 #define cleanup
184 
190 /*----------------------------------------------------------------------------*/
191 int
193  cpl_size *powers)
194 {
195  int ndims,
196  dim;
197  bool overflow;
198  cpl_errorstate errstat = cpl_errorstate_get();
199 
200  cassure_automsg( p != NULL,
201  CPL_ERROR_NULL_INPUT,
202  return true);
203  cassure_automsg( powers != NULL,
204  CPL_ERROR_NULL_INPUT,
205  return true);
206 
207  ndims = cpl_polynomial_get_dimension(p);
208  for (dim = 0; dim < ndims; dim++)
209  powers[dim] = 0;
210 
211  if (fors_polynomial_is_coeff_set(p, powers))
212  return false;
213 
214  overflow = fors_polynomial_powers_find_next_coeff(p, powers);
215  passure(cpl_errorstate_is_equal(errstat), return true);
216  cleanup;
217 
218  return overflow;
219 }
220 
221 /*----------------------------------------------------------------------------*/
222 #undef cleanup
223 #define cleanup
224 
230 /*----------------------------------------------------------------------------*/
231 int
233  cpl_size *powers)
234 {
235  bool overflow;
236  cpl_errorstate errstat = cpl_errorstate_get();
237 
238  cassure_automsg( p != NULL,
239  CPL_ERROR_NULL_INPUT,
240  return true);
241  cassure_automsg( powers != NULL,
242  CPL_ERROR_NULL_INPUT,
243  return true);
244 
245  overflow = fors_polynomial_powers_next(p, powers);
246  while (!overflow)
247  {
248  if (fors_polynomial_is_coeff_set(p, powers))
249  break;
250 
251  overflow = fors_polynomial_powers_next(p, powers);
252  }
253 
254  passure(cpl_errorstate_is_equal(errstat), return true);
255  cleanup;
256 
257  return overflow;
258 }
259 
260 /*----------------------------------------------------------------------------*/
261 #undef cleanup
262 #define cleanup \
263 do { \
264  if (pows != NULL) \
265  cpl_free(pows); \
266  pows = NULL; \
267 } while (0)
268 
275 /*----------------------------------------------------------------------------*/
276 cpl_error_code
278  const double *coeffs,
279  int n_coeffs)
280 {
281  int n,
282  ndims;
283  cpl_size *pows = NULL;
284  bool overflow = false;
285  cpl_errorstate errstat = cpl_errorstate_get();
286 
287  if (p == NULL)
288  return 0;
289 
290  /* check input */
291  cassure_automsg( p != NULL,
292  CPL_ERROR_NULL_INPUT,
293  return cpl_error_get_code());
294  cassure_automsg( coeffs != NULL,
295  CPL_ERROR_NULL_INPUT,
296  return cpl_error_get_code());
297  cassure_automsg( n_coeffs > 0,
298  CPL_ERROR_ILLEGAL_INPUT,
299  return cpl_error_get_code());
300 
301  /* start */
302  ndims = cpl_polynomial_get_dimension(p);
303  pows = cpl_calloc(ndims, sizeof(*pows));
304 
305  overflow = fors_polynomial_powers_find_first_coeff(p, pows);
306  n = 0;
307  while (!overflow)
308  {
309  cassure( n < n_coeffs,
310  CPL_ERROR_ACCESS_OUT_OF_RANGE,
311  return cpl_error_get_code(),
312  "p contains more coefficients "
313  "than coeffs");
314  cpl_polynomial_set_coeff(p, pows, coeffs[n]);
315  n++;
316 
317  overflow = fors_polynomial_powers_find_next_coeff(p, pows);
318  }
319 
320  cleanup;
321 
322  return cpl_errorstate_is_equal(errstat) ?
323  CPL_ERROR_NONE :
324  cpl_error_get_code();
325 }
326 
327 /*----------------------------------------------------------------------------*/
328 #undef cleanup
329 #define cleanup \
330 do { \
331  if (powersA != NULL) { cpl_free(powersA); powersA = NULL;} \
332  if (powersB != NULL) { cpl_free(powersB); powersB = NULL;} \
333  if (powersE != NULL) { cpl_free(powersE); powersE = NULL;} \
334  cpl_polynomial_delete(ep); ep = NULL; \
335 } while (0)
336 
354 /*----------------------------------------------------------------------------*/
355 cpl_polynomial*
356 fors_polynomial_create_variance_polynomial( const cpl_polynomial *p_def,
357  const cpl_matrix *cov_coeff)
358 {
359  int n_dims,
360  n_coeffs,
361  n_col,
362  ia = 0;
363  cpl_size *powersA = NULL,
364  *powersB = NULL,
365  *powersE = NULL;
366  cpl_polynomial *ep = NULL;
367  bool overflowa = false;
368  cpl_errorstate errstat = cpl_errorstate_get();
369 
370  /* check input */
371  cassure_automsg( p_def != NULL,
372  CPL_ERROR_NULL_INPUT,
373  return ep);
374  cassure_automsg( cov_coeff != NULL,
375  CPL_ERROR_NULL_INPUT,
376  return ep);
377 
378  n_coeffs = fors_polynomial_count_coeff(p_def);
379  n_dims = cpl_polynomial_get_dimension(p_def);
380  n_col = cpl_matrix_get_ncol(cov_coeff);
381  passure(cpl_errorstate_is_equal(errstat), return ep);
382 
383  cassure( n_coeffs == n_col,
384  CPL_ERROR_INCOMPATIBLE_INPUT,
385  return ep,
386  "number of p_def coefficients "
387  "!= nr of columns");
388  cassure( n_col == cpl_matrix_get_nrow(
389  cov_coeff),
390  CPL_ERROR_ILLEGAL_INPUT,
391  return ep,
392  "cov_coeff is not square");
393 
394  ep = cpl_polynomial_new(n_dims);
395  powersA = cpl_calloc(n_dims, sizeof(*powersA));
396  powersB = cpl_calloc(n_dims, sizeof(*powersB));
397  powersE = cpl_calloc(n_dims, sizeof(*powersE));
398  passure(cpl_errorstate_is_equal(errstat), return ep);
399 
400  overflowa = fors_polynomial_powers_find_first_coeff(p_def, powersA);
401  while (!overflowa)
402  {
403  bool overflowb = false;
404  int ib = 0;
405 
406  overflowb = fors_polynomial_powers_find_first_coeff(p_def, powersB);
407  while (!overflowb)
408  {
409  double coeff;
410  int d;
411  passure(cpl_errorstate_is_equal(errstat), return ep);
412  /* Add cov_ij to the proper coeff:
413  * cov_ij * dp/d(ai) * dp/d(aj) =
414  * cov_ij * (x^degx[i] * y^degy[i]) * (x^degx[i] * y^degy[i]) =
415  * cov_ij * x^(degx[i]+degx[j]) * y^(degy[i] + degy[j]),
416  *
417  * i.e. add cov_ij to
418  * coeff (degx[i]+degx[j], degy[i]+degy[j])
419  */
420  for (d = 0; d < n_dims; d++)
421  powersE[d] = powersA[d] + powersB[d];
422 
423  coeff = cpl_polynomial_get_coeff(ep, powersE);
424  cpl_polynomial_set_coeff(ep, powersE,
425  coeff
426  + cpl_matrix_get(
427  cov_coeff, ia, ib));
428 
429  ib++;
430  overflowb = fors_polynomial_powers_find_next_coeff(p_def, powersB);
431  }
432  ia++;
433  overflowa = fors_polynomial_powers_find_next_coeff(p_def, powersA);
434  }
435  passure(cpl_errorstate_is_equal(errstat), return ep);
436 
437  cpl_polynomial *ret_ep = ep; ep = NULL;
438  cleanup;
439 
440  return ret_ep;
441 }
442 
443 /*----------------------------------------------------------------------------*/
444 #undef cleanup
445 #define cleanup \
446 do { \
447  if (pows != NULL) \
448  cpl_free(pows); \
449  pows = NULL; \
450  if (ndxstr != NULL) \
451  cpl_free(ndxstr); \
452  ndxstr = NULL; \
453 } while (0)
454 
463 /*----------------------------------------------------------------------------*/
464 cpl_error_code
465 fors_polynomial_dump( const cpl_polynomial *p,
466  const char *name,
467  cpl_msg_severity level,
468  const cpl_polynomial *p_def)
469 {
470  int ndims,
471  ndegs,
472  dim;
473  cpl_size *pows = NULL;
474  char *ndxstr = NULL;
475  char max_ndx_str[15];
476  cpl_errorstate errstat = cpl_errorstate_get();
477 
478  /* check input */
479  cassure_automsg( p != NULL,
480  CPL_ERROR_NULL_INPUT,
481  return cpl_error_get_code());
482 
483  if (p_def != NULL)
484  {
485  ndims = cpl_polynomial_get_dimension(p_def);
486  cassure_automsg( ndims
487  = cpl_polynomial_get_dimension(p),
488  CPL_ERROR_INCOMPATIBLE_INPUT,
489  return cpl_error_get_code());
490  }
491  else
492  {
493  ndims = cpl_polynomial_get_dimension(p);
494  p_def = p;
495  }
496 
497  ndegs = cpl_polynomial_get_degree(p_def);
498 
499  pows = cpl_calloc(ndims, sizeof(*pows));
500  /* allocate a string that can contain "%d,%d,...,%d" */
501  sprintf(max_ndx_str, "%d", ndegs);
502  ndxstr = cpl_calloc(ndims*(strlen(max_ndx_str)+1), sizeof(*ndxstr));
503 
504  /* ATTENTION: below, the last dimension is the fastest index (for nicer
505  * printing). This differs from the strategy in all other polynomial
506  * handling functions above, so be careful when doing copy & paste!
507  */
508  while (pows[0] <= ndegs)
509  {
510  if (fors_polynomial_is_coeff_set(p_def, pows))
511  {
512  double coeff;
513  coeff = cpl_polynomial_get_coeff(p, pows);
514  /* create the index string */
515  sprintf(ndxstr, "%"CPL_SIZE_FORMAT, pows[0]);
516  for (dim = 1; dim < ndims; dim++)
517  sprintf(ndxstr+strlen(ndxstr), ",%"CPL_SIZE_FORMAT, pows[dim]);
518  fors_msg( level,
519  "%s_%s = %e",
520  (name != NULL) ? name : "p",
521  ndxstr,
522  coeff);
523  }
524 
525  dim = ndims-1;
526  pows[dim]++;
527  while(dim > 0 && pows[dim] > ndegs) /* carry over */
528  {
529  pows[dim] = 0;
530  dim--;
531  pows[dim]++;
532  }
533  }
534 
535  cleanup;
536 
537  return cpl_errorstate_is_equal(errstat) ?
538  CPL_ERROR_NONE :
539  cpl_error_get_code();
540 }
541 
542 /*----------------------------------------------------------------------------*/
543 #undef cleanup
544 #define cleanup \
545 do { \
546  if (ndxstr != NULL) \
547  cpl_free(ndxstr); \
548  ndxstr = NULL; \
549 } while (0)
550 
561 /*----------------------------------------------------------------------------*/
562 char*
563 fors_polynomial_sprint_coeff( const cpl_polynomial *p,
564  cpl_size *powers,
565  const char *prefix)
566 {
567  int ndims,
568  ndegs,
569  dim,
570  max_nr,
571  max_nr_strlen;
572  char *ndxstr = NULL;
573  char max_ndx_str[15];
574 
575  /* check input */
576  cassure_automsg( p != NULL,
577  CPL_ERROR_NULL_INPUT,
578  return ndxstr);
579  cassure_automsg( powers != NULL,
580  CPL_ERROR_NULL_INPUT,
581  return ndxstr);
582 
583  ndims = cpl_polynomial_get_dimension(p);
584  ndegs = cpl_polynomial_get_degree(p);
585 
586  /* be safe to cover maximum required str length */
587  /* FIXME: catch negative numbers */
588  max_nr = ndegs;
589  for (dim = 0; dim < ndims; dim++)
590  if (powers[dim] > max_nr)
591  max_nr = powers[dim];
592 
593  sprintf(max_ndx_str, "%d", max_nr);
594  max_nr_strlen = strlen(max_ndx_str);
595  if (prefix != NULL && prefix[0] != '\0')
596  {
597  int len = strlen(prefix) + 1 + ndims*(max_nr_strlen+1);
598  ndxstr = cpl_calloc(len, sizeof(*ndxstr));
599  sprintf(ndxstr, "%s_", prefix);
600  }
601  else
602  {
603  ndxstr = cpl_calloc(ndims*(max_nr_strlen+1), sizeof(*ndxstr));
604  }
605  /* specify max length for snprintf including nul char */
606  snprintf(ndxstr+strlen(ndxstr), max_nr_strlen+1,
607  (powers[0] >= 0) ? "%"CPL_SIZE_FORMAT : "?",
608  powers[0]);
609  for (dim = 1; dim < ndims; dim++)
610  snprintf(ndxstr+strlen(ndxstr), max_nr_strlen+2,
611  (powers[dim] >= 0) ? ",%"CPL_SIZE_FORMAT : "?",
612  powers[dim]);
613 
614  return ndxstr;
615 }
616 
static bool fors_polynomial_is_coeff_set(const cpl_polynomial *p, const cpl_size *powers)
Implementation of the check whether a coefficient exists.
cpl_error_code fors_polynomial_dump(const cpl_polynomial *p, const char *name, cpl_msg_severity level, const cpl_polynomial *p_def)
Count the total number of non-zero coefficients.
int fors_polynomial_count_coeff(const cpl_polynomial *p)
Count the total number of non-zero coefficients.
char * fors_polynomial_sprint_coeff(const cpl_polynomial *p, cpl_size *powers, const char *prefix)
Print a coefficient's name into a newly allocated string.
int fors_polynomial_powers_find_next_coeff(const cpl_polynomial *p, cpl_size *powers)
Find the next non-zero coefficient.
static bool fors_polynomial_powers_next(const cpl_polynomial *p, cpl_size *powers)
Step the powers of a polynomials coefficient to the next.
int fors_polynomial_powers_find_first_coeff(const cpl_polynomial *p, cpl_size *powers)
Find the first non-zero coefficient.
cpl_error_code fors_polynomial_set_existing_coeff(cpl_polynomial *p, const double *coeffs, int n_coeffs)
Set the already existing coefficients in a polynomial to values taken from an array.
cpl_polynomial * fors_polynomial_create_variance_polynomial(const cpl_polynomial *p_def, const cpl_matrix *cov_coeff)
Create a polynomial modelling the squared influence of the error of the coefficients of another polyn...