IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ticket #482: psPolynomials.c

File psPolynomials.c, 15.3 KB (added by eugene, 21 years ago)

my implementation examples of ordinary polynomial fitting functions

Line 
1# include "psphot.h"
2
3// write out the terms of the given 1D polynomial
4void psPolynomial1DDump (psPolynomial1D *poly) {
5
6 for (int i = 0; i < poly->n + 1; i++) {
7 fprintf (stderr, "x^%d : %g +/- %g\n", i, poly->coeff[i], poly->coeffErr[i]);
8 }
9}
10
11psF32 Polynomial1DEval_EAM(psF32 x, const psPolynomial1D* myPoly)
12{
13 psS32 loop_x = 0;
14 psF32 polySum = 0.0;
15 psF32 xSum = 1.0;
16
17 for (loop_x = 0; loop_x < myPoly->n + 1; loop_x++) {
18 if (myPoly->mask[loop_x] == 0) {
19 polySum += xSum * myPoly->coeff[loop_x];
20 }
21 xSum *= x;
22 }
23
24 return(polySum);
25}
26
27psVector *Polynomial1DEvalVector_EAM(const psPolynomial1D *myPoly,
28 const psVector *x)
29{
30 PS_POLY_CHECK_NULL(myPoly, NULL);
31 PS_VECTOR_CHECK_NULL(x, NULL);
32 PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F64, NULL);
33
34 psVector *tmp;
35
36 tmp = psVectorAlloc(x->n, PS_TYPE_F64);
37 for (psS32 i=0;i<x->n;i++) {
38 tmp->data.F64[i] = Polynomial1DEval_EAM(x->data.F64[i], myPoly);
39 }
40
41 return(tmp);
42}
43
44// XXX EAM : use Nterm = Norder + 1 definition
45// XXX EAM : should we provide both order and nterms in struct?
46psPolynomial1D* Polynomial1DAlloc(psS32 nOrder,
47 psPolynomialType type)
48{
49 PS_INT_CHECK_NON_NEGATIVE(nOrder, NULL);
50
51 psS32 i = 0;
52 psS32 nTerm = nOrder + 1;
53 psPolynomial1D* newPoly = NULL;
54
55 newPoly = (psPolynomial1D* ) psAlloc(sizeof(psPolynomial1D));
56 // p_psMemSetDeallocator(newPoly, (psFreeFcn) polynomial1DFree);
57 // XXX EAM : me, being lazy
58
59 newPoly->type = type;
60 newPoly->n = nOrder;
61 newPoly->coeff = (psF32 *)psAlloc(nTerm * sizeof(psF32));
62 newPoly->coeffErr = (psF32 *)psAlloc(nTerm * sizeof(psF32));
63 newPoly->mask = (psU8 *)psAlloc(nTerm * sizeof(psU8));
64 for (i = 0; i < nTerm; i++) {
65 newPoly->coeff[i] = 0.0;
66 newPoly->coeffErr[i] = 0.0;
67 newPoly->mask[i] = 0;
68 }
69 return(newPoly);
70}
71
72// XXX EAM : my alternate BuildSums1D
73static psVector *BuildSums1D(psVector* sums,
74 psF64 x,
75 psS32 nTerm)
76{
77 psS32 nSum = 0;
78 psF64 xSum = 0.0;
79
80 nSum = 2*nTerm;
81 if (sums == NULL) {
82 sums = psVectorAlloc(nSum, PS_TYPE_F64);
83 }
84 if (nSum > sums->n) {
85 sums = psVectorRealloc(sums, nSum);
86 }
87
88 xSum = 1.0;
89 for (int i = 0; i < nSum; i++) {
90 sums->data.F64[i] = xSum;
91 xSum *= x;
92 }
93 return (sums);
94}
95
96// XXX EAM : test version of 1d fitting
97psPolynomial1D* VectorFitPolynomial1DOrd_EAM(psPolynomial1D* myPoly,
98 psVector *mask,
99 const psVector *x,
100 const psVector *y,
101 const psVector *yErr)
102{
103 // I think this is 1 dimension down
104 psImage* A = NULL;
105 psVector* B = NULL;
106 psVector* xSums = NULL;
107 psS32 nTerm;
108 psF64 wt;
109
110 psTrace(".psLib.dataManip.VectorFitPolynomial1DOrd", 4,
111 "---- VectorFitPolynomial1DOrd() begin ----\n");
112
113 // dump minutiae
114# ifndef PS_NO_TRACE
115 if (psTraceGetLevel (".psLib.dataManip.VectorFitPolynomial1DOrd") >= 5) {
116 FILE *f = psTraceGetDestination ();
117 fprintf (f, "VectorFitPolynomial1D()\n");
118 for (int i = 0; i < x->n; i++) {
119 fprintf (f, "(x, y, yErr) is (%f, %f, %f)\n", x->data.F64[i], y->data.F64[i], yErr->data.F64[i]);
120 }
121 }
122# endif
123
124 nTerm = myPoly->n + 1;
125 A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64);
126 B = psVectorAlloc(nTerm, PS_TYPE_F64);
127
128 // Initialize data structures (why is this not a function!)
129 for (int i = 0; i < nTerm; i++) {
130 B->data.F64[i] = 0.0;
131 for (int j = 0; j < nTerm; j++) {
132 A->data.F64[i][j] = 0.0;
133 }
134 }
135
136 // xSums look like: 1, x, x^2, ... x^(2n+1)
137
138 // Build the B and A data structs.
139 for (int k = 0; k < x->n; k++) {
140 if ((mask != NULL) && mask->data.U8[k]) continue;
141 xSums = BuildSums1D(xSums, x->data.F64[k], nTerm);
142
143 if (yErr == NULL) {
144 wt = 1.0;
145 } else {
146 // this should probably by yErr^2 !!
147 // this should filter yErr == 0 values
148 wt = 1.0 / PS_SQR(yErr->data.F64[k]);
149 }
150 for (int i = 0; i < nTerm; i++) {
151 B->data.F64[i] += y->data.F64[k] * xSums->data.F64[i] * wt;
152 }
153
154 // we could skip half of the array and assign at the end
155 // we must handle masked orders
156 for (int i = 0; i < nTerm; i++) {
157 for (int j = 0; j < nTerm; j++) {
158 A->data.F64[i][j] += xSums->data.F64[i + j] * wt;
159 }
160 }
161 }
162
163 // GaussJordan version
164 if (0) {
165 // does the solution in place
166 psGaussJordan (A, B);
167
168 // the first nTerm entries in B correspond directly to the desired
169 // polynomial coefficients. this is only true for the 1D case
170 for (int k = 0; k < nTerm; k++) {
171 myPoly->coeff[k] = B->data.F64[k];
172 }
173 }
174 else
175 // LUD version of the fit
176 {
177 psImage *ALUD = NULL;
178 psVector* outPerm = NULL;
179 psVector* coeffs = NULL;
180
181 ALUD = psImageAlloc(nTerm, nTerm, PS_TYPE_F64);
182 ALUD = psMatrixLUD(ALUD, &outPerm, A);
183 coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
184 for (int k = 0; k < nTerm; k++) {
185 myPoly->coeff[k] = coeffs->data.F64[k];
186 }
187 }
188
189 psFree(A);
190 psFree(B);
191 psFree(xSums);
192
193 psTrace(".psLib.dataManip.VectorFitPolynomial1DOrd", 4,
194 "---- VectorFitPolynomial1DOrd() begin ----\n");
195 return (myPoly);
196}
197
198// ********************** 2D polynomial functions ******************
199
200// XXX EAM : this version uses myPoly->nX as Norder, not Nterms
201psVector *Polynomial2DEvalVector(const psPolynomial2D *myPoly,
202 const psVector *x,
203 const psVector *y)
204
205{
206 PS_POLY_CHECK_NULL(myPoly, NULL);
207 PS_VECTOR_CHECK_NULL(x, NULL);
208 PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NULL);
209 PS_VECTOR_CHECK_NULL(y, NULL);
210 PS_VECTOR_CHECK_TYPE(y, PS_TYPE_F32, NULL);
211
212 psVector *tmp;
213 psS32 vecLen=x->n;
214
215 // Determine the length of the output vector to by the minimum of the x,y vectors
216 if (y->n < vecLen) {
217 vecLen = y->n;
218 }
219
220 // Create output vector to return
221 tmp = psVectorAlloc(vecLen, PS_TYPE_F32);
222
223 // Evaluate the polynomial at the specified points
224 for (psS32 i=0; i<vecLen; i++) {
225 tmp->data.F32[i] = Polynomial2DEval(myPoly,x->data.F32[i],y->data.F32[i]);
226 }
227
228 // Return output vector
229 return(tmp);
230}
231
232// XXX EAM : this version uses the F64 vectors
233psVector *Polynomial2DEvalVectorD(const psPolynomial2D *myPoly,
234 const psVector *x,
235 const psVector *y)
236
237{
238 PS_POLY_CHECK_NULL(myPoly, NULL);
239 PS_VECTOR_CHECK_NULL(x, NULL);
240 PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F64, NULL);
241 PS_VECTOR_CHECK_NULL(y, NULL);
242 PS_VECTOR_CHECK_TYPE(y, PS_TYPE_F64, NULL);
243
244 psVector *tmp;
245 psS32 vecLen=x->n;
246
247 // Determine the length of the output vector to by the minimum of the x,y vectors
248 if (y->n < vecLen) {
249 vecLen = y->n;
250 }
251
252 // Create output vector to return
253 tmp = psVectorAlloc(vecLen, PS_TYPE_F64);
254
255 // Evaluate the polynomial at the specified points
256 for (psS32 i=0; i<vecLen; i++) {
257 tmp->data.F64[i] = Polynomial2DEval(myPoly,x->data.F64[i],y->data.F64[i]);
258 }
259
260 // Return output vector
261 return(tmp);
262}
263
264// XXX EAM : use Nterm = Norder + 1 definition
265// the user requests a polynomial of order Norder
266psPolynomial2D* Polynomial2DAlloc(psS32 nXorder, psS32 nYorder,
267 psPolynomialType type)
268{
269 PS_INT_CHECK_NON_NEGATIVE(nXorder, NULL);
270 PS_INT_CHECK_NON_NEGATIVE(nYorder, NULL);
271
272 psS32 x = 0;
273 psS32 y = 0;
274 psS32 nXterm = nXorder + 1;
275 psS32 nYterm = nYorder + 1;
276 psPolynomial2D* newPoly = NULL;
277
278 newPoly = (psPolynomial2D* ) psAlloc(sizeof(psPolynomial2D));
279 // p_psMemSetDeallocator(newPoly, (psFreeFcn) polynomial2DFree);
280 // XXX EAM : me, being lazy
281
282 newPoly->type = type;
283 newPoly->nX = nXorder;
284 newPoly->nY = nYorder;
285
286 newPoly->coeff = (psF32 **)psAlloc(nXterm * sizeof(psF32 *));
287 newPoly->coeffErr = (psF32 **)psAlloc(nXterm * sizeof(psF32 *));
288 newPoly->mask = (psU8 **)psAlloc(nXterm * sizeof(psU8 *));
289 for (x = 0; x < nXterm; x++) {
290 newPoly->coeff[x] = (psF32 *)psAlloc(nYterm * sizeof(psF32));
291 newPoly->coeffErr[x] = (psF32 *)psAlloc(nYterm * sizeof(psF32));
292 newPoly->mask[x] = (psU8 *)psAlloc(nYterm * sizeof(psU8));
293 }
294 for (x = 0; x < nXterm; x++) {
295 for (y = 0; y < nYterm; y++) {
296 newPoly->coeff[x][y] = 0.0;
297 newPoly->coeffErr[x][y] = 0.0;
298 newPoly->mask[x][y] = 0;
299 }
300 }
301 return(newPoly);
302}
303
304// XXX EAM : BuildSums2D in analogy with BuildSums1D
305static psImage *BuildSums2D(psImage* sums,
306 psF64 x, psF64 y,
307 psS32 nXterm, psS32 nYterm)
308{
309 psS32 nXsum = 0;
310 psS32 nYsum = 0;
311 psF64 xSum = 1.0;
312 psF64 ySum = 1.0;
313
314 nXsum = 2*nXterm;
315 nYsum = 2*nYterm;
316 if (sums == NULL) {
317 sums = psImageAlloc(nXsum, nYsum, PS_TYPE_F64);
318 }
319 if ((nXsum != sums->numCols) || (nYsum != sums->numRows)) {
320 psFree (sums);
321 sums = psImageAlloc(nXsum, nYsum, PS_TYPE_F64);
322 }
323
324 ySum = 1.0;
325 for (int j = 0; j < nYsum; j++) {
326 xSum = ySum;
327 for (int i = 0; i < nXsum; i++) {
328 sums->data.F64[i][j] = xSum;
329 xSum *= x;
330 }
331 ySum *= y;
332 }
333 return (sums);
334}
335
336// XXX EAM : test version of 2d fitting
337psPolynomial2D* VectorFitPolynomial2DOrd_EAM(psPolynomial2D* myPoly,
338 psVector* mask,
339 const psVector* x,
340 const psVector* y,
341 const psVector* z,
342 const psVector* zErr)
343{
344 // I think this is 1 dimension down
345 psImage* A = NULL;
346 psVector* B = NULL;
347 psImage* Sums = NULL;
348 psF64 wt;
349 psS32 nTerm, nXterm, nYterm;
350
351 nXterm = myPoly->nX + 1;
352 nYterm = myPoly->nY + 1;
353 nTerm = nXterm * nYterm;
354
355 A = psImageAlloc(nTerm, nTerm, PS_TYPE_F64);
356 B = psVectorAlloc(nTerm, PS_TYPE_F64);
357
358 // Initialize data structures (why is this not a function!)
359 for (int i = 0; i < nTerm; i++) {
360 B->data.F64[i] = 0.0;
361 for (int j = 0; j < nTerm; j++) {
362 A->data.F64[i][j] = 0.0;
363 }
364 }
365
366 // Sums look like: 1, x, x^2, ... x^(2n+1), y, xy, x^2y, ... x^(2n+1)
367
368 // Build the B and A data structs.
369 for (int k = 0; k < x->n; k++) {
370 if ((mask != NULL) && mask->data.U8[k]) continue;
371 Sums = BuildSums2D(Sums, x->data.F64[k], y->data.F64[k], nXterm, nYterm);
372
373 if (zErr == NULL) {
374 wt = 1.0;
375 } else {
376 // this should probably by zErr^2 !!
377 // this should filter zErr == 0 values
378 wt = 1.0 / zErr->data.F64[k];
379 }
380
381 // we could skip half of the array and assign at the end
382 // we must handle masked orders
383 for (int n = 0; n < nXterm; n++) {
384 for (int m = 0; m < nYterm; m++) {
385 B->data.F64[n+m*nXterm] += z->data.F64[k] * Sums->data.F64[n][m] * wt;
386 }
387 }
388
389 for (int i = 0; i < nXterm; i++) {
390 for (int j = 0; j < nYterm; j++) {
391 for (int n = 0; n < nXterm; n++) {
392 for (int m = 0; m < nYterm; m++) {
393 A->data.F64[i+j*nXterm][n+m*nXterm] += Sums->data.F64[i+n][j+m] * wt;
394 }
395 }
396 }
397 }
398 }
399
400 // does the solution in place
401 psGaussJordan (A, B);
402
403 // XXX: How do we know if these routines were successful?
404 // ALUD = psMatrixLUD(ALUD, &outPerm, A);
405 // coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
406
407 for (int n = 0; n < nXterm; n++) {
408 for (int m = 0; m < nYterm; m++) {
409 myPoly->coeff[n][m] = B->data.F64[n+m*nXterm];
410 }
411 }
412
413 psFree(A);
414 psFree(B);
415 psFree(Sums);
416
417 psTrace(".psLib.dataManip.VectorFitPolynomial2DOrd", 4,
418 "---- VectorFitPolynomial2DOrd() begin ----\n");
419 return (myPoly);
420}
421
422// write out the terms of the given 2D polynomial
423void psPolynomial2DDump (psPolynomial2D *poly) {
424
425 for (int i = 0; i < poly->nX + 1; i++) {
426 for (int j = 0; j < poly->nY + 1; j++) {
427 fprintf (stderr, "x^%d y^%d : %g +/- %g\n", i, j, poly->coeff[i][j], poly->coeffErr[i][j]);
428 }
429 }
430}
431
432psPolynomial2D* RobustFit2D_nomask(psPolynomial2D* poly,
433 const psVector* x,
434 const psVector* y,
435 const psVector* z,
436 const psVector* dz)
437{
438 psVector *X;
439 psVector *Y;
440 psVector *Z;
441 psVector *dZ;
442
443 psVector *zFit = NULL;
444 psVector *zResid = NULL;
445 psStats *stats = NULL;
446
447 X = psVectorCopy (NULL, x, PS_TYPE_F64);
448 Y = psVectorCopy (NULL, y, PS_TYPE_F64);
449 Z = psVectorCopy (NULL, z, PS_TYPE_F64);
450 dZ = psVectorCopy (NULL, dz, PS_TYPE_F64);
451
452 for (int N = 0; N < 3; N++) {
453 // XXX EAM : this would be better defined with an element mask
454 poly = VectorFitPolynomial2DOrd_EAM (poly, NULL, X, Y, Z, dZ);
455 zFit = Polynomial2DEvalVectorD (poly, x, y);
456 zResid = (psVector *) psBinaryOp (NULL, (void *) z, "-", (void *) zFit);
457
458 stats = psStatsAlloc (PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV);
459 stats = psVectorStats (stats, zResid, NULL, NULL, 0);
460 psTrace (".psphot.RobustFit", 4, "residual stats for robust fit: %g +/- %g (%d pts)\n", stats->clippedMean, stats->clippedStdev, stats->clippedNvalues);
461
462 // re-create X, Y, Z, dZ if pts are valid
463 int n = 0;
464 for (int i = 0; i < zResid->n; i++) {
465 if (fabs(zResid->data.F64[i] - stats->clippedMean) > 3*stats->clippedStdev) {
466 continue;
467 }
468 X->data.F64[n] = x->data.F64[i];
469 Y->data.F64[n] = y->data.F64[i];
470 Z->data.F64[n] = z->data.F64[i];
471 dZ->data.F64[n] = dz->data.F64[i];
472 n++;
473 }
474 X->n = n;
475 Y->n = n;
476 Z->n = n;
477 dZ->n = n;
478 }
479 return (poly);
480}
481
482// XXX EAM : be careful here with F32 vs F64 vectors
483psPolynomial2D* RobustFit2D(psPolynomial2D* poly,
484 psVector* mask,
485 const psVector* x,
486 const psVector* y,
487 const psVector* z,
488 const psVector* dz)
489{
490 PS_VECTOR_CHECK_NULL(mask, NULL);
491 PS_VECTOR_CHECK_NULL(x, NULL);
492 PS_VECTOR_CHECK_NULL(y, NULL);
493 PS_VECTOR_CHECK_NULL(z, NULL);
494 PS_VECTOR_CHECK_NULL(dz, NULL);
495
496 psVector *zFit = NULL;
497 psVector *zResid = psVectorAlloc (x->n, PS_TYPE_F64);
498 psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV);
499
500 for (int N = 0; N < 3; N++) {
501 poly = VectorFitPolynomial2DOrd_EAM (poly, mask, x, y, z, dz);
502 zFit = Polynomial2DEvalVectorD (poly, x, y);
503 zResid = (psVector *) psBinaryOp (zResid, (void *) z, "-", (void *) zFit);
504
505 stats = psVectorStats (stats, zResid, NULL, mask, 1);
506 psTrace (".psphot.RobustFit", 4, "residual stats for robust fit: %g +/- %g\n",
507 stats->sampleMean, stats->sampleStdev);
508
509 // set mask if pts are not valid
510 // we are masking out any point which is out of range
511 // recovery is not allowed with this scheme
512 for (int i = 0; i < zResid->n; i++) {
513 if (mask->data.U8[i]) continue;
514 if (fabs(zResid->data.F64[i] - stats->sampleMean) > 3*stats->sampleStdev) {
515 mask->data.U8[i] = 1;
516 continue;
517 }
518 }
519 psFree (zFit);
520 }
521 psFree (zResid);
522 psFree (stats);
523 return (poly);
524}
525
526// XXX EAM : VectorFitPolynomial2DOrd and Polynomial2DEvalVector require different types (F32 vs F64)
527
528# if (0) // moved to psLib
529// XXX EAM : this version uses myPoly->nX as Norder, not Nterms
530psF32 Polynomial2DEval(const psPolynomial2D* myPoly,
531 psF32 x,
532 psF32 y)
533{
534 PS_POLY_CHECK_NULL(myPoly, NAN);
535
536 psS32 loop_x = 0;
537 psS32 loop_y = 0;
538 psF32 polySum = 0.0;
539 psF32 xSum = 1.0;
540 psF32 ySum = 1.0;
541
542 // XXX EAM : nX is order, not nTerms
543 for (loop_x = 0; loop_x < myPoly->nX + 1; loop_x++) {
544 ySum = xSum;
545 // XXX EAM : nX is order, not nTerms
546 for (loop_y = 0; loop_y < myPoly->nY + 1; loop_y++) {
547 if (myPoly->mask[loop_x][loop_y] == 0) {
548 polySum += ySum * myPoly->coeff[loop_x][loop_y];
549 }
550 ySum *= y;
551 }
552 xSum *= x;
553 }
554
555 return(polySum);
556}
557# endif
558