uves_utils_polynomial.c

00001 /*                                                                              *
00002  *   This file is part of the ESO UVES Pipeline                                 *
00003  *   Copyright (C) 2004,2005 European Southern Observatory                      *
00004  *                                                                              *
00005  *   This library is free software; you can redistribute it and/or modify       *
00006  *   it under the terms of the GNU General Public License as published by       *
00007  *   the Free Software Foundation; either version 2 of the License, or          *
00008  *   (at your option) any later version.                                        *
00009  *                                                                              *
00010  *   This program is distributed in the hope that it will be useful,            *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of             *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
00013  *   GNU General Public License for more details.                               *
00014  *                                                                              *
00015  *   You should have received a copy of the GNU General Public License          *
00016  *   along with this program; if not, write to the Free Software                *
00017  *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA       *
00018  *                                                                              */
00019 
00020 /*
00021  * $Author: amodigli $
00022  * $Date: 2007/06/06 08:17:33 $
00023  * $Revision: 1.60 $
00024  * $Name: uves-3_3_1 $
00025  * $Log: uves_utils_polynomial.c,v $
00026  * Revision 1.60  2007/06/06 08:17:33  amodigli
00027  * replace tab with 4 spaces
00028  *
00029  * Revision 1.59  2007/05/03 15:23:08  jmlarsen
00030  * Removed dead code
00031  *
00032  * Revision 1.58  2007/05/03 15:18:29  jmlarsen
00033  * Added function to add polynomials
00034  *
00035  * Revision 1.57  2007/04/27 07:21:51  jmlarsen
00036  * Polyfit: Changed error code from ILLEGAL_INPUT to SINGULAR_MATRIX
00037  *
00038  * Revision 1.56  2007/04/24 12:50:29  jmlarsen
00039  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00040  *
00041  * Revision 1.55  2007/03/23 08:01:55  jmlarsen
00042  * Fixed mixed code and declarations
00043  *
00044  * Revision 1.54  2007/03/19 15:10:03  jmlarsen
00045  * Optimization in 2d fitting: do not call pow too often
00046  *
00047  * Revision 1.53  2007/03/13 15:35:11  jmlarsen
00048  * Made a few time optimizations
00049  *
00050  * Revision 1.52  2007/03/05 10:20:49  jmlarsen
00051  * Added uves_polynomial_delete_const()
00052  *
00053  * Revision 1.51  2007/01/15 08:48:51  jmlarsen
00054  * Shortened lines
00055  *
00056  * Revision 1.50  2006/11/24 09:36:49  jmlarsen
00057  * Workaround for slow uves_propertylist_get_size
00058  *
00059  * Revision 1.49  2006/11/15 15:02:15  jmlarsen
00060  * Implemented const safe workarounds for CPL functions
00061  *
00062  * Revision 1.47  2006/11/15 14:04:08  jmlarsen
00063  * Removed non-const version of parameterlist_get_first/last/next which is
00064  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00065  *
00066  * Revision 1.46  2006/11/13 14:23:55  jmlarsen
00067  * Removed workarounds for CPL const bugs
00068  *
00069  * Revision 1.45  2006/11/06 15:19:42  jmlarsen
00070  * Removed unused include directives
00071  *
00072  * Revision 1.44  2006/09/08 14:06:29  jmlarsen
00073  * Removed profiling code
00074  *
00075  * Revision 1.43  2006/09/06 14:46:21  jmlarsen
00076  * Added missing newline in uves_polynomial_dump()
00077  *
00078  * Revision 1.42  2006/08/17 14:11:25  jmlarsen
00079  * Use assure_mem macro to check for memory allocation failure
00080  *
00081  * Revision 1.41  2006/08/17 13:56:53  jmlarsen
00082  * Reduced max line length
00083  *
00084  * Revision 1.40  2006/07/03 13:27:52  jmlarsen
00085  * Moved failing assertion to where it should be
00086  *
00087  * Revision 1.39  2006/06/01 14:43:17  jmlarsen
00088  * Added missing documentation
00089  *
00090  * Revision 1.38  2006/05/05 13:59:03  jmlarsen
00091  * Support fitting zero-degree polynomial
00092  *
00093  * Revision 1.37  2006/04/24 09:28:29  jmlarsen
00094  * Added function to create zero-polynomial
00095  *
00096  * Revision 1.36  2006/03/27 09:41:37  jmlarsen
00097  * Added timing markers
00098  *
00099  * Revision 1.35  2006/03/09 10:52:25  jmlarsen
00100  * Renamed pow->power
00101  *
00102  * Revision 1.34  2006/03/03 13:54:11  jmlarsen
00103  * Changed syntax of check macro
00104  *
00105  * Revision 1.33  2005/12/19 16:17:56  jmlarsen
00106  * Replaced bool -> int
00107  *
00108  */
00109 
00110 #ifdef HAVE_CONFIG_H
00111 #  include <config.h>
00112 #endif
00113 
00114 /*----------------------------------------------------------------------------*/
00134 /*----------------------------------------------------------------------------*/
00135 
00136 /*-----------------------------------------------------------------------------
00137                                 Defines
00138  -----------------------------------------------------------------------------*/
00139 
00140 /*
00141  *  When storing a 2d polynomial in a table,
00142  *  these column names are used
00143  */
00144 #define COLUMN_ORDER1 "Order1"
00145 #define COLUMN_ORDER2 "Order2"
00146 #define COLUMN_COEFF  "Coeff"
00147 
00150 /*-----------------------------------------------------------------------------
00151                                 Includes
00152  -----------------------------------------------------------------------------*/
00153 #include <uves_utils_polynomial.h>
00154 
00155 #include <uves_utils.h>
00156 #include <uves_utils_wrappers.h>
00157 #include <uves_dump.h>
00158 #include <uves_msg.h>
00159 #include <uves_error.h>
00160 
00161 #include <irplib_access.h>
00162 
00163 #include <cpl.h>
00164 
00165 /*-----------------------------------------------------------------------------
00166                             Typedefs
00167  -----------------------------------------------------------------------------*/
00170 struct _polynomial 
00171 {
00173     cpl_polynomial *pol; 
00174 
00176     cpl_vector *vec;
00177     double *vec_data;
00178 
00179     int dimension;  /* for efficiency */
00180 
00182     double *shift;
00183 
00185     double *scale;
00186 };
00187 
00188 /*-----------------------------------------------------------------------------
00189                             Implementation
00190  -----------------------------------------------------------------------------*/
00191 /*----------------------------------------------------------------------------*/
00202 /*----------------------------------------------------------------------------*/
00203 polynomial *
00204 uves_polynomial_new(const cpl_polynomial *pol)
00205 {
00206     polynomial *p = NULL;
00207     int i;
00208     
00209     /* Test input */
00210     assure(pol != NULL, CPL_ERROR_ILLEGAL_INPUT, "Null polynomial");
00211 
00212     /* Allocate and initialize struct */
00213     p = cpl_calloc(1, sizeof(polynomial)) ;
00214     assure_mem( p );
00215 
00216     check( p->dimension = cpl_polynomial_get_dimension(pol), "Error reading dimension");
00217 
00218     /* Allocate vector */
00219     p->vec = cpl_vector_new(p->dimension);
00220     assure_mem( p->vec );
00221     p->vec_data = cpl_vector_get_data(p->vec);
00222 
00223     /* Shifts are initialized to zero, scales to 1 */
00224     p->shift = cpl_calloc(p->dimension + 1, sizeof(double));
00225     assure_mem( p->shift );
00226 
00227     p->scale = cpl_malloc((p->dimension + 1) * sizeof(double));
00228     assure_mem( p->scale );
00229     for (i = 0; i <= p->dimension; i++)
00230     p->scale[i] = 1.0;
00231 
00232     check( p->pol = cpl_polynomial_duplicate(pol), "Error copying polynomial");
00233     
00234   cleanup:
00235     if (cpl_error_get_code() != CPL_ERROR_NONE)
00236     uves_polynomial_delete(&p);
00237     
00238     return p;
00239 }
00240 
00241 /*----------------------------------------------------------------------------*/
00249 /*----------------------------------------------------------------------------*/
00250 polynomial *
00251 uves_polynomial_new_zero(int dim)
00252 {
00253     polynomial *result = NULL;
00254     cpl_polynomial *p = NULL;
00255 
00256     assure( dim >= 1, CPL_ERROR_ILLEGAL_INPUT, "Illegal dimension: %d", dim);
00257 
00258     p = cpl_polynomial_new(dim);
00259     assure_mem( p );
00260 
00261     result = uves_polynomial_new(p);
00262     assure_mem( result );
00263 
00264   cleanup:
00265     uves_free_polynomial(&p);
00266 
00267     return result;
00268 }
00269 
00270 /*----------------------------------------------------------------------------*/
00277 /*----------------------------------------------------------------------------*/
00278 void 
00279 uves_polynomial_delete(polynomial **p)
00280 {
00281     uves_polynomial_delete_const((const polynomial **)p);
00282 }
00283 
00284 /*----------------------------------------------------------------------------*/
00291 /*----------------------------------------------------------------------------*/
00292 void 
00293 uves_polynomial_delete_const(const polynomial **p)
00294 {
00295     if (*p == NULL) return;
00296     irplib_polynomial_delete((*p)->pol);
00297     irplib_vector_delete((*p)->vec);
00298     cpl_free((*p)->shift);
00299     cpl_free((*p)->scale);
00300     irplib_free(*p);
00301     *p = NULL;
00302     return;
00303 }
00304 /*----------------------------------------------------------------------------*/
00310 /*----------------------------------------------------------------------------*/
00311 int
00312 uves_polynomial_get_degree(const polynomial *p)
00313 {
00314     int result = -1;
00315     assure( p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
00316     
00317     result = cpl_polynomial_get_degree(p->pol);
00318 
00319   cleanup:
00320     return result;
00321 }
00322 
00323 /*----------------------------------------------------------------------------*/
00329 /*----------------------------------------------------------------------------*/
00330 polynomial *
00331 uves_polynomial_duplicate(const polynomial *p)
00332 {
00333     polynomial *result = NULL;
00334     int dimension;
00335     int i;
00336 
00337     assure( p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
00338     dimension = uves_polynomial_get_dimension(p);
00339 
00340     check( result = uves_polynomial_new(p->pol),
00341        "Error allocating polynomial");
00342     
00343     for (i = 0; i <= dimension; i++)
00344     {
00345         result->shift[i] = p->shift[i];
00346         result->scale[i] = p->scale[i];
00347     }
00348 
00349   cleanup:
00350     if (cpl_error_get_code() != CPL_ERROR_NONE)
00351     {
00352         uves_polynomial_delete(&result);
00353         return NULL;
00354     }
00355     
00356     return result;
00357 }
00358 
00359 
00360 /*----------------------------------------------------------------------------*/
00371 /*----------------------------------------------------------------------------*/
00372 cpl_table *
00373 uves_polynomial_convert_to_table(const polynomial *p)
00374 {
00375     cpl_table *t = NULL; /* Result */
00376     int degree;
00377     int i, j, row;
00378 
00379     /* Check input */
00380     assure( p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
00381     assure( uves_polynomial_get_dimension(p) == 2, 
00382         CPL_ERROR_ILLEGAL_INPUT, "Polynomial must be 2D");
00383     
00384     degree = cpl_polynomial_get_degree(p->pol);
00385 
00386     /* Allocate space for 3 shifts, 3 scale factors and all
00387        coefficients */
00388     t = cpl_table_new(3 + 3 + (degree + 1)*(degree + 2)/2);
00389     cpl_table_new_column(t, COLUMN_ORDER1, CPL_TYPE_INT);
00390     cpl_table_new_column(t, COLUMN_ORDER2, CPL_TYPE_INT);
00391     cpl_table_new_column(t, COLUMN_COEFF , CPL_TYPE_DOUBLE);
00392 
00393     row = 0;
00394 
00395     /* First write the shifts, write non-garbage to coeff columns (which are not used) */
00396     cpl_table_set_int   (t, COLUMN_ORDER1, row, -1);
00397     cpl_table_set_int   (t, COLUMN_ORDER2, row, -1);
00398     cpl_table_set_double(t, COLUMN_COEFF , row, p->shift[0]); row++;
00399 
00400     cpl_table_set_int   (t, COLUMN_ORDER1, row, -1);
00401     cpl_table_set_int   (t, COLUMN_ORDER2, row, -1);
00402     cpl_table_set_double(t, COLUMN_COEFF , row, p->shift[1]); row++;
00403 
00404     cpl_table_set_int   (t, COLUMN_ORDER1, row, -1);
00405     cpl_table_set_int   (t, COLUMN_ORDER2, row, -1);
00406     cpl_table_set_double(t, COLUMN_COEFF , row, p->shift[2]); row++;
00407 
00408     /* Then the scale factors */
00409     cpl_table_set_int   (t, COLUMN_ORDER1, row, -1);
00410     cpl_table_set_int   (t, COLUMN_ORDER2, row, -1);
00411     cpl_table_set_double(t, COLUMN_COEFF, row, p->scale[0]); row++;
00412 
00413     cpl_table_set_int   (t, COLUMN_ORDER1, row, -1);
00414     cpl_table_set_int   (t, COLUMN_ORDER2, row, -1);
00415     cpl_table_set_double(t, COLUMN_COEFF, row, p->scale[1]); row++;
00416 
00417     cpl_table_set_int   (t, COLUMN_ORDER1, row, -1);
00418     cpl_table_set_int   (t, COLUMN_ORDER2, row, -1);
00419     cpl_table_set_double(t, COLUMN_COEFF, row, p->scale[2]); row++;
00420 
00421     /* And then write the coefficients */
00422     for (i = 0; i <= degree; i++){
00423     for (j = 0; j+i <= degree; j++){
00424         double coeff;
00425         int power[2];
00426         power[0] = i;
00427         power[1] = j;
00428         
00429         coeff = cpl_polynomial_get_coeff(p->pol, power);
00430         cpl_table_set_int   (t, COLUMN_ORDER1, row, power[0]);
00431         cpl_table_set_int   (t, COLUMN_ORDER2, row, power[1]);
00432         cpl_table_set_double(t, COLUMN_COEFF , row, coeff);
00433         
00434         row++;
00435     }
00436     }
00437 
00438   cleanup:
00439     return t;
00440 }
00441 
00442 /*----------------------------------------------------------------------------*/
00451 /*----------------------------------------------------------------------------*/
00452 polynomial *
00453 uves_polynomial_convert_from_table(cpl_table *t)
00454 {
00455     polynomial *p = NULL;  /* Result */
00456     cpl_polynomial *pol = NULL;
00457     cpl_type type;
00458     int i;
00459     
00460     /* Only 2d supported */
00461     check( pol = cpl_polynomial_new(2), "Error initializing polynomial");
00462 
00463     /* Check table format */
00464     assure(t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
00465     assure(cpl_table_has_column(t, COLUMN_ORDER1), CPL_ERROR_ILLEGAL_INPUT, 
00466        "No '%s' column found in table", COLUMN_ORDER1);
00467     assure(cpl_table_has_column(t, COLUMN_ORDER2), CPL_ERROR_ILLEGAL_INPUT,
00468        "No '%s' column found in table", COLUMN_ORDER2);
00469     assure(cpl_table_has_column(t, COLUMN_COEFF ), CPL_ERROR_ILLEGAL_INPUT,
00470        "No '%s' column found in table", COLUMN_COEFF );
00471     
00472     type = cpl_table_get_column_type(t, COLUMN_ORDER1);
00473     assure(type == CPL_TYPE_INT   , CPL_ERROR_INVALID_TYPE,
00474        "Column '%s' has type %s. Integer expected", COLUMN_ORDER1,
00475        uves_tostring_cpl_type(type));
00476     
00477     type = cpl_table_get_column_type(t, COLUMN_ORDER2);
00478     assure(type == CPL_TYPE_INT   , CPL_ERROR_INVALID_TYPE,
00479        "Column '%s' has type %s. Integer expected", COLUMN_ORDER2,
00480        uves_tostring_cpl_type(type));
00481     
00482     type = cpl_table_get_column_type(t, COLUMN_COEFF);
00483     assure(type == CPL_TYPE_DOUBLE, CPL_ERROR_INVALID_TYPE,
00484        "Column '%s' has type %s. Double expected", COLUMN_COEFF ,
00485        uves_tostring_cpl_type(type));
00486 
00487     assure(cpl_table_get_nrow(t) > 1 + 2 + 1 + 2, CPL_ERROR_ILLEGAL_INPUT,
00488        "Table must contain at least one coefficient");
00489     
00490     /* Read the coefficients */
00491     for(i = 3 + 3; i < cpl_table_get_nrow(t); i++) {
00492     double coeff;
00493     int power[2];
00494     
00495     check(( power[0] = cpl_table_get_int(t, COLUMN_ORDER1, i, NULL),
00496         power[1] = cpl_table_get_int(t, COLUMN_ORDER2, i, NULL),
00497         coeff  = cpl_table_get_double(t, COLUMN_COEFF , i, NULL)),
00498            "Error reading table row %d", i);
00499     
00500     uves_msg_debug("Pol.coeff.(%d, %d) = %e", power[0], power[1], coeff);
00501 
00502     check( cpl_polynomial_set_coeff(pol, power, coeff), "Error creating polynomial");
00503     }
00504     p = uves_polynomial_new(pol);
00505 
00506     /* Read shifts and rescaling */
00507     uves_polynomial_rescale(p, 0, cpl_table_get_double( t, COLUMN_COEFF, 3, NULL));
00508     uves_polynomial_rescale(p, 1, cpl_table_get_double( t, COLUMN_COEFF, 4, NULL));
00509     uves_polynomial_rescale(p, 2, cpl_table_get_double( t, COLUMN_COEFF, 5, NULL));
00510     uves_polynomial_shift  (p, 0, cpl_table_get_double( t, COLUMN_COEFF, 0, NULL));
00511     uves_polynomial_shift  (p, 1, cpl_table_get_double( t, COLUMN_COEFF, 1, NULL));
00512     uves_polynomial_shift  (p, 2, cpl_table_get_double( t, COLUMN_COEFF, 2, NULL));
00513 
00514   cleanup:
00515     uves_free_polynomial(&pol);
00516     if (cpl_error_get_code() != CPL_ERROR_NONE)
00517     uves_polynomial_delete(&p);
00518 
00519     return p;
00520 }
00521 
00522 /*----------------------------------------------------------------------------*/
00538 /*----------------------------------------------------------------------------*/
00539 polynomial *
00540 uves_polynomial_convert_from_plist_midas(const uves_propertylist *plist, 
00541                      const char *regression_name)
00542 {
00543     polynomial *result = NULL;
00544     cpl_polynomial *pol = NULL;
00545     int N = strlen(regression_name);
00546     int degree1 = -1;
00547     int degree2 = -1; 
00548     bool found = false;
00549     const long int plist_size = uves_propertylist_get_size(plist);
00550     int i;
00551        
00552     for (i = 0; !found && i < plist_size; i++){
00553     const cpl_property *p = uves_propertylist_get_const(plist, i);
00554     const char *name = cpl_property_get_name(p);
00555 
00556     if (strcmp(name, "HISTORY") == 0) {
00557         const char *value;
00558         check( value = cpl_property_get_string(p),
00559            "Error reading property value");
00560         
00561         /* match the string  "'<regression_name>I'"  */
00562         if ((int)strlen(value) >= 1+N+2 &&
00563         value[0]     == '\'' &&
00564         value[1+N]   == 'I' && 
00565         value[1+N+1] == '\'' && 
00566         strncmp(value+1, regression_name, N) == 0
00567         ) {
00568         long number;
00569         char *next;
00570         
00571         assure(i+1 < plist_size, CPL_ERROR_ILLEGAL_INPUT, 
00572                "Missing header data");
00573         p = uves_propertylist_get_const(plist, i+1);
00574         assure(       cpl_property_get_type(p)             == CPL_TYPE_STRING &&
00575             strcmp(cpl_property_get_name(p), "HISTORY") == 0, 
00576                   CPL_ERROR_ILLEGAL_INPUT,
00577                   "Error parsing polynomial");
00578         value = cpl_property_get_string(
00579             uves_propertylist_get_const(plist, i+1));
00580 
00581         /* ignore OUTPUTI(1)- N,no.of data, */
00582         number = strtol(value, &next, 10);
00583 
00584         /* OUTPUTI(2)- M,no.of ind.var. */
00585         value = next;
00586         assure( strtol(value, &next, 10) == 2, CPL_ERROR_UNSUPPORTED_MODE,
00587             "Regressions is %ld-dimensional (2D expected)", 
00588             strtol(value, &next, 10));
00589 
00590         /* ignore OUTPUTI(3-5) (column number of variables)
00591                    (3)- col.no. of dep.var.
00592                    (4)- col.no. of indep.var.
00593                    (5)-
00594         */
00595         value = next; number = strtol(value, &next, 10);
00596         value = next; number = strtol(value, &next, 10);
00597         value = next; number = strtol(value, &next, 10);
00598 
00599         /* Read degree of first and second variable 
00600            (6)- degree (ND) */
00601         value = next; degree1 = strtol(value, &next, 10);
00602         value = next; degree2 = strtol(value, &next, 10);
00603 
00604         uves_msg_debug("Degree of 2D regression %s is (%d, %d)",
00605                    regression_name, degree1, degree2);
00606         
00607         /* Stop search */
00608         found = true;
00609         } /* string was "'...I'" */
00610     } /* Keyword was HISTORY */
00611     }/* for i... */
00612     
00613     assure( found, CPL_ERROR_ILLEGAL_INPUT, "No MIDAS-regression named %s found in propertylist",
00614         regression_name);
00615 
00616     /* The degree of the regression is now known. Next, read the coefficients */
00617 
00618     pol = cpl_polynomial_new(2);
00619 
00620     /* Search for <regression_name>D */
00621     found = false;
00622     for (i = 0; !found && i < plist_size; i++){
00623     const cpl_property *p = uves_propertylist_get_const(plist, i);
00624     const char *name = cpl_property_get_name(p);
00625     
00626     if (strcmp(name, "HISTORY") == 0) {
00627         const char *value;
00628         check( value = cpl_property_get_string(p),
00629            "Error reading property value");
00630         
00631         /* match the string  "'<regression_name>D'"  */
00632 
00633         if ((int)strlen(value) >= 1+N+2 &&
00634         value[0]     == '\'' &&
00635         value[1+N]   == 'D' && 
00636         value[1+N+1] == '\'' && 
00637         strncmp(value+1, regression_name, N) == 0
00638         ) {
00639         double coeff;
00640         char *next;
00641         int power[2];
00642         int j = i; /* points to the property currently being read */
00643 
00644         power[0] = 0;  /* Current degree */
00645         power[1] = 0;
00646 
00647         found = true;
00648         value = "dummy"; /* This will make strtod fail the first time */
00649         
00650         while (power[1] <= degree2){
00651             /* Read coefficient */
00652             coeff = strtod(value, &next);
00653             
00654             if (next != value) {
00655             /* A prefix of the string was successfully converted to double */
00656             cpl_polynomial_set_coeff(pol, power, coeff);
00657             uves_msg_debug("Polynomial coefficient of order (%d, %d) is %e", 
00658                        power[0], power[1], coeff);
00659             
00660             power[0]++;
00661             if (power[0] > degree1){
00662                 power[0] = 0;
00663                 power[1]++;
00664             }
00665             value = next;
00666             }
00667             else {
00668             /* No more doubles could be read from the string,
00669                so move to the next property in the plist */
00670             j = j + 1;
00671             
00672             assure(j < plist_size, CPL_ERROR_ILLEGAL_INPUT,
00673                    "Missing header data");
00674             
00675             p = uves_propertylist_get_const(plist, j);
00676             assure(       cpl_property_get_type(p)             == CPL_TYPE_STRING &&
00677                    strcmp(cpl_property_get_name(p), "HISTORY") == 0, 
00678                       CPL_ERROR_ILLEGAL_INPUT, "Error parsing polynomial");
00679             
00680             value = cpl_property_get_string(p);
00681 
00682             
00683             uves_msg_debug("Parsing string '%s'", value);
00684             }
00685         } /* Read coefficients */
00686         } /* string was "'...D'" */
00687     } /* Keyword was HISTORY */
00688     }/* for i... */
00689     
00690     assure( found, CPL_ERROR_ILLEGAL_INPUT, "Could not find '%sD' in property list", 
00691         regression_name);
00692 
00693     /* Create a new polynomial from the cpl_polynomial */
00694     result = uves_polynomial_new(pol);
00695     
00696   cleanup:
00697     uves_free_polynomial(&pol);
00698     if (cpl_error_get_code() != CPL_ERROR_NONE) 
00699     {
00700         uves_polynomial_delete(&result);
00701     }
00702 
00703     return result;
00704 }
00705 
00706 /*----------------------------------------------------------------------------*/
00712 /*----------------------------------------------------------------------------*/
00713 int
00714 uves_polynomial_get_dimension(const polynomial *p)
00715 {
00716     int dim = -1;
00717     assure(p != NULL, CPL_ERROR_ILLEGAL_INPUT, "Null polynomial");
00718 
00719 /* slow     check( dim = cpl_polynomial_get_dimension(p->pol), "Error reading dimension"); */
00720     dim = p->dimension;
00721     
00722   cleanup:
00723     return dim;
00724 }
00725 
00726 /*----------------------------------------------------------------------------*/
00734 /*----------------------------------------------------------------------------*/
00735 void uves_polynomial_dump(const polynomial *p, FILE *stream)
00736 {
00737     if (p == NULL)
00738     fprintf(stream, "Null polynomial\n");
00739     else {
00740     int i;
00741     cpl_polynomial_dump(p->pol, stream);
00742     fprintf(stream, "shift_y \t= %f  \tscale_y \t= %f\n", p->shift[0], p->scale[0]);
00743     for (i = 1; i <= uves_polynomial_get_dimension(p); i++)
00744         {
00745         fprintf(stream, "shift_x%d \t= %f  \tscale_x%d \t= %f\n", 
00746             i, p->shift[i], i, p->scale[i]);
00747         }
00748     }
00749     return;
00750 }
00751 
00752 /*----------------------------------------------------------------------------*/
00766 /*----------------------------------------------------------------------------*/
00767 cpl_error_code
00768 uves_polynomial_rescale(polynomial *p, int varno, double scale)
00769 {
00770     assure(p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
00771     assure(0 <= varno && varno <= uves_polynomial_get_dimension(p), 
00772        CPL_ERROR_ILLEGAL_INPUT, "Illegal variable number: %d", varno);
00773 
00774     /*  Rescaling an x variable by the factor S corresponds to:  
00775      *    p'(x) := p(x/S)  =
00776      *  cpl( (x/S -  shiftx ) /    scalex  ) * scaley + shifty  = 
00777      *  cpl( (x - (S*shiftx)) / (S*scalex) ) * scaley + shifty      */
00778 
00779     /*  Rescaling the y variable by the factor S corresponds to:  
00780      *    p'(x) := S*p(x)  =
00781      *  S * ( cpl((x - shiftx)/scalex) * scaley     + shifty )  = 
00782      *        cpl((x - shiftx)/scalex) * (S*scaley) + (S*shifty) 
00783      *
00784      *  therefore the implementation is the same in the two cases. */
00785      
00786     p->shift[varno] *= scale;
00787     p->scale[varno] *= scale;
00788 
00789   cleanup:
00790     return cpl_error_get_code();
00791 }
00792 
00793 /*----------------------------------------------------------------------------*/
00807 /*----------------------------------------------------------------------------*/
00808 cpl_error_code
00809 uves_polynomial_shift(polynomial *p, int varno, double shift)
00810 {
00811     assure(p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
00812     assure(0 <= varno && varno <= uves_polynomial_get_dimension(p), 
00813        CPL_ERROR_ILLEGAL_INPUT, "Illegal variable number: %d", varno);
00814 
00815     /* The implementation is similar for x and y variables because
00816      *  p(x-S)  =
00817      *  cpl( (x-S - shiftx)   / scalex ) * scaley + shifty  = 
00818      *  cpl( (x - (shiftx+S)) / scalex ) * scaley + shifty
00819      * and
00820      *  p(x) + S  =
00821      *  cpl( (x - shiftx)/scalex ) * scaley + shifty + S  = 
00822      *  cpl( (x - shiftx)/scalex ) * scaley + (shifty+S)      */
00823 
00824     p->shift[varno] += shift;
00825 
00826   cleanup:
00827     return cpl_error_get_code();
00828 }
00829 
00830 /*----------------------------------------------------------------------------*/
00839 /*----------------------------------------------------------------------------*/
00840 double
00841 uves_polynomial_evaluate_1d(const polynomial *p, double x)
00842 {
00843     double result = 0;
00844     
00845     assure(p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
00846     assure(uves_polynomial_get_dimension(p) == 1, 
00847        CPL_ERROR_ILLEGAL_INPUT, "Polynomial must be 1d");
00848     
00849     check( result = 
00850        cpl_polynomial_eval_1d(p->pol, (x - p->shift[1])/p->scale[1], NULL)
00851        * p->scale[0] + p->shift[0],
00852        "Could not evaluate polynomial");
00853     
00854   cleanup:
00855     return result;
00856 }
00857 
00858 
00859 /*----------------------------------------------------------------------------*/
00869 /*----------------------------------------------------------------------------*/
00870 
00871 double
00872 uves_polynomial_evaluate_2d(const polynomial *p, double x1, double x2)
00873 {
00874     double result = 0;
00875 
00876     assure(p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
00877     assure(p->dimension == 2, CPL_ERROR_ILLEGAL_INPUT,
00878        "Polynomial must be 2d. It's %dd", p->dimension);
00879     {
00880         double scale = p->scale[0];
00881         double shift = p->shift[0];
00882 
00883         //    cpl_vector_set(p->vec, 0, (x1 - p->shift[1]) / p->scale[1]);
00884         //    cpl_vector_set(p->vec, 1, (x2 - p->shift[2]) / p->scale[2]);
00885         p->vec_data[0] = (x1 - p->shift[1]) / p->scale[1];
00886         p->vec_data[1] = (x2 - p->shift[2]) / p->scale[2];
00887         
00888         result = cpl_polynomial_eval(p->pol, p->vec) * scale + shift;
00889     }
00890 
00891   cleanup:
00892     return result;
00893 }
00894 
00895 /*----------------------------------------------------------------------------*/
00908 /*----------------------------------------------------------------------------*/
00909 double
00910 uves_polynomial_solve_1d(const polynomial *p, double value, double guess, int multiplicity)
00911 {
00912     double result = 0;
00913     int power[1];
00914     double coeff0;
00915 
00916     assure(p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
00917     assure(uves_polynomial_get_dimension(p) == 1, CPL_ERROR_ILLEGAL_INPUT, 
00918        "Polynomial must be 1d");
00919     
00920     /* Solving p(x) = value corresponds to solving
00921        <=>    cpl_p( (x-xshift)/xscale )*yscale + yshift = value
00922        <=>    cpl_p( (x-xshift)/xscale ) + (yshift - value)/yscale = 0 
00923 
00924        So   1) find zero point for the polynomial   cpl() + (yshift-value)/yscale
00925        Then 2) shift and rescale the result
00926     */
00927 
00928     power[0] = 0;
00929     check(( coeff0 = cpl_polynomial_get_coeff(p->pol, power),
00930         cpl_polynomial_set_coeff(p->pol, power, coeff0 + (p->shift[0] - value)/p->scale[0])),
00931       "Error setting coefficient");
00932 
00933     check( cpl_polynomial_solve_1d(p->pol, (guess - p->shift[1]) / p->scale[1],
00934                    &result, multiplicity), "Could not find root");
00935     /* Restore polynomial */
00936     cpl_polynomial_set_coeff(p->pol, power, coeff0);
00937     
00938     /* Shift solution */
00939     result = result * p->scale[1] + p->shift[1];
00940 
00941   cleanup:
00942     return result;
00943 }
00944 
00945 /*----------------------------------------------------------------------------*/
00962 /*----------------------------------------------------------------------------*/
00963 double
00964 uves_polynomial_solve_2d(const polynomial *p, double value, double guess,
00965              int multiplicity, int varno, double x_value)
00966 {
00967     double result = 0;
00968     polynomial *pol_1d = NULL;
00969 
00970     assure( 1 <= varno && varno <= 2, CPL_ERROR_ILLEGAL_INPUT,
00971         "Illegal variable number: %d", varno);
00972 
00973     check( pol_1d = uves_polynomial_collapse(p, varno, x_value),
00974        "Could not collapse polynomial");
00975 
00976     check( result = uves_polynomial_solve_1d(pol_1d, value, guess, multiplicity),
00977        "Could not find root");
00978 
00979   cleanup:
00980     uves_polynomial_delete(&pol_1d);
00981     return result;
00982 }
00983 
00984 /*----------------------------------------------------------------------------*/
00993 /*----------------------------------------------------------------------------*/
00994 double
00995 uves_polynomial_derivative_2d(const polynomial *p, double x1, double x2, int varno)
00996 {
00997     double result = 0;
00998     int power[2];
00999 
01000     assure (1 <= varno && varno <= 2, CPL_ERROR_ILLEGAL_INPUT,
01001         "Illegal variable number (%d)", varno);
01002 
01003     assure(p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
01004     assure(uves_polynomial_get_dimension(p) == 2, CPL_ERROR_ILLEGAL_INPUT,
01005        "Polynomial must be 2d. It's %dd", uves_polynomial_get_dimension(p));
01006 
01007     /*  d/dx_i [ p(x) ] =
01008      *  d/dx_i [ cpl( (x - shiftx) / scalex ) * scaley + shifty ] = 
01009      *  [ d(cpl)/dx_i ( (x - shiftx) / scalex ) * scaley ]
01010      */
01011 
01012     /* Shift, scale  (x1, x2) */
01013     x1 = (x1 - p->shift[1])/p->scale[1];
01014     x2 = (x2 - p->shift[2])/p->scale[2];
01015  
01016     /* Get derivative of cpl polynomial.
01017      * 
01018      */
01019     {
01020     int degree = cpl_polynomial_get_degree(p->pol);
01021     double yj = 1;  /* y^j */
01022     int i, j;
01023     
01024     result = 0;
01025     for (j = 0, yj = 1;
01026          j <= degree; j++,
01027          yj *= (varno == 1) ? x2 : x1)
01028         {
01029         /*  Proof by example (degree = 3): For each j account for these terms
01030          *  using Horner's rule:
01031          *
01032          * d/dx     y^j * [  c_3j x^3 +  c_2j x^2 +  c_1j x^1 + c_0j ]   =
01033          *
01034          *          y^j * [ 3c_3j x^2 + 2c_2j x^1 + 1c_1j ]     =
01035          *
01036          *          y^j * [ ((3c_3j) x + 2c_2j) x + 1c_1j ]
01037          */
01038 
01039         double sum = 0;
01040         for (i = degree; i >= 1; i--)
01041             {
01042             double c_ij;
01043 
01044             power[0] = (varno == 1) ? i : j;
01045             power[1] = (varno == 1) ? j : i;
01046             
01047             c_ij = cpl_polynomial_get_coeff(p->pol, power);
01048             
01049             sum += (i * c_ij);
01050             if (i >= 2) sum *= (varno == 1) ? x1 : x2;
01051             }
01052 
01053         /* Collect terms */
01054         result += yj * sum;
01055         }
01056     }
01057 
01058     result *= p->scale[0];
01059 
01060 
01061 /* Old code: This method (valid for varno = 2)
01062    of getting the derivative of
01063    the CPL polynomial is slow because of the call to 
01064    uves_polynomial_collapse()
01065 
01066    check( pol_1d = uves_polynomial_collapse(p, 1, x1);
01067    dummy = cpl_polynomial_eval_1d(pol_1d->pol, (x2 - pol_1d->shift[1])/pol_1d->scale[1], &result),
01068    "Error evaluating derivative");
01069 */
01070     
01071   cleanup:
01072     return result;
01073 }
01074 
01075 /*----------------------------------------------------------------------------*/
01082 /*----------------------------------------------------------------------------*/
01083 double
01084 uves_polynomial_derivative_1d(const polynomial *p, double x)
01085 {
01086     double result = 0;
01087     double dummy;
01088 
01089     assure(p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
01090     assure(uves_polynomial_get_dimension(p) == 1, 
01091        CPL_ERROR_ILLEGAL_INPUT, "Polynomial must be 1d");
01092     
01093     check( dummy = cpl_polynomial_eval_1d(p->pol, (x - p->shift[1])/p->scale[1], &result),
01094        "Error evaluating derivative");
01095     
01096   cleanup:
01097     return result;
01098 }
01099 
01100 /*----------------------------------------------------------------------------*/
01107 /*----------------------------------------------------------------------------*/
01108 polynomial *
01109 uves_polynomial_add_2d(const polynomial *p1, const polynomial *p2)
01110 {
01111     polynomial *result = NULL;
01112     cpl_polynomial *pol = NULL;
01113 
01114     assure(p1 != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
01115     assure(p2 != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
01116     assure(uves_polynomial_get_dimension(p1) == 2, 
01117        CPL_ERROR_ILLEGAL_INPUT, "Polynomial must be 2d");
01118     assure(uves_polynomial_get_dimension(p2) == 2, 
01119        CPL_ERROR_ILLEGAL_INPUT, "Polynomial must be 2d");
01120 
01121     /* cpl_polynomial1((x - shift_x1)/scale_x1) * scale_y1 + shift_y1
01122        +
01123        cpl_polynomial2((x - shift_x2)/scale_x2) * scale_y2 + shift_y2
01124        = ???
01125        Not easy.
01126 
01127        Use brute force:
01128     */
01129     
01130     {
01131         int degree, i, j;
01132 
01133         degree = uves_max_int(uves_polynomial_get_degree(p1),
01134                               uves_polynomial_get_degree(p2));
01135         
01136         pol = cpl_polynomial_new(2);
01137         for (i = 0; i <= degree; i++)
01138             for (j = 0; j <= degree; j++) {
01139                 double coeff1, coeff2;
01140                 int power[2];
01141 
01142                 /* Simple: add coefficients of the same power */
01143                 coeff1 = uves_polynomial_get_coeff_2d(p1, i, j);
01144                 coeff2 = uves_polynomial_get_coeff_2d(p2, i, j);
01145                 
01146                 power[0] = i;
01147                 power[1] = j;
01148                 cpl_polynomial_set_coeff(pol, power, coeff1 + coeff2);
01149             }
01150     }
01151 
01152     result = uves_polynomial_new(pol);
01153    
01154   cleanup:
01155     uves_free_polynomial(&pol);
01156     return result;
01157 }
01158 
01159 /*----------------------------------------------------------------------------*/
01172 /*----------------------------------------------------------------------------*/
01173 static cpl_error_code
01174 derivative_cpl_polynomial(cpl_polynomial *p, int varno)
01175 {
01176     int dimension, degree;
01177     int i, j;
01178     int power[2];
01179     
01180     assure(p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
01181     dimension = cpl_polynomial_get_dimension(p);
01182     degree = cpl_polynomial_get_degree(p);
01183     assure( 1 <= dimension && dimension <= 2, CPL_ERROR_ILLEGAL_INPUT, 
01184         "Illegal dimension: %d", dimension);
01185     assure( 1 <= varno && varno <= dimension, CPL_ERROR_ILLEGAL_INPUT,
01186         "Illegal variable number: %d", varno);
01187     
01188     if (dimension == 1)
01189     {
01190         /*  a_i := (i+1) * a_(i+1) */
01191         for(i = 0; i <= degree; i++)
01192         {
01193             double coeff;
01194             power[0] = i+1;
01195             /* power[1] is ignored */
01196             
01197             coeff = cpl_polynomial_get_coeff(p, power);
01198                 
01199             power[0] = i;            
01200             cpl_polynomial_set_coeff(p, power, (i+1) * coeff);
01201         }
01202     }
01203     
01204     if (dimension == 2)
01205     {
01206         /*  a_ij := (i+1) * a_{(i+1),j} */
01207         for(i = 0; i <= degree; i++)
01208         {
01209             for(j = 0; i + j <= degree; j++)
01210             {
01211                 double coeff;
01212                 power[varno - 1] = i+1;    /* varno == 1:    0,1  */ 
01213                 power[2 - varno] = j;      /* varno == 2:    1,0  */
01214                 
01215                 coeff = cpl_polynomial_get_coeff(p, power);
01216                 
01217                 power[varno - 1] = i;
01218                 
01219                 cpl_polynomial_set_coeff(p, power, (i+1) * coeff);
01220             }
01221         }
01222     }
01223 
01224   cleanup:
01225     return cpl_error_get_code();
01226 }
01227 
01228 /*----------------------------------------------------------------------------*/
01238 /*----------------------------------------------------------------------------*/
01239 cpl_error_code
01240 uves_polynomial_derivative(polynomial *p, int varno)
01241 {
01242     int dimension;
01243     
01244     assure( p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
01245     check ( dimension = uves_polynomial_get_dimension(p), "Error reading dimension");
01246     assure( 1 <= varno && varno <= dimension, CPL_ERROR_ILLEGAL_INPUT, 
01247         "Illegal variable number: %d", varno);
01248 
01249 
01250     /*   d/dx_i [ cpl( (x - shiftx) / scalex ) * scaley + shifty ] = 
01251      *     sum_j d(cpl)/dx_j ( (x - shiftx) / scalex ) * scaley * dx_j/dx_i / scalex_j =
01252      *     d(cpl)/dx_i ( (x - shiftx) / scalex ) * scaley/scalex_i,
01253      * 
01254      * so transform :      shifty -> 0
01255      *                     shiftx -> shiftx
01256      *                     scaley -> scaley/scalex_i
01257      *                     scalex -> scalex
01258      *                       cpl  -> d(cpl)/dx_i
01259      */
01260 
01261     p->shift[0] = 0;
01262     p->scale[0] = p->scale[0] / p->scale[varno];
01263 
01264     check( derivative_cpl_polynomial(p->pol, varno),
01265        "Error calculating derivative of CPL-polynomial");
01266     
01267   cleanup:
01268     return cpl_error_get_code();
01269 }
01270 
01271 
01272 /*----------------------------------------------------------------------------*/
01281 /*----------------------------------------------------------------------------*/
01282 double
01283 uves_polynomial_get_coeff_2d(const polynomial *p, int degree1, int degree2)
01284 {
01285     polynomial *pp = NULL;
01286     int dimension;
01287     double result = 0;
01288     double factorial;
01289     
01290     assure( p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
01291     check ( dimension = uves_polynomial_get_dimension(p), "Error reading dimension");
01292     assure(dimension == 2, CPL_ERROR_ILLEGAL_INPUT, "Illegal dimension: %d", dimension);
01293     assure( 0 <= degree1, CPL_ERROR_ILLEGAL_INPUT, "Illegal degree: %d", degree1);
01294     assure( 0 <= degree2, CPL_ERROR_ILLEGAL_INPUT, "Illegal degree: %d", degree2);
01295 
01296     /* Calculate the coefficient as
01297      * d^N p / (dx1^degree1 dx2^degree2)  /  (degree1! * degree2!)
01298      * evaluated in (0,0)
01299     */
01300 
01301     pp = uves_polynomial_duplicate(p);
01302 
01303     factorial = 1;
01304     while(degree1 > 0)
01305     {
01306         check( uves_polynomial_derivative(pp, 1), "Error calculating derivative");
01307 
01308         factorial *= degree1;
01309         degree1 -= 1;
01310     }
01311 
01312     while(degree2 > 0)
01313     {
01314         check( uves_polynomial_derivative(pp, 2), "Error calculating derivative");
01315 
01316         factorial *= degree2;
01317         degree2 -= 1;
01318     }
01319     
01320     check( result = uves_polynomial_evaluate_2d(pp, 0, 0) / factorial,
01321        "Error evaluating polynomial");
01322     
01323   cleanup:
01324     uves_polynomial_delete(&pp);
01325     return result;
01326 }
01327 /*----------------------------------------------------------------------------*/
01337 /*----------------------------------------------------------------------------*/
01338 double
01339 uves_polynomial_get_coeff_1d(const polynomial *p, int degree)
01340 {
01341     polynomial *pp = NULL;
01342     int dimension;
01343     double result = 0;
01344     double factorial;
01345     
01346     assure( p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
01347     check ( dimension = uves_polynomial_get_dimension(p), "Error reading dimension");
01348     assure(dimension == 1, CPL_ERROR_ILLEGAL_INPUT, "Illegal dimension: %d", dimension);
01349     assure( 0 <= degree, CPL_ERROR_ILLEGAL_INPUT, "Illegal degree: %d", degree);
01350     
01351     /* Calculate the coefficient as
01352      *  d^degree p/dx^degree  /  (degree1! * degree2!)
01353      * evaluated in 0.
01354      */
01355     
01356     pp = uves_polynomial_duplicate(p);
01357     
01358     factorial = 1;
01359     while(degree > 0)
01360     {
01361         check( uves_polynomial_derivative(pp, 1), "Error calculating derivative");
01362         
01363         factorial *= degree;
01364         degree -= 1;
01365     }
01366     
01367     check( result = uves_polynomial_evaluate_1d(pp, 0) / factorial,
01368        "Error evaluating polynomial");
01369     
01370   cleanup:
01371     uves_polynomial_delete(&pp);
01372     return result;
01373 }
01374 
01375 
01376 /*----------------------------------------------------------------------------*/
01392 /*----------------------------------------------------------------------------*/
01393 polynomial *
01394 uves_polynomial_collapse(const polynomial *p, int varno, double value)
01395 {
01396     polynomial     *result  = NULL;
01397     cpl_polynomial *pol     = NULL;
01398     int            *power     = NULL;
01399 
01400     int i, j;
01401     int degree, dimension;
01402     
01403     assure(p != NULL, CPL_ERROR_NULL_INPUT, "Null polynomial");
01404     dimension = uves_polynomial_get_dimension(p);
01405     assure(dimension  > 0, CPL_ERROR_ILLEGAL_INPUT,
01406        "Polynomial has non-positive dimension: %d", dimension);
01407     assure(dimension != 1, CPL_ERROR_ILLEGAL_OUTPUT,
01408        "Don't collapse a 1d polynomial. Evaluate it!");
01409 
01410     /* To generalize this function to work with dimensions higher than 2,
01411        also changes needs to be made below (use varno properly). For now,
01412        support only 2d. */
01413     assure(dimension == 2, CPL_ERROR_ILLEGAL_INPUT, "Polynomial must be 2d");
01414     
01415     assure(1 <= varno && varno <= dimension, CPL_ERROR_ILLEGAL_INPUT, 
01416        "Wrong variable number");
01417     value = (value - p->shift[varno]) / p->scale[varno];
01418 
01419     /* Compute new coefficients */
01420     degree = cpl_polynomial_get_degree(p->pol);
01421     pol    = cpl_polynomial_new(dimension - 1);
01422     power = cpl_malloc(sizeof(int) * dimension);
01423     assure_mem( power );
01424     for (i = 0; i <= degree; i++) 
01425     {
01426         double coeff;
01427         
01428         power[2-varno] = i;   /* map 2->0  and 1->1 */
01429         
01430         /* Collect all terms with x^i  (using Horner's rule) */
01431         coeff = 0;
01432         for (j = degree - i; j >= 0; j--) 
01433         {
01434             power[varno-1] = j;  /* map 2->1 and 1->0 */
01435             coeff += cpl_polynomial_get_coeff(p->pol, power);
01436             if (j > 0) coeff *= value;
01437         }
01438         /* Write coefficient in 1d polynomial */
01439         power[0] = i;
01440         cpl_polynomial_set_coeff(pol, power, coeff);
01441     }
01442     
01443     /* Wrap the polynomial */
01444     result = uves_polynomial_new(pol);
01445 
01446     /* Copy the shifts and scales, skip variable number varno */
01447     j = 0;
01448     for(i = 0; i <= dimension - 1; i++) 
01449     {
01450         if (i == varno) 
01451         {
01452             /* Don't copy */
01453             j += 2;
01454             /* For the remainder of this for loop, j = i+1 */
01455         }
01456         else 
01457         {
01458             result->shift[i] = p->shift[j];
01459             result->scale[i] = p->scale[j];
01460             j += 1;
01461         }
01462     }
01463     
01464     assure(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(), 
01465        "Error collapsing polynomial");
01466     
01467   cleanup:
01468     cpl_free(power); power = NULL;
01469     uves_free_polynomial(&pol);
01470     if (cpl_error_get_code() != CPL_ERROR_NONE)
01471     {
01472         uves_polynomial_delete(&result);
01473     }
01474     return result;
01475 }
01476 
01477 
01478 
01479 /*----------------------------------------------------------------------------*/
01499 /*----------------------------------------------------------------------------*/
01500 polynomial * uves_polynomial_fit_1d(
01501     const cpl_vector    *   x_pos,
01502     const cpl_vector    *   values,
01503     const cpl_vector    *   sigmas,
01504     int                     poly_deg,
01505     double              *   mse)
01506 {
01507     int                 nc ;
01508     int                 np ;
01509     cpl_matrix      *   ma = NULL;
01510     cpl_matrix      *   mb = NULL;
01511     cpl_matrix      *   mx = NULL;
01512     const double    *   x_pos_data ;
01513     const double    *   values_data ;
01514     const double    *   sigmas_data = NULL;
01515     double              mean_x, mean_z;
01516     polynomial      *   result = NULL;
01517     cpl_polynomial  *   out ;
01518     cpl_vector      *   x_val = NULL;
01519     int                 i, j ;
01520     
01521     /* Check entries */
01522     assure_nomsg( x_pos != NULL && values != NULL, CPL_ERROR_NULL_INPUT);
01523     assure( poly_deg >= 0, CPL_ERROR_ILLEGAL_INPUT, 
01524         "Polynomial degree is %d. Must be non-negative", poly_deg);
01525     np = cpl_vector_get_size(x_pos) ;
01526     
01527     nc = 1 + poly_deg ;
01528     assure( np >= nc, CPL_ERROR_ILLEGAL_INPUT,
01529         "Not enough points (%d) to fit %d-order polynomial. %d point(s) needed",
01530         np, poly_deg, nc);
01531 
01532     /* Fill up look-up table for coefficients to compute */
01533     /* Initialize matrices */
01534     /* ma contains the polynomial terms for each input point. */
01535     /* mb contains the values */
01536     ma = cpl_matrix_new(np, nc) ;
01537     mb = cpl_matrix_new(np, 1) ;
01538 
01539     /* Get mean values */
01540     mean_x = cpl_vector_get_mean(x_pos);
01541     mean_z = cpl_vector_get_mean(values);
01542 
01543     /* Fill up matrices, shift */
01544     x_pos_data = irplib_vector_get_data_const(x_pos) ;
01545     values_data = irplib_vector_get_data_const(values) ;
01546     if (sigmas != NULL)
01547     {
01548         sigmas_data = irplib_vector_get_data_const(sigmas) ;
01549     }
01550 
01551     if (sigmas != NULL)
01552     {
01553         for (i=0 ; i<np ; i++) 
01554         {
01555             /* Catch division by zero */
01556             if (sigmas_data[i] == 0)
01557             {
01558                 uves_free_matrix(&ma) ;
01559                 uves_free_matrix(&mb) ;
01560                 assure(false, CPL_ERROR_DIVISION_BY_ZERO,
01561                    "Sigmas must be non-zero");
01562             }
01563             for (j=0 ; j<nc ; j++) 
01564             {
01565                 cpl_matrix_set(ma, i, j,  
01566                        uves_pow_int(x_pos_data[i] - mean_x, j) /
01567                        sigmas_data[i]) ;
01568             }
01569             /* mb contains surface values (z-axis) */
01570             cpl_matrix_set(mb, i, 0, (values_data[i] - mean_z) / sigmas_data[i]);
01571         }
01572     }
01573     else  /* Use sigma = 1 */
01574     {
01575         for (i=0 ; i<np ; i++) 
01576         {
01577             for (j=0 ; j<nc ; j++) 
01578             {
01579                 cpl_matrix_set(ma, i, j,  
01580                        uves_pow_int(x_pos_data[i] - mean_x, j) / 1);
01581             }
01582             /* mb contains surface values (z-values) */
01583             cpl_matrix_set(mb, i, 0, (values_data[i] - mean_z) / 1) ;
01584         }
01585     }
01586     
01587     /* Solve XA=B by a least-square solution (aka pseudo-inverse). */
01588     check( mx = cpl_matrix_solve_normal(ma, mb),
01589        "Could not invert matrix");
01590     uves_free_matrix(&ma);
01591     uves_free_matrix(&mb);
01592 
01593     /* Store coefficients for output */
01594     out = cpl_polynomial_new(1) ;
01595 
01596     for (i=0 ; i<nc ; i++) {
01597         cpl_polynomial_set_coeff(out, &i, cpl_matrix_get(mx, i, 0)) ;
01598     }
01599     uves_free_matrix(&mx);
01600 
01601     /* If requested, compute mean squared error */
01602     if (mse != NULL) {
01603         *mse = 0.00 ;
01604         x_val = cpl_vector_new(1) ;
01605         for (i=0 ; i<np ; i++)
01606         {
01607         double residual;
01608         cpl_vector_set(x_val, 0, x_pos_data[i] - mean_x) ;
01609         /* Subtract from the true value, square, accumulate */
01610         residual = (values_data[i] - mean_z) - cpl_polynomial_eval(out, x_val);
01611         *mse += residual*residual;
01612         }
01613         uves_free_vector(&x_val) ;
01614         /* Average the error term */
01615         *mse /= (double)np ;
01616     }
01617 
01618     /* Create and shift result */
01619     result = uves_polynomial_new(out);
01620     uves_free_polynomial(&out);
01621 
01622     uves_polynomial_shift(result, 0, mean_z);
01623     uves_polynomial_shift(result, 1, mean_x);
01624 
01625   cleanup:
01626     uves_free_vector(&x_val);
01627     uves_free_matrix(&ma);
01628     uves_free_matrix(&mb);
01629     uves_free_matrix(&mx);
01630     return result;
01631 }
01632 
01633 
01634 /*----------------------------------------------------------------------------*/
01678 /*----------------------------------------------------------------------------*/
01679 polynomial *
01680 uves_polynomial_fit_2d(
01681     const cpl_bivector     *  xy_pos,
01682     const cpl_vector       *  values,
01683     const cpl_vector       *  sigmas,
01684     int                       poly_deg1,
01685     int                       poly_deg2,
01686     double                 *  mse,
01687     double                 *  red_chisq,
01688     polynomial             ** variance)
01689 {
01690     int                 nc ;
01691     int                 degx, degy ;
01692     int             *   degx_tab ;
01693     int             *   degy_tab ;
01694     int                 np ;
01695     cpl_matrix      *   ma ;
01696     cpl_matrix      *   mb ;
01697     cpl_matrix      *   mx ;
01698     cpl_matrix      *   mat;
01699     cpl_matrix      *   mat_ma;
01700     cpl_matrix      *   cov = NULL;
01701     const double    *   xy_pos_data_x ;
01702     const double    *   xy_pos_data_y ;
01703     const double    *   values_data ;
01704     const double    *   sigmas_data = NULL;
01705     const cpl_vector*   xy_pos_x;
01706     const cpl_vector*   xy_pos_y;
01707     double              mean_x, mean_y, mean_z;
01708     cpl_polynomial  *   out ;
01709     cpl_polynomial  *   variance_cpl ;
01710     polynomial      *   result         = NULL;
01711     int             *   powers ;
01712 
01713     /* Check entries */
01714     assure(xy_pos && values, CPL_ERROR_NULL_INPUT, "Null input");
01715     assure(poly_deg1 >= 0, CPL_ERROR_ILLEGAL_INPUT, "Polynomial degree1 is %d", poly_deg1);
01716     assure(poly_deg2 >= 0, CPL_ERROR_ILLEGAL_INPUT, "Polynomial degree2 is %d", poly_deg2);
01717     np = cpl_bivector_get_size(xy_pos) ;
01718 
01719     /* Can't calculate variance and chi_sq without sigmas */
01720     assure( (variance == NULL && red_chisq == NULL) || sigmas != NULL, 
01721         CPL_ERROR_ILLEGAL_INPUT, 
01722         "Cannot calculate variance or chi_sq without knowing");
01723 
01724     /* Fill up look-up table for coefficients to compute */
01725     nc = (1 + poly_deg1)*(1 + poly_deg2) ;     /* rectangular matrix */
01726     
01727     assure(np >= nc, CPL_ERROR_SINGULAR_MATRIX, "%d coefficients. Only %d points", nc, np);
01728     /* The error code here is set to SINGULAR_MATRIX, in order to allow the caller
01729        to detect when too many coefficients are fitted to too few points */
01730 
01731     /* Need an extra point to calculate reduced chi^2 */
01732     assure(red_chisq == NULL || np > nc, CPL_ERROR_ILLEGAL_INPUT, 
01733        "%d coefficients. %d points. Cannot calculate chi square", nc, np);
01734     
01735     degx_tab = cpl_malloc(nc * sizeof(int)) ;
01736     assure_mem( degx_tab );
01737 
01738     degy_tab = cpl_malloc(nc * sizeof(int)) ;
01739     if (degy_tab == NULL) {
01740     cpl_free(degx_tab);
01741     assure_mem( false );
01742     }
01743 
01744     {
01745         int i=0 ;
01746         for (degy=0 ; degy<=poly_deg2 ; degy++) {     /* rectangular matrix */
01747             for (degx=0 ; degx<=poly_deg1 ; degx++) {
01748                 degx_tab[i] = degx ;
01749                 degy_tab[i] = degy ;
01750                 i++ ;
01751             }
01752         }
01753     }
01754     
01755     /* Initialize matrices */
01756     /* ma contains the polynomial terms in the order described */
01757     /* above in each column, for each input point. */
01758     /* mb contains the values */
01759     ma = cpl_matrix_new(np, nc) ;
01760     mb = cpl_matrix_new(np, 1) ;
01761 
01762     /* Get the mean of each variable */
01763     xy_pos_x = irplib_bivector_get_x_const(xy_pos);
01764     xy_pos_y = irplib_bivector_get_y_const(xy_pos);
01765 
01766     mean_x = cpl_vector_get_mean(xy_pos_x);
01767     mean_y = cpl_vector_get_mean(xy_pos_y);
01768     mean_z = cpl_vector_get_mean(values);
01769 
01770     /* Fill up matrices. At the same time shift the data
01771        so that it is centered around zero */
01772     xy_pos_data_x = irplib_vector_get_data_const(xy_pos_x) ;
01773     xy_pos_data_y = irplib_vector_get_data_const(xy_pos_y) ;
01774     values_data   = irplib_vector_get_data_const(values) ;
01775     if (sigmas != NULL)
01776     {
01777         sigmas_data = irplib_vector_get_data_const(sigmas) ;
01778     }
01779 
01780     if (sigmas != NULL)
01781     {
01782             int i;
01783         for (i=0 ; i<np ; i++) {
01784                 double *ma_data = cpl_matrix_get_data(ma);
01785                 double *mb_data = cpl_matrix_get_data(mb);
01786 
01787                 int j = 0;
01788                 double valy = 1;
01789 
01790         /* Catch division by zero */
01791         if (sigmas_data[i] == 0)
01792             {
01793             uves_free_matrix(&ma) ;
01794             uves_free_matrix(&mb) ;
01795             cpl_free(degx_tab) ;
01796             cpl_free(degy_tab) ;
01797             assure(false, CPL_ERROR_DIVISION_BY_ZERO,
01798                                "Sigmas must be non-zero. sigma[%d] is %f", i, sigmas_data[i]);
01799             }
01800 
01801                 for (degy=0 ; degy<=poly_deg2 ; degy++) {
01802                     double valx = 1; 
01803                     for (degx=0 ; degx<=poly_deg1 ; degx++) {
01804                         ma_data[j + i*nc] = valx * valy / sigmas_data[i];
01805                         valx *= (xy_pos_data_x[i] - mean_x);
01806                         j++;
01807                     }
01808                     valy *= (xy_pos_data_y[i] - mean_y);
01809                 }
01810 
01811         /* mb contains surface values (z-axis) */
01812 
01813         mb_data[0 + i*1] = (values_data[i] - mean_z) / sigmas_data[i];
01814         }
01815     }
01816     else  /* Use sigma = 1 */
01817     {
01818             int i;
01819         for (i=0 ; i<np ; i++) {
01820                 double *ma_data = cpl_matrix_get_data(ma);
01821                 double *mb_data = cpl_matrix_get_data(mb);
01822 
01823                 double valy = 1;
01824                 int j = 0;
01825                 for (degy=0 ; degy<=poly_deg2 ; degy++) {
01826                     double valx = 1; 
01827                     for (degx=0 ; degx<=poly_deg1 ; degx++) {
01828                         ma_data[j + i*nc] = valx * valy / 1;
01829                         valx *= (xy_pos_data_x[i] - mean_x);
01830                         j++;
01831                     }
01832                     valy *= (xy_pos_data_y[i] - mean_y);
01833                 }
01834 
01835         /* mb contains surface values (z-axis) */
01836 //        cpl_matrix_set(mb, i, 0, (values_data[i] - mean_z) / 1) ;
01837         mb_data[0 + i*1] = (values_data[i] - mean_z) / 1;
01838         }
01839     }
01840     
01841     /* If variance polynomial is requested, 
01842        compute covariance matrix = (A^T * A)^-1 */
01843     if (variance != NULL)
01844     {
01845         mat    = cpl_matrix_transpose_create(ma);
01846         if (mat != NULL)
01847         {
01848             mat_ma = cpl_matrix_product_create(mat, ma);
01849             if (mat_ma != NULL)
01850             {
01851                 cov          = cpl_matrix_invert_create(mat_ma);
01852                 /* Here, one might do a (paranoia) check that the covariance
01853                    matrix is symmetrical and has positive eigenvalues (so that
01854                    the returned variance polynomial is guaranteed to be positive) */
01855 
01856                 variance_cpl = cpl_polynomial_new(2);
01857             }
01858         }
01859         uves_free_matrix(&mat);
01860         uves_free_matrix(&mat_ma);
01861     }
01862 
01863     /* Solve XA=B by a least-square solution (aka pseudo-inverse). */
01864     mx = cpl_matrix_solve_normal(ma, mb) ;
01865 
01866     uves_free_matrix(&ma) ;
01867     uves_free_matrix(&mb) ;
01868     if (mx == NULL) {
01869         cpl_free(degx_tab) ;
01870         cpl_free(degy_tab) ;
01871     uves_free_matrix(&cov) ;
01872         assure(false, CPL_ERROR_ILLEGAL_OUTPUT, "Matrix inversion failed") ;
01873     }
01874 
01875     /* Store coefficients for output */
01876     out = cpl_polynomial_new(2) ;
01877     powers = cpl_malloc(2 * sizeof(int)) ;
01878     if (powers == NULL) {
01879         cpl_free(degx_tab) ;
01880         cpl_free(degy_tab) ;
01881     uves_free_matrix(&mx) ;
01882     uves_free_matrix(&cov) ;
01883     uves_free_polynomial(&out) ;
01884     assure_mem( false );
01885     }
01886 
01887     {
01888         int i;
01889     for (i = 0 ; i < nc ; i++)
01890     {
01891         powers[0] = degx_tab[i] ;
01892         powers[1] = degy_tab[i] ;
01893         cpl_polynomial_set_coeff(out, powers, cpl_matrix_get(mx, i, 0)) ;
01894         
01895         /* Create variance polynomial (if requested) */
01896         if (variance != NULL &&                   /* Requested? */
01897         cov != NULL && variance_cpl != NULL   /* covariance computation succeeded? */
01898         )
01899         {
01900                     int j;
01901             for (j = 0; j < nc; j++)
01902             {
01903                 double coeff;
01904                 /* Add cov_ij to the proper coeff:
01905                    cov_ij * dp/d(ai) * dp/d(aj) =
01906                    cov_ij * (x^degx[i] * y^degy[i]) * (x^degx[i] * y^degy[i]) =
01907                    cov_ij * x^(degx[i]+degx[j]) * y^(degy[i] + degy[j]),
01908                    
01909                    i.e. add cov_ij to coeff (degx[i]+degx[j], degy[i]+degy[j]) */
01910                 powers[0] = degx_tab[i] + degx_tab[j] ;
01911                 powers[1] = degy_tab[i] + degy_tab[j] ;
01912                 
01913                 coeff = cpl_polynomial_get_coeff(variance_cpl, powers);
01914                 cpl_polynomial_set_coeff(variance_cpl, powers, 
01915                              coeff + cpl_matrix_get(cov, i, j)) ;
01916             }
01917         }
01918     }
01919     }
01920     
01921     cpl_free(powers) ;
01922     cpl_free(degx_tab) ;
01923     cpl_free(degy_tab) ;
01924     uves_free_matrix(&cov) ;
01925     uves_free_matrix(&mx) ;
01926     
01927     /* Create and shift result */
01928     result = uves_polynomial_new(out);
01929     uves_free_polynomial(&out);
01930     uves_polynomial_shift(result, 0, mean_z);
01931     uves_polynomial_shift(result, 1, mean_x);
01932     uves_polynomial_shift(result, 2, mean_y);
01933 
01934     /* Wrap up variance polynomial */
01935     if (variance != NULL)
01936     {
01937         *variance = uves_polynomial_new(variance_cpl);
01938         uves_free_polynomial(&variance_cpl);
01939             /* The variance of the fit does not change
01940            when a constant is added to the a_00
01941            coefficient of the polynomial, so don't:
01942            uves_polynomial_shift(*variance, 0, mean_z); */
01943         uves_polynomial_shift(*variance, 1, mean_x);
01944         uves_polynomial_shift(*variance, 2, mean_y);
01945 
01946         /* Maybe here add a consistency check that the variance polynomial is 
01947            positive at all input points */
01948     }  
01949 
01950     /* If requested, compute mean squared error */
01951     if (mse != NULL || red_chisq != NULL) 
01952     {
01953             int i;
01954 
01955         if (mse       != NULL) *mse = 0.00 ;
01956         if (red_chisq != NULL) *red_chisq = 0.00 ;
01957         for (i = 0 ; i < np ; i++) 
01958         {
01959             double regress = uves_polynomial_evaluate_2d(result, 
01960                                  xy_pos_data_x[i],
01961                                  xy_pos_data_y[i]);
01962             /* Subtract from the true value, square, accumulate */
01963             if (mse != NULL)
01964             {
01965                 double residual = values_data[i] - regress;
01966                 *mse += residual*residual;
01967             }
01968             if (red_chisq != NULL)
01969             {
01970                 *red_chisq += uves_pow_int((values_data[i] - regress) /
01971                                sigmas_data[i], 2);
01972             }
01973         }
01974         /* Get average */
01975         if (mse       != NULL)  *mse       /= (double) np ;
01976         
01977         if (red_chisq != NULL)
01978         {
01979             passure( np > nc, "%d %d", np, nc); /* Was already checked */
01980             *red_chisq /= (double) (np - nc) ;
01981         }
01982     }
01983 
01984   cleanup:
01985     return result ;
01986 }
01987 
01988 

Generated on Tue Jun 19 14:39:18 2007 for UVES Pipeline Reference Manual by  doxygen 1.4.6