Changeset 5175 for trunk/psLib/src/math/psMinimize.c
- Timestamp:
- Sep 28, 2005, 4:13:54 PM (21 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/math/psMinimize.c (modified) (15 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/math/psMinimize.c
r5113 r5175 10 10 * @author EAM, IfA 11 11 * 12 * @version $Revision: 1.14 0$ $Name: not supported by cvs2svn $13 * @date $Date: 2005-09-2 3 23:01:30$12 * @version $Revision: 1.141 $ $Name: not supported by cvs2svn $ 13 * @date $Date: 2005-09-29 02:13:54 $ 14 14 * 15 15 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii 16 16 * 17 17 * XXX: must follow coding name standards on local functions. 18 * 18 * XXX: put local functions in front. 19 * 19 20 */ 20 21 /*****************************************************************************/ … … 33 34 /*****************************************************************************/ 34 35 /* DEFINE STATEMENTS */ 35 /* What are the following macros for? */36 36 /*****************************************************************************/ 37 #define PS_SEG psLib 38 #define PS_PWD dataManip 39 #define PS_FILE psMinimize 37 40 38 /*****************************************************************************/ 41 39 /* TYPE DEFINITIONS */ … … 44 42 /*****************************************************************************/ 45 43 /* GLOBAL VARIABLES */ 44 /* XXX: Do these conform to code standard? */ 46 45 /*****************************************************************************/ 47 46 static psMinimizeChi2PowellFunc Chi2PowellFunc = NULL; 48 47 static psVector *myValue; 49 48 static psVector *myError; 50 51 49 /*****************************************************************************/ 52 50 /* FILE STATIC VARIABLES */ … … 64 62 ****************************************************************************** 65 63 *****************************************************************************/ 66 // measure the distance to the minimum assuming a linear model 67 // XXX: Move this to the pub area. 68 bool psMinimizeGaussNewtonDelta (psVector *delta, 69 const psVector *params, 70 const psVector *paramMask, 71 const psArray *x, 72 const psVector *y, 73 const psVector *yErr, 74 psMinimizeLMChi2Func func) 64 // XXX EAM : can we use static copies of LUv, LUm, A? 65 psBool p_psMinLM_GuessABP( 66 psImage *Alpha, 67 psVector *Beta, 68 psVector *Params, 69 const psImage *alpha, 70 const psVector *beta, 71 const psVector *params, 72 const psVector *paramMask, 73 const psVector *beta_lim, 74 const psVector *params_min, 75 const psVector *params_max, 76 psF64 lambda) 77 { 78 # define USE_LU_DECOMP 1 79 # if (USE_LU_DECOMP) 80 psVector *LUv = NULL; 81 psImage *LUm = NULL; 82 psImage *A = NULL; 83 psF32 det; 84 85 // LU decomposition version 86 psTrace(__func__, 5, "using LUD version\n"); 87 88 // set new guess values (creates matrix A) 89 A = psImageCopy(NULL, alpha, PS_TYPE_F64); 90 for (int j = 0; j < params->n; j++) { 91 if ((paramMask != NULL) && (paramMask->data.U8[j])) 92 continue; 93 A->data.F64[j][j] = alpha->data.F64[j][j] * (1.0 + lambda); 94 } 95 96 // solve A*beta = Beta (Alpha = 1/A) 97 // these operations do not modify the input values (creates LUm, LUv) 98 LUm = psMatrixLUD(NULL, &LUv, A); 99 Beta = psMatrixLUSolve(Beta, LUm, beta, LUv); 100 Alpha = psMatrixInvert(Alpha, A, &det); 101 102 # else 103 // gauss-jordan version 104 psTrace(__func__, 5, "using Gauss-J version"); 105 106 // set new guess values (creates matrix A) 107 Beta = psVectorCopy(Beta, beta, PS_TYPE_F64); 108 Alpha = psImageCopy(Alpha, alpha, PS_TYPE_F64); 109 for (int j = 0; j < params->n; j++) { 110 if ((paramMask != NULL) && (paramMask->data.U8[j])) 111 continue; 112 Alpha->data.F64[j][j] = alpha->data.F64[j][j] * (1.0 + lambda); 113 } 114 115 psGaussJordan(Alpha, Beta); 116 psFree(A); 117 psFree(LUm); 118 psFree(LUv); 119 # endif 120 121 // apply Beta to get new Params values 122 for (int j = 0; j < params->n; j++) { 123 if ((paramMask != NULL) && (paramMask->data.U8[j])) 124 continue; 125 // Params->data.F32[j] = params->data.F32[j] - Beta->data.F64[j]; 126 // compare Beta to beta limits 127 if (beta_lim != NULL) { 128 if (fabs(Beta->data.F64[j]) > fabs(beta_lim->data.F32[j])) { 129 Beta->data.F64[j] = (Beta->data.F64[j] > 0) ? fabs(beta_lim->data.F32[j]) : -fabs(beta_lim->data.F32[j]); 130 } 131 } 132 Params->data.F32[j] = params->data.F32[j] - Beta->data.F64[j]; 133 // compare new params to param limits 134 if (params_max != NULL) { 135 Params->data.F32[j] = PS_MIN (Params->data.F32[j], params_max->data.F32[j]); 136 } 137 if (params_min != NULL) { 138 Params->data.F32[j] = PS_MAX (Params->data.F32[j], params_min->data.F32[j]); 139 } 140 } 141 # if (USE_LU_DECOMP) 142 psFree(A); 143 psFree(LUm); 144 psFree(LUv); 145 # endif 146 147 return(true); 148 } 149 150 151 bool psMinimizeGaussNewtonDelta( 152 psVector *delta, 153 const psVector *params, 154 const psVector *paramMask, 155 const psArray *x, 156 const psVector *y, 157 const psVector *yWt, 158 psMinimizeLMChi2Func func) 75 159 { 76 160 77 161 // allocate internal arrays (current vs Guess) 78 psImage *alpha = psImageAlloc (params->n, params->n, PS_TYPE_F64);79 psImage *Alpha = psImageAlloc (params->n, params->n, PS_TYPE_F64);80 psVector *beta = psVectorAlloc (params->n, PS_TYPE_F64);81 psVector *Params = psVectorAlloc (params->n, PS_TYPE_F64);82 psVector *dy = psVectorAlloc (y->n, PS_TYPE_F32);162 psImage *alpha = psImageAlloc (params->n, params->n, PS_TYPE_F64); 163 psImage *Alpha = psImageAlloc (params->n, params->n, PS_TYPE_F64); 164 psVector *beta = psVectorAlloc(params->n, PS_TYPE_F64); 165 psVector *Params = psVectorAlloc(params->n, PS_TYPE_F64); 166 psVector *dy = NULL; 83 167 84 168 // the user provides the error or NULL. we need to convert 85 169 // to appropriate weights 86 if (yErr != NULL) { 87 for (int i = 0; i < dy->n; i++) { 88 dy->data.F32[i] = 1.0 / PS_SQR (yErr->data.F32[i]); 89 } 170 if (yWt != NULL) { 171 dy = (psVector *) yWt; 90 172 } else { 91 for (int i = 0; i < dy->n; i++) { 92 dy->data.F32[i] = 1.0; 93 } 94 } 95 96 p_psMinLM_SetABX (alpha, beta, params, paramMask, x, y, dy, func); 97 p_psMinLM_GuessABP (Alpha, delta, Params, alpha, beta, params, paramMask, 0.0); 98 99 psFree (alpha); 100 psFree (Alpha); 101 psFree (beta); 102 psFree (Params); 103 psFree (dy); 173 dy = psVectorAlloc(y->n, PS_TYPE_F32); 174 psVectorInit(dy, 1.0); 175 } 176 177 p_psMinLM_SetABX(alpha, beta, params, paramMask, x, y, dy, func); 178 p_psMinLM_GuessABP(Alpha, delta, Params, alpha, beta, params, paramMask, NULL, NULL, NULL, 0.0); 179 180 psFree(alpha); 181 psFree(Alpha); 182 psFree(beta); 183 psFree(Params); 184 if (yWt == NULL) { 185 psFree(dy); 186 } 104 187 return (true); 105 188 } 106 189 107 108 190 // measure linear model prediction 109 psF64 p_psMinLM_dLinear (const psVector *Beta, const psVector *beta, psF64 lambda) 191 psF64 p_psMinLM_dLinear( 192 const psVector *Beta, 193 const psVector *beta, 194 psF64 lambda) 110 195 { 111 196 … … 117 202 dLinear += lambda*PS_SQR(B[i]) + B[i]*b[i]; 118 203 } 119 return (0.5*dLinear); 120 } 204 return(0.5*dLinear); 205 } 206 207 // XXX EAM: this needs to respect the mask on params 208 // alpha, beta, params are already allocated 209 psF64 p_psMinLM_SetABX( 210 psImage *alpha, 211 psVector *beta, 212 const psVector *params, 213 const psVector *paramMask, 214 const psArray *x, 215 const psVector *y, 216 const psVector *dy, 217 psMinimizeLMChi2Func func) 218 { 219 PS_ASSERT_IMAGE_NON_NULL(alpha, NAN); 220 PS_ASSERT_VECTOR_NON_NULL(beta, NAN); 221 PS_ASSERT_VECTOR_NON_NULL(params, NAN); 222 PS_ASSERT_PTR_NON_NULL(x, NAN); 223 PS_ASSERT_VECTOR_NON_NULL(y, NAN); 224 PS_ASSERT_VECTOR_NON_NULL(dy, NAN); 225 226 psF64 chisq; 227 psF64 delta; 228 psF64 weight; 229 psF64 ymodel; 230 psVector *deriv = psVectorAlloc(params->n, PS_TYPE_F32); 231 232 // zero alpha and beta for summing below 233 for (int j = 0; j < params->n; j++) { 234 for (int k = 0; k < params->n; k++) { 235 alpha->data.F64[j][k] = 0; 236 } 237 beta->data.F64[j] = 0; 238 } 239 chisq = 0.0; 240 241 // calculate chisq, alpha, beta 242 for (int i = 0; i < y->n; i++) { 243 ymodel = func(deriv, params, (psVector *) x->data[i]); 244 245 delta = ymodel - y->data.F32[i]; 246 chisq += PS_SQR(delta) * dy->data.F32[i]; 247 248 for (int j = 0; j < params->n; j++) { 249 if ((paramMask != NULL) && (paramMask->data.U8[j])) 250 continue; 251 weight = deriv->data.F32[j] * dy->data.F32[i]; 252 for (int k = 0; k <= j; k++) { 253 if ((paramMask != NULL) && (paramMask->data.U8[k])) 254 continue; 255 alpha->data.F64[j][k] += weight * deriv->data.F32[k]; 256 } 257 beta->data.F64[j] += weight * delta; 258 } 259 } 260 261 // calculate lower-left half of alpha 262 for (int j = 1; j < params->n; j++) { 263 for (int k = 0; k < j; k++) { 264 alpha->data.F64[k][j] = alpha->data.F64[j][k]; 265 } 266 } 267 268 // fill in pivots if we apply a mask 269 if (paramMask != NULL) { 270 for (int j = 0; j < params->n; j++) { 271 if (paramMask->data.U8[j]) { 272 alpha->data.F64[j][j] = 1; 273 beta->data.F64[j] = 1; 274 } 275 } 276 } 277 278 psFree(deriv); 279 return(chisq); 280 } 281 121 282 122 283 /****************************************************************************** 123 psMinimizeLMChi2(): This routine will take an procedure which calculates 124 an arbitrary function and it's derivative and minimize the chi-squared match 125 between that function at the specified coords and the specified value at 126 those coords. 284 psMinimizeLMChi2(): This routine will take an procedure which calculates an 285 arbitrary function and it's derivative and minimize the chi-squared match 286 between that function at the specified coords and the specified value at those 287 coords. 288 289 XXX: Put the ASSERTS in. 127 290 128 291 XXX EAM this is my re-implementation of MinLM … … 135 298 XXX: Change the whole thing to F64, if input data is F32, convert it. 136 299 *****************************************************************************/ 137 psBool psMinimizeLMChi2(psMinimization *min, 138 psImage *covar, 139 psVector *params, 140 const psVector *paramMask, 141 const psArray *x, 142 const psVector *y, 143 const psVector *yErr, 144 psMinimizeLMChi2Func func) 145 { 300 psBool psMinimizeLMChi2( 301 psMinimization *min, 302 psImage *covar, 303 psVector *params, 304 const psVector *paramMask, 305 const psArray *x, 306 const psVector *y, 307 const psVector *yWt, 308 psMinimizeLMChi2Func func) 309 { 310 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 146 311 PS_ASSERT_PTR_NON_NULL(min, false); 312 // XXX: If covar not NULL, do asserts... 147 313 PS_ASSERT_VECTOR_NON_NULL(params, false); 148 314 PS_ASSERT_VECTOR_NON_EMPTY(params, false); … … 162 328 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F32, false); 163 329 PS_ASSERT_VECTORS_SIZE_EQUAL(x, y, false); 164 if (y Err!= NULL) {165 PS_ASSERT_VECTOR_TYPE(y Err, PS_TYPE_F32, false);166 PS_ASSERT_VECTORS_SIZE_EQUAL(y, y Err, false);330 if (yWt != NULL) { 331 PS_ASSERT_VECTOR_TYPE(yWt, PS_TYPE_F32, false); 332 PS_ASSERT_VECTORS_SIZE_EQUAL(y, yWt, false); 167 333 } 168 334 PS_ASSERT_PTR_NON_NULL(func, false); … … 173 339 174 340 // allocate internal arrays (current vs Guess) 175 psImage *alpha = psImageAlloc (params->n, params->n, PS_TYPE_F64);176 psImage *Alpha = psImageAlloc (params->n, params->n, PS_TYPE_F64);177 psVector *beta = psVectorAlloc (params->n, PS_TYPE_F64);178 psVector *Beta = psVectorAlloc (params->n, PS_TYPE_F64);179 psVector *Params = psVectorAlloc (params->n, PS_TYPE_F32);341 psImage *alpha = psImageAlloc(params->n, params->n, PS_TYPE_F64); 342 psImage *Alpha = psImageAlloc(params->n, params->n, PS_TYPE_F64); 343 psVector *beta = psVectorAlloc(params->n, PS_TYPE_F64); 344 psVector *Beta = psVectorAlloc(params->n, PS_TYPE_F64); 345 psVector *Params = psVectorAlloc(params->n, PS_TYPE_F32); 180 346 psVector *dy = NULL; 181 347 psF64 Chisq = 0.0; 182 348 psF64 lambda = 0.001; 183 184 // XXX EAM: why is this needed here? the value is not used, and the memory 185 // is allocated above. However, if I drop it, I get weird answers or 186 // crashes. 187 Params = psVectorCopy (Params, params, PS_TYPE_F32); 349 // XXX: Code this properly. Don't use mustFree00. 350 psBool mustFree00 = false; 351 psVector *beta_lim = NULL; 352 psVector *param_min = NULL; 353 psVector *param_max = NULL; 354 355 // if we are provided a covar image, we expect to find these three vectors in first three rows 356 if (covar != NULL) { 357 mustFree00 = true; 358 beta_lim = psVectorAlloc(params->n, PS_TYPE_F32); 359 param_min = psVectorAlloc(params->n, PS_TYPE_F32); 360 param_max = psVectorAlloc(params->n, PS_TYPE_F32); 361 for (int i = 0; i < params->n; i++) { 362 beta_lim->data.F32[i] = covar->data.F64[0][i]; 363 param_min->data.F32[i] = covar->data.F64[1][i]; 364 param_max->data.F32[i] = covar->data.F64[2][i]; 365 } 366 psImageRecycle(covar, params->n, params->n, PS_TYPE_F64); 367 } 368 369 // why is this needed here??? the initial guess on params is provided by the user 370 Params = psVectorCopy(Params, params, PS_TYPE_F32); 188 371 189 372 // the user provides the error or NULL. we need to convert 190 373 // to appropriate weights 191 dy = psVectorAlloc (y->n, PS_TYPE_F32); 192 if (yErr != NULL) { 193 for (int i = 0; i < dy->n; i++) { 194 dy->data.F32[i] = 1.0 / PS_SQR (yErr->data.F32[i]); 195 } 374 if (yWt != NULL) { 375 dy = (psVector *) yWt; 196 376 } else { 197 for (int i = 0; i < dy->n; i++) { 198 dy->data.F32[i] = 1.0; 199 } 377 dy = psVectorAlloc(y->n, PS_TYPE_F32); 378 psVectorInit(dy, 1.0); 200 379 } 201 380 202 381 // calculate initial alpha and beta, set chisq (min->value) 203 min->value = p_psMinLM_SetABX (alpha, beta, params, paramMask, x, y, dy, func); 204 # ifndef PS_NO_TRACE 382 min->value = p_psMinLM_SetABX(alpha, beta, params, paramMask, x, y, dy, func); 383 if (isnan(min->value)) { 384 min->iter = min->maxIter; 385 return(false); 386 } 205 387 // dump some useful info if trace is defined 206 /* XXX: This code is seg faulting. 207 if (psTraceGetLevel (".psLib.dataManip.psMinimizeLMChi2") >= 5) { 208 p_psImagePrint (psTraceGetDestination(), alpha, "alpha guess"); 209 p_psVectorPrint (psTraceGetDestination(), beta, "beta guess"); 210 p_psVectorPrint (psTraceGetDestination(), params, "params guess"); 211 } 212 if (psTraceGetLevel (".psLib.dataManip.psMinimizeLMChi2") >= 4) { 213 // XXX: Where is this? 214 // p_psVectorPrintRow (psTraceGetDestination(), Params, "params guess"); 215 } 216 */ 217 # endif /* PS_NO_TRACE */ 218 219 min->lastDelta = min->tol + 1.0; 388 if (psTraceGetLevel(__func__) >= 6) { 389 p_psImagePrint(psTraceGetDestination(), alpha, "alpha guess (0)"); 390 p_psVectorPrint(psTraceGetDestination(), beta, "beta guess (0)"); 391 p_psVectorPrint(psTraceGetDestination(), params, "params guess (0)"); 392 } 393 if (psTraceGetLevel (__func__) >= 6) { 394 //XXX: p_psVectorPrintRow(psTraceGetDestination(), Params, "params guess"); 395 } 396 220 397 // iterate until the tolerance is reached, or give up 221 while ((min->lastDelta > min->tol) && (min->iter < min->maxIter)) { 398 while ((min->iter < min->maxIter) && ((min->lastDelta > min->tol) || !isfinite(min->lastDelta))) { 399 psTrace(__func__, 5, "Iteration number %d. (max iterations is %d).\n", min->iter, min->maxIter); 400 psTrace(__func__, 5, "Last delta is %f. Min->tol is %f.\n", min->lastDelta, min->tol); 401 222 402 // set a new guess for Alpha, Beta, Params 223 p_psMinLM_GuessABP (Alpha, Beta, Params, alpha, beta, params, paramMask, lambda); 403 p_psMinLM_GuessABP(Alpha, Beta, Params, alpha, beta, params, paramMask, 404 beta_lim, param_min, param_max, lambda); 224 405 225 406 // measure linear model prediction 226 psF64 dLinear = p_psMinLM_dLinear (Beta, beta, lambda); 227 228 # ifndef PS_NO_TRACE 407 psF64 dLinear = p_psMinLM_dLinear(Beta, beta, lambda); 408 229 409 // dump some useful info if trace is defined 230 /* XXX: This code is seg faulting. 231 if (psTraceGetLevel (".psLib.dataManip.psMinimizeLMChi2") >= 5) { 232 p_psImagePrint (psTraceGetDestination(), Alpha, "alpha guess"); 233 p_psVectorPrint (psTraceGetDestination(), Beta, "beta guess"); 234 p_psVectorPrint (psTraceGetDestination(), Params, "params guess"); 235 } 236 if (psTraceGetLevel (".psLib.dataManip.psMinimizeLMChi2") >= 4) { 237 // XXX: Where is this? 238 // p_psVectorPrintRow (psTraceGetDestination(), Params, "params guess"); 239 } 240 */ 241 # endif /* PS_NO_TRACE */ 410 if (psTraceGetLevel(__func__) >= 6) { 411 p_psImagePrint(psTraceGetDestination(), Alpha, "alpha guess (1)"); 412 p_psVectorPrint(psTraceGetDestination(), Beta, "beta guess (1)"); 413 p_psVectorPrint(psTraceGetDestination(), Params, "params guess (1)"); 414 } 415 if (psTraceGetLevel(__func__) >= 6) { 416 //XXX: p_psVectorPrintRow(psTraceGetDestination(), Params, "params guess"); 417 } 242 418 243 419 // calculate Chisq for new guess, update Alpha & Beta 244 Chisq = p_psMinLM_SetABX (Alpha, Beta, Params, paramMask, x, y, dy, func);420 Chisq = p_psMinLM_SetABX(Alpha, Beta, Params, paramMask, x, y, dy, func); 245 421 246 422 // XXX EAM alternate convergence criterion: … … 250 426 psF64 rho = (min->value - Chisq) / dLinear; 251 427 252 psTrace (".psLib.dataManip.psMinimizeLMChi2", 4, "last chisq: %f, new chisq %f, delta: %f, rho: %f\n", min->value, Chisq, min->lastDelta, rho); 253 # ifndef PS_NO_TRACE 428 psTrace(__func__, 5, "last chisq: %f, new chisq %f, delta: %f, rho: %f\n", min->value, 429 Chisq, min->lastDelta, rho); 430 254 431 // dump some useful info if trace is defined 255 /* XXX: This code is seg faulting. 256 if (psTraceGetLevel (".psLib.dataManip.psMinimizeLMChi2") >= 5) { 257 p_psImagePrint (psTraceGetDestination(), Alpha, "alpha guess"); 258 p_psVectorPrint (psTraceGetDestination(), Beta, "beta guess"); 259 p_psVectorPrint (psTraceGetDestination(), Params, "params guess"); 260 } 261 */ 262 # endif /* PS_NO_TRACE */ 432 if (psTraceGetLevel(__func__) >= 6) { 433 p_psImagePrint(psTraceGetDestination(), Alpha, "alpha guess (2)"); 434 p_psVectorPrint(psTraceGetDestination(), Beta, "beta guess (2)"); 435 p_psVectorPrint(psTraceGetDestination(), Params, "params guess (2)"); 436 } 263 437 264 438 /* if (Chisq < min->value) { */ … … 266 440 min->lastDelta = (min->value - Chisq) / (dy->n - params->n); 267 441 min->value = Chisq; 268 alpha = psImageCopy (alpha, Alpha, PS_TYPE_F64);269 beta = psVectorCopy (beta, Beta, PS_TYPE_F64);270 params = psVectorCopy (params, Params, PS_TYPE_F32);442 alpha = psImageCopy(alpha, Alpha, PS_TYPE_F64); 443 beta = psVectorCopy(beta, Beta, PS_TYPE_F64); 444 params = psVectorCopy(params, Params, PS_TYPE_F32); 271 445 lambda *= 0.1; 272 446 } else { 273 447 lambda *= 10.0; 274 448 } 275 min->iter ++; 276 277 // printf("CONDITIONS: (%f > %f) && (%d < %d)\n", min->lastDelta, min->tol, min->iter, min->maxIter); 278 } 279 psTrace (".psLib.dataManip.psMinimizeLMChi2", 4, "chisq: %f, last delta: %f, Niter: %d\n", min->value, min->lastDelta, min->iter); 449 min->iter++; 450 } 451 psTrace(__func__, 5, "chisq: %f, last delta: %f, Niter: %d\n", min->value, min->lastDelta, min->iter); 280 452 281 453 // construct & return the covariance matrix (if requested) 282 454 if (covar != NULL) { 283 p_psMinLM_GuessABP (covar, Beta, Params, alpha, beta, params, paramMask, 0.0); 455 p_psMinLM_GuessABP(covar, Beta, Params, alpha, beta, params, paramMask, 456 beta_lim, param_min, param_max, 0.0); 284 457 } 285 458 286 459 // free the internal temporary data 287 psFree (alpha); 288 psFree (Alpha); 289 psFree (beta); 290 psFree (Beta); 291 psFree (Params); 292 psFree (dy); 293 460 psFree(alpha); 461 psFree(Alpha); 462 psFree(beta); 463 psFree(Beta); 464 psFree(Params); 465 if (yWt == NULL) { 466 psFree(dy); 467 } 468 if (mustFree00 == true) { 469 psFree(beta_lim); 470 psFree(param_min); 471 psFree(param_max); 472 } 294 473 if (min->iter == min->maxIter) { 295 return (false); 296 } 297 return (true); 298 } 299 300 // XXX EAM: this needs to respect the mask on params 301 // alpha, beta, params are already allocated 302 psF64 p_psMinLM_SetABX (psImage *alpha, 303 psVector *beta, 304 const psVector *params, 305 const psVector *paramMask, 306 const psArray *x, 307 const psVector *y, 308 const psVector *dy, 309 psMinimizeLMChi2Func func) 310 { 311 PS_ASSERT_IMAGE_NON_NULL(alpha, NAN); 312 PS_ASSERT_VECTOR_NON_NULL(beta, NAN); 313 PS_ASSERT_VECTOR_NON_NULL(params, NAN); 314 PS_ASSERT_PTR_NON_NULL(x, NAN); 315 PS_ASSERT_VECTOR_NON_NULL(y, NAN); 316 PS_ASSERT_VECTOR_NON_NULL(dy, NAN); 317 318 psF64 chisq; 319 psF64 delta; 320 psF64 weight; 321 psF64 ymodel; 322 psVector *deriv = psVectorAlloc (params->n, PS_TYPE_F32); 323 324 // zero alpha and beta for summing below 325 for (int j = 0; j < params->n; j++) { 326 for (int k = 0; k < params->n; k++) { 327 alpha->data.F64[j][k] = 0; 328 } 329 beta->data.F64[j] = 0; 330 } 331 chisq = 0.0; 332 333 // calculate chisq, alpha, beta 334 for (int i = 0; i < y->n; i++) { 335 ymodel = func (deriv, params, (psVector *) x->data[i]); 336 337 delta = ymodel - y->data.F32[i]; 338 chisq += PS_SQR (delta) * dy->data.F32[i]; 339 340 for (int j = 0; j < params->n; j++) { 341 if ((paramMask != NULL) && (paramMask->data.U8[j])) 342 continue; 343 weight = deriv->data.F32[j] * dy->data.F32[i]; 344 for (int k = 0; k <= j; k++) { 345 if ((paramMask != NULL) && (paramMask->data.U8[k])) 346 continue; 347 alpha->data.F64[j][k] += weight * deriv->data.F32[k]; 348 } 349 beta->data.F64[j] += weight * delta; 350 } 351 } 352 353 // calculate lower-left half of alpha 354 for (int j = 1; j < params->n; j++) { 355 for (int k = 0; k < j; k++) { 356 alpha->data.F64[k][j] = alpha->data.F64[j][k]; 357 } 358 } 359 360 // fill in pivots if we apply a mask 361 if (paramMask != NULL) { 362 for (int j = 0; j < params->n; j++) { 363 if (paramMask->data.U8[j]) { 364 alpha->data.F64[j][j] = 1; 365 beta->data.F64[j] = 1; 366 } 367 } 368 } 369 370 psFree (deriv); 371 return (chisq); 372 } 373 374 // XXX EAM : can we use static copies of LUv, LUm, A? 375 psBool p_psMinLM_GuessABP (psImage *Alpha, 376 psVector *Beta, 377 psVector *Params, 378 const psImage *alpha, 379 const psVector *beta, 380 const psVector *params, 381 const psVector *paramMask, 382 psF64 lambda) 383 { 384 385 # define USE_LU_DECOMP 1 386 # if (USE_LU_DECOMP) 387 psVector *LUv = NULL; 388 psImage *LUm = NULL; 389 psImage *A = NULL; 390 psF32 det; 391 392 // LU decomposition version 393 psTrace (".psLib.dataManip.psMinLM_GuessABP", 5, "using LUD version\n"); 394 395 // set new guess values (creates matrix A) 396 A = psImageCopy (NULL, alpha, PS_TYPE_F64); 397 for (int j = 0; j < params->n; j++) { 398 if ((paramMask != NULL) && (paramMask->data.U8[j])) 399 continue; 400 A->data.F64[j][j] = alpha->data.F64[j][j] * (1.0 + lambda); 401 } 402 403 // solve A*beta = Beta (Alpha = 1/A) 404 // these operations do not modify the input values (creates LUm, LUv) 405 LUm = psMatrixLUD (NULL, &LUv, A); 406 Beta = psMatrixLUSolve (Beta, LUm, beta, LUv); 407 Alpha = psMatrixInvert (Alpha, A, &det); 408 409 # else 410 // gauss-jordan version 411 psTrace (".psLib.dataManip.psMinLM_GuessABP", 5, "using Gauss-J version"); 412 413 // set new guess values (creates matrix A) 414 Beta = psVectorCopy (Beta, beta, PS_TYPE_F64); 415 Alpha = psImageCopy (Alpha, alpha, PS_TYPE_F64); 416 for (int j = 0; j < params->n; j++) { 417 if ((paramMask != NULL) && (paramMask->data.U8[j])) 418 continue; 419 Alpha->data.F64[j][j] = alpha->data.F64[j][j] * (1.0 + lambda); 420 } 421 422 psGaussJordan (Alpha, Beta); 423 # endif 424 425 // apply Beta to get new Params values 426 for (int j = 0; j < params->n; j++) { 427 if ((paramMask != NULL) && (paramMask->data.U8[j])) 428 continue; 429 Params->data.F32[j] = params->data.F32[j] - Beta->data.F64[j]; 430 } 431 432 # if (USE_LU_DECOMP) 433 psFree (A); 434 psFree (LUm); 435 psFree (LUv); 436 # endif 437 438 return true; 474 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 475 return(false); 476 } 477 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 478 return(true); 439 479 } 440 480 441 481 // XXX EAM : temporary gauss-jordan solver based on gene's 442 482 // version based on the Numerical Recipes version 443 bool psGaussJordan (psImage *a, psVector *b) 483 bool psGaussJordan( 484 psImage *a, 485 psVector *b) 444 486 { 445 487 … … 455 497 vector = b->data.F64; 456 498 457 indxc = psAlloc (Nx*sizeof(int));458 indxr = psAlloc (Nx*sizeof(int));459 ipiv = psAlloc (Nx*sizeof(int));499 indxc = psAlloc(Nx*sizeof(int)); 500 indxr = psAlloc(Nx*sizeof(int)); 501 ipiv = psAlloc(Nx*sizeof(int)); 460 502 for (j = 0; j < Nx; j++) { 461 503 ipiv[j] = 0; … … 476 518 if (ipiv[k] == 0) { 477 519 if (fabs (matrix[j][k]) >= big) { 478 big = fabs (matrix[j][k]);520 big = fabs(matrix[j][k]); 479 521 irow = j; 480 522 icol = k; … … 492 534 if (irow != icol) { 493 535 for (l = 0; l < Nx; l++) { 494 PS_SWAP (matrix[irow][l], matrix[icol][l]);495 } 496 PS_SWAP (vector[irow], vector[icol]);536 PS_SWAP(matrix[irow][l], matrix[icol][l]); 537 } 538 PS_SWAP(vector[irow], vector[icol]); 497 539 } 498 540 indxr[i] = irow; … … 524 566 if (indxr[l] != indxc[l]) { 525 567 for (k = 0; k < Nx; k++) { 526 PS_SWAP (matrix[k][indxr[l]], matrix[k][indxc[l]]);527 } 528 } 529 } 530 psFree (ipiv);531 psFree (indxr);532 psFree (indxc);533 return (true);568 PS_SWAP(matrix[k][indxr[l]], matrix[k][indxc[l]]); 569 } 570 } 571 } 572 psFree(ipiv); 573 psFree(indxr); 574 psFree(indxc); 575 return(true); 534 576 535 577 fescape: 536 psFree (ipiv);537 psFree (indxr);538 psFree (indxc);539 return (false);578 psFree(ipiv); 579 psFree(indxr); 580 psFree(indxc); 581 return(false); 540 582 } 541 583 … … 565 607 bool psMemCheckMinimization(psPtr ptr) 566 608 { 567 return ( psMemGetDeallocator(ptr) == (psFreeFunc)minimizationFree );609 return( psMemGetDeallocator(ptr) == (psFreeFunc)minimizationFree ); 568 610 } 569 611
Note:
See TracChangeset
for help on using the changeset viewer.
