1 #include <petsc/private/taolinesearchimpl.h> 2 #include <../src/tao/linesearch/impls/morethuente/morethuente.h> 3 4 /* 5 This algorithm is taken from More' and Thuente, "Line search algorithms 6 with guaranteed sufficient decrease", Argonne National Laboratory, 7 Technical Report MCS-P330-1092. 8 */ 9 10 static PetscErrorCode Tao_mcstep(TaoLineSearch ls, PetscReal *stx, PetscReal *fx, PetscReal *dx, PetscReal *sty, PetscReal *fy, PetscReal *dy, PetscReal *stp, PetscReal *fp, PetscReal *dp); 11 12 static PetscErrorCode TaoLineSearchDestroy_MT(TaoLineSearch ls) 13 { 14 TaoLineSearch_MT *mt = (TaoLineSearch_MT *)ls->data; 15 16 PetscFunctionBegin; 17 PetscCall(PetscObjectDereference((PetscObject)mt->x)); 18 PetscCall(VecDestroy(&mt->work)); 19 PetscCall(PetscFree(ls->data)); 20 PetscFunctionReturn(PETSC_SUCCESS); 21 } 22 23 static PetscErrorCode TaoLineSearchSetFromOptions_MT(TaoLineSearch ls, PetscOptionItems *PetscOptionsObject) 24 { 25 PetscFunctionBegin; 26 PetscFunctionReturn(PETSC_SUCCESS); 27 } 28 29 static PetscErrorCode TaoLineSearchMonitor_MT(TaoLineSearch ls) 30 { 31 TaoLineSearch_MT *mt = (TaoLineSearch_MT *)ls->data; 32 33 PetscFunctionBegin; 34 PetscCall(PetscViewerASCIIPrintf(ls->viewer, "stx: %g, fx: %g, dgx: %g\n", (double)mt->stx, (double)mt->fx, (double)mt->dgx)); 35 PetscCall(PetscViewerASCIIPrintf(ls->viewer, "sty: %g, fy: %g, dgy: %g\n", (double)mt->sty, (double)mt->fy, (double)mt->dgy)); 36 PetscFunctionReturn(PETSC_SUCCESS); 37 } 38 39 static PetscErrorCode TaoLineSearchApply_MT(TaoLineSearch ls, Vec x, PetscReal *f, Vec g, Vec s) 40 { 41 TaoLineSearch_MT *mt = (TaoLineSearch_MT *)ls->data; 42 PetscReal xtrapf = 4.0; 43 PetscReal finit, width, width1, dginit, fm, fxm, fym, dgm, dgxm, dgym; 44 PetscReal dgx, dgy, dg, dg2, fx, fy, stx, sty, dgtest; 45 PetscReal ftest1 = 0.0, ftest2 = 0.0; 46 PetscInt i, stage1, n1, n2, nn1, nn2; 47 PetscReal bstepmin1, bstepmin2, bstepmax, ostepmin, ostepmax; 48 PetscBool g_computed = PETSC_FALSE; /* to prevent extra gradient computation */ 49 50 PetscFunctionBegin; 51 ls->reason = TAOLINESEARCH_CONTINUE_ITERATING; 52 PetscCall(TaoLineSearchMonitor(ls, 0, *f, 0.0)); 53 /* Check work vector */ 54 if (!mt->work) { 55 PetscCall(VecDuplicate(x, &mt->work)); 56 mt->x = x; 57 PetscCall(PetscObjectReference((PetscObject)mt->x)); 58 } else if (x != mt->x) { 59 PetscCall(VecDestroy(&mt->work)); 60 PetscCall(VecDuplicate(x, &mt->work)); 61 PetscCall(PetscObjectDereference((PetscObject)mt->x)); 62 mt->x = x; 63 PetscCall(PetscObjectReference((PetscObject)mt->x)); 64 } 65 66 ostepmax = ls->stepmax; 67 ostepmin = ls->stepmin; 68 69 if (ls->bounded) { 70 /* Compute step length needed to make all variables equal a bound */ 71 /* Compute the smallest steplength that will make one nonbinding variable 72 equal the bound */ 73 PetscCall(VecGetLocalSize(ls->upper, &n1)); 74 PetscCall(VecGetLocalSize(mt->x, &n2)); 75 PetscCall(VecGetSize(ls->upper, &nn1)); 76 PetscCall(VecGetSize(mt->x, &nn2)); 77 PetscCheck(n1 == n2 && nn1 == nn2, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Variable vector not compatible with bounds vector"); 78 PetscCall(VecScale(s, -1.0)); 79 PetscCall(VecBoundGradientProjection(s, x, ls->lower, ls->upper, s)); 80 PetscCall(VecScale(s, -1.0)); 81 PetscCall(VecStepBoundInfo(x, s, ls->lower, ls->upper, &bstepmin1, &bstepmin2, &bstepmax)); 82 ls->stepmax = PetscMin(bstepmax, ls->stepmax); 83 } 84 85 PetscCall(VecDot(g, s, &dginit)); 86 if (PetscIsInfOrNanReal(dginit)) { 87 PetscCall(PetscInfo(ls, "Initial Line Search step * g is Inf or Nan (%g)\n", (double)dginit)); 88 ls->reason = TAOLINESEARCH_FAILED_INFORNAN; 89 PetscFunctionReturn(PETSC_SUCCESS); 90 } 91 if (dginit >= 0.0) { 92 PetscCall(PetscInfo(ls, "Initial Line Search step * g is not descent direction (%g)\n", (double)dginit)); 93 ls->reason = TAOLINESEARCH_FAILED_ASCENT; 94 PetscFunctionReturn(PETSC_SUCCESS); 95 } 96 97 /* Initialization */ 98 mt->bracket = 0; 99 stage1 = 1; 100 finit = *f; 101 dgtest = ls->ftol * dginit; 102 width = ls->stepmax - ls->stepmin; 103 width1 = width * 2.0; 104 PetscCall(VecCopy(x, mt->work)); 105 /* Variable dictionary: 106 stx, fx, dgx - the step, function, and derivative at the best step 107 sty, fy, dgy - the step, function, and derivative at the other endpoint 108 of the interval of uncertainty 109 step, f, dg - the step, function, and derivative at the current step */ 110 111 stx = 0.0; 112 fx = finit; 113 dgx = dginit; 114 sty = 0.0; 115 fy = finit; 116 dgy = dginit; 117 118 ls->step = ls->initstep; 119 for (i = 0; i < ls->max_funcs; i++) { 120 /* Set min and max steps to correspond to the interval of uncertainty */ 121 if (mt->bracket) { 122 ls->stepmin = PetscMin(stx, sty); 123 ls->stepmax = PetscMax(stx, sty); 124 } else { 125 ls->stepmin = stx; 126 ls->stepmax = ls->step + xtrapf * (ls->step - stx); 127 } 128 129 /* Force the step to be within the bounds */ 130 ls->step = PetscMax(ls->step, ls->stepmin); 131 ls->step = PetscMin(ls->step, ls->stepmax); 132 133 /* If an unusual termination is to occur, then let step be the lowest 134 point obtained thus far */ 135 if (stx != 0 && ((mt->bracket && (ls->step <= ls->stepmin || ls->step >= ls->stepmax)) || (mt->bracket && (ls->stepmax - ls->stepmin <= ls->rtol * ls->stepmax)) || (ls->nfeval + ls->nfgeval >= ls->max_funcs - 1) || mt->infoc == 0)) 136 ls->step = stx; 137 138 PetscCall(VecWAXPY(mt->work, ls->step, s, x)); /* W = X + step*S */ 139 140 if (ls->step == 0.0) { 141 PetscCall(PetscInfo(ls, "Step size is zero.\n")); 142 ls->reason = TAOLINESEARCH_HALTED_LOWERBOUND; 143 break; 144 } 145 146 if (ls->bounded) PetscCall(VecMedian(ls->lower, mt->work, ls->upper, mt->work)); 147 if (ls->usegts) { 148 PetscCall(TaoLineSearchComputeObjectiveAndGTS(ls, mt->work, f, &dg)); 149 g_computed = PETSC_FALSE; 150 } else { 151 PetscCall(TaoLineSearchComputeObjectiveAndGradient(ls, mt->work, f, g)); 152 g_computed = PETSC_TRUE; 153 if (ls->bounded) { 154 PetscCall(VecDot(g, x, &dg)); 155 PetscCall(VecDot(g, mt->work, &dg2)); 156 dg = (dg2 - dg) / ls->step; 157 } else { 158 PetscCall(VecDot(g, s, &dg)); 159 } 160 } 161 162 /* update bracketing parameters in the MT context for printouts in monitor */ 163 mt->stx = stx; 164 mt->fx = fx; 165 mt->dgx = dgx; 166 mt->sty = sty; 167 mt->fy = fy; 168 mt->dgy = dgy; 169 PetscCall(TaoLineSearchMonitor(ls, i + 1, *f, ls->step)); 170 171 if (i == 0) ls->f_fullstep = *f; 172 173 if (PetscIsInfOrNanReal(*f) || PetscIsInfOrNanReal(dg)) { 174 /* User provided compute function generated Not-a-Number, assume 175 domain violation and set function value and directional 176 derivative to infinity. */ 177 *f = PETSC_INFINITY; 178 dg = PETSC_INFINITY; 179 } 180 181 ftest1 = finit + ls->step * dgtest; 182 if (ls->bounded) ftest2 = finit + ls->step * dgtest * ls->ftol; 183 184 /* Convergence testing */ 185 if ((*f - ftest1 <= PETSC_SMALL * PetscAbsReal(finit)) && (PetscAbsReal(dg) + ls->gtol * dginit <= 0.0)) { 186 PetscCall(PetscInfo(ls, "Line search success: Sufficient decrease and directional deriv conditions hold\n")); 187 ls->reason = TAOLINESEARCH_SUCCESS; 188 break; 189 } 190 191 /* Check Armijo if beyond the first breakpoint */ 192 if (ls->bounded && *f <= ftest2 && ls->step >= bstepmin2) { 193 PetscCall(PetscInfo(ls, "Line search success: Sufficient decrease.\n")); 194 ls->reason = TAOLINESEARCH_SUCCESS; 195 break; 196 } 197 198 /* Checks for bad cases */ 199 if ((mt->bracket && (ls->step <= ls->stepmin || ls->step >= ls->stepmax)) || !mt->infoc) { 200 PetscCall(PetscInfo(ls, "Rounding errors may prevent further progress. May not be a step satisfying\nsufficient decrease and curvature conditions. Tolerances may be too small.\n")); 201 ls->reason = TAOLINESEARCH_HALTED_OTHER; 202 break; 203 } 204 if (ls->step == ls->stepmax && *f <= ftest1 && dg <= dgtest) { 205 PetscCall(PetscInfo(ls, "Step is at the upper bound, stepmax (%g)\n", (double)ls->stepmax)); 206 ls->reason = TAOLINESEARCH_HALTED_UPPERBOUND; 207 break; 208 } 209 if (ls->step == ls->stepmin && *f >= ftest1 && dg >= dgtest) { 210 PetscCall(PetscInfo(ls, "Step is at the lower bound, stepmin (%g)\n", (double)ls->stepmin)); 211 ls->reason = TAOLINESEARCH_HALTED_LOWERBOUND; 212 break; 213 } 214 if (mt->bracket && (ls->stepmax - ls->stepmin <= ls->rtol * ls->stepmax)) { 215 PetscCall(PetscInfo(ls, "Relative width of interval of uncertainty is at most rtol (%g)\n", (double)ls->rtol)); 216 ls->reason = TAOLINESEARCH_HALTED_RTOL; 217 break; 218 } 219 220 /* In the first stage, we seek a step for which the modified function 221 has a nonpositive value and nonnegative derivative */ 222 if (stage1 && *f <= ftest1 && dg >= dginit * PetscMin(ls->ftol, ls->gtol)) stage1 = 0; 223 224 /* A modified function is used to predict the step only if we 225 have not obtained a step for which the modified function has a 226 nonpositive function value and nonnegative derivative, and if a 227 lower function value has been obtained but the decrease is not 228 sufficient */ 229 230 if (stage1 && *f <= fx && *f > ftest1) { 231 fm = *f - ls->step * dgtest; /* Define modified function */ 232 fxm = fx - stx * dgtest; /* and derivatives */ 233 fym = fy - sty * dgtest; 234 dgm = dg - dgtest; 235 dgxm = dgx - dgtest; 236 dgym = dgy - dgtest; 237 238 /* if (dgxm * (ls->step - stx) >= 0.0) */ 239 /* Update the interval of uncertainty and compute the new step */ 240 PetscCall(Tao_mcstep(ls, &stx, &fxm, &dgxm, &sty, &fym, &dgym, &ls->step, &fm, &dgm)); 241 242 fx = fxm + stx * dgtest; /* Reset the function and */ 243 fy = fym + sty * dgtest; /* gradient values */ 244 dgx = dgxm + dgtest; 245 dgy = dgym + dgtest; 246 } else { 247 /* Update the interval of uncertainty and compute the new step */ 248 PetscCall(Tao_mcstep(ls, &stx, &fx, &dgx, &sty, &fy, &dgy, &ls->step, f, &dg)); 249 } 250 251 /* Force a sufficient decrease in the interval of uncertainty */ 252 if (mt->bracket) { 253 if (PetscAbsReal(sty - stx) >= 0.66 * width1) ls->step = stx + 0.5 * (sty - stx); 254 width1 = width; 255 width = PetscAbsReal(sty - stx); 256 } 257 } 258 if (ls->nfeval + ls->nfgeval > ls->max_funcs) { 259 PetscCall(PetscInfo(ls, "Number of line search function evals (%" PetscInt_FMT ") > maximum (%" PetscInt_FMT ")\n", ls->nfeval + ls->nfgeval, ls->max_funcs)); 260 ls->reason = TAOLINESEARCH_HALTED_MAXFCN; 261 } 262 ls->stepmax = ostepmax; 263 ls->stepmin = ostepmin; 264 265 /* Finish computations */ 266 PetscCall(PetscInfo(ls, "%" PetscInt_FMT " function evals in line search, step = %g\n", ls->nfeval + ls->nfgeval, (double)ls->step)); 267 268 /* Set new solution vector and compute gradient if needed */ 269 PetscCall(VecCopy(mt->work, x)); 270 if (!g_computed) PetscCall(TaoLineSearchComputeGradient(ls, mt->work, g)); 271 PetscFunctionReturn(PETSC_SUCCESS); 272 } 273 274 /*MC 275 TAOLINESEARCHMT - More-Thuente line-search type with cubic interpolation that satisfies both the sufficient decrease and 276 curvature conditions. This method can take step lengths greater than 1, {cite}`more:92` 277 278 Options Database Key: 279 . -tao_ls_type more-thuente - use this line search type 280 281 Level: developer 282 283 .seealso: `TaoLineSearchCreate()`, `TaoLineSearchSetType()`, `TaoLineSearchApply()` 284 M*/ 285 PETSC_EXTERN PetscErrorCode TaoLineSearchCreate_MT(TaoLineSearch ls) 286 { 287 TaoLineSearch_MT *ctx; 288 289 PetscFunctionBegin; 290 PetscValidHeaderSpecific(ls, TAOLINESEARCH_CLASSID, 1); 291 PetscCall(PetscNew(&ctx)); 292 ctx->bracket = 0; 293 ctx->infoc = 1; 294 ls->data = (void *)ctx; 295 ls->initstep = 1.0; 296 ls->ops->setup = NULL; 297 ls->ops->reset = NULL; 298 ls->ops->apply = TaoLineSearchApply_MT; 299 ls->ops->destroy = TaoLineSearchDestroy_MT; 300 ls->ops->setfromoptions = TaoLineSearchSetFromOptions_MT; 301 ls->ops->monitor = TaoLineSearchMonitor_MT; 302 PetscFunctionReturn(PETSC_SUCCESS); 303 } 304 305 /* 306 The subroutine mcstep is taken from the work of Jorge Nocedal. 307 this is a variant of More' and Thuente's routine. 308 309 subroutine mcstep 310 311 the purpose of mcstep is to compute a safeguarded step for 312 a linesearch and to update an interval of uncertainty for 313 a minimizer of the function. 314 315 the parameter stx contains the step with the least function 316 value. the parameter stp contains the current step. it is 317 assumed that the derivative at stx is negative in the 318 direction of the step. if bracket is set true then a 319 minimizer has been bracketed in an interval of uncertainty 320 with endpoints stx and sty. 321 322 the subroutine statement is 323 324 subroutine mcstep(stx,fx,dx,sty,fy,dy,stp,fp,dp,bracket, 325 stpmin,stpmax,info) 326 327 where 328 329 stx, fx, and dx are variables which specify the step, 330 the function, and the derivative at the best step obtained 331 so far. The derivative must be negative in the direction 332 of the step, that is, dx and stp-stx must have opposite 333 signs. On output these parameters are updated appropriately. 334 335 sty, fy, and dy are variables which specify the step, 336 the function, and the derivative at the other endpoint of 337 the interval of uncertainty. On output these parameters are 338 updated appropriately. 339 340 stp, fp, and dp are variables which specify the step, 341 the function, and the derivative at the current step. 342 If bracket is set true then on input stp must be 343 between stx and sty. On output stp is set to the new step. 344 345 bracket is a logical variable which specifies if a minimizer 346 has been bracketed. If the minimizer has not been bracketed 347 then on input bracket must be set false. If the minimizer 348 is bracketed then on output bracket is set true. 349 350 stpmin and stpmax are input variables which specify lower 351 and upper bounds for the step. 352 353 info is an integer output variable set as follows: 354 if info = 1,2,3,4,5, then the step has been computed 355 according to one of the five cases below. otherwise 356 info = 0, and this indicates improper input parameters. 357 358 subprograms called 359 360 fortran-supplied ... abs,max,min,sqrt 361 362 argonne national laboratory. minpack project. june 1983 363 jorge j. more', david j. thuente 364 365 */ 366 367 static PetscErrorCode Tao_mcstep(TaoLineSearch ls, PetscReal *stx, PetscReal *fx, PetscReal *dx, PetscReal *sty, PetscReal *fy, PetscReal *dy, PetscReal *stp, PetscReal *fp, PetscReal *dp) 368 { 369 TaoLineSearch_MT *mtP = (TaoLineSearch_MT *)ls->data; 370 PetscReal gamma1, p, q, r, s, sgnd, stpc, stpf, stpq, theta; 371 PetscInt bound; 372 373 PetscFunctionBegin; 374 /* Check the input parameters for errors */ 375 mtP->infoc = 0; 376 PetscCheck(!mtP->bracket || (*stp > PetscMin(*stx, *sty) && *stp < PetscMax(*stx, *sty)), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "bad stp in bracket"); 377 PetscCheck(*dx * (*stp - *stx) < 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "dx * (stp-stx) >= 0.0"); 378 PetscCheck(ls->stepmax >= ls->stepmin, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "stepmax > stepmin"); 379 380 /* Determine if the derivatives have opposite sign */ 381 sgnd = *dp * (*dx / PetscAbsReal(*dx)); 382 383 if (*fp > *fx) { 384 /* Case 1: a higher function value. 385 The minimum is bracketed. If the cubic step is closer 386 to stx than the quadratic step, the cubic step is taken, 387 else the average of the cubic and quadratic steps is taken. */ 388 389 mtP->infoc = 1; 390 bound = 1; 391 theta = 3 * (*fx - *fp) / (*stp - *stx) + *dx + *dp; 392 s = PetscMax(PetscAbsReal(theta), PetscAbsReal(*dx)); 393 s = PetscMax(s, PetscAbsReal(*dp)); 394 gamma1 = s * PetscSqrtScalar(PetscPowScalar(theta / s, 2.0) - (*dx / s) * (*dp / s)); 395 if (*stp < *stx) gamma1 = -gamma1; 396 /* Can p be 0? Check */ 397 p = (gamma1 - *dx) + theta; 398 q = ((gamma1 - *dx) + gamma1) + *dp; 399 r = p / q; 400 stpc = *stx + r * (*stp - *stx); 401 stpq = *stx + ((*dx / ((*fx - *fp) / (*stp - *stx) + *dx)) * 0.5) * (*stp - *stx); 402 403 if (PetscAbsReal(stpc - *stx) < PetscAbsReal(stpq - *stx)) stpf = stpc; 404 else stpf = stpc + 0.5 * (stpq - stpc); 405 mtP->bracket = 1; 406 } else if (sgnd < 0.0) { 407 /* Case 2: A lower function value and derivatives of 408 opposite sign. The minimum is bracketed. If the cubic 409 step is closer to stx than the quadratic (secant) step, 410 the cubic step is taken, else the quadratic step is taken. */ 411 412 mtP->infoc = 2; 413 bound = 0; 414 theta = 3 * (*fx - *fp) / (*stp - *stx) + *dx + *dp; 415 s = PetscMax(PetscAbsReal(theta), PetscAbsReal(*dx)); 416 s = PetscMax(s, PetscAbsReal(*dp)); 417 gamma1 = s * PetscSqrtScalar(PetscPowScalar(theta / s, 2.0) - (*dx / s) * (*dp / s)); 418 if (*stp > *stx) gamma1 = -gamma1; 419 p = (gamma1 - *dp) + theta; 420 q = ((gamma1 - *dp) + gamma1) + *dx; 421 r = p / q; 422 stpc = *stp + r * (*stx - *stp); 423 stpq = *stp + (*dp / (*dp - *dx)) * (*stx - *stp); 424 425 if (PetscAbsReal(stpc - *stp) > PetscAbsReal(stpq - *stp)) stpf = stpc; 426 else stpf = stpq; 427 mtP->bracket = 1; 428 } else if (PetscAbsReal(*dp) < PetscAbsReal(*dx)) { 429 /* Case 3: A lower function value, derivatives of the 430 same sign, and the magnitude of the derivative decreases. 431 The cubic step is only used if the cubic tends to infinity 432 in the direction of the step or if the minimum of the cubic 433 is beyond stp. Otherwise the cubic step is defined to be 434 either stepmin or stepmax. The quadratic (secant) step is also 435 computed and if the minimum is bracketed then the step 436 closest to stx is taken, else the step farthest away is taken. */ 437 438 mtP->infoc = 3; 439 bound = 1; 440 theta = 3 * (*fx - *fp) / (*stp - *stx) + *dx + *dp; 441 s = PetscMax(PetscAbsReal(theta), PetscAbsReal(*dx)); 442 s = PetscMax(s, PetscAbsReal(*dp)); 443 444 /* The case gamma1 = 0 only arises if the cubic does not tend 445 to infinity in the direction of the step. */ 446 gamma1 = s * PetscSqrtScalar(PetscMax(0.0, PetscPowScalar(theta / s, 2.0) - (*dx / s) * (*dp / s))); 447 if (*stp > *stx) gamma1 = -gamma1; 448 p = (gamma1 - *dp) + theta; 449 q = (gamma1 + (*dx - *dp)) + gamma1; 450 r = p / q; 451 if (r < 0.0 && gamma1 != 0.0) stpc = *stp + r * (*stx - *stp); 452 else if (*stp > *stx) stpc = ls->stepmax; 453 else stpc = ls->stepmin; 454 stpq = *stp + (*dp / (*dp - *dx)) * (*stx - *stp); 455 456 if (mtP->bracket) { 457 if (PetscAbsReal(*stp - stpc) < PetscAbsReal(*stp - stpq)) stpf = stpc; 458 else stpf = stpq; 459 } else { 460 if (PetscAbsReal(*stp - stpc) > PetscAbsReal(*stp - stpq)) stpf = stpc; 461 else stpf = stpq; 462 } 463 } else { 464 /* Case 4: A lower function value, derivatives of the 465 same sign, and the magnitude of the derivative does 466 not decrease. If the minimum is not bracketed, the step 467 is either stpmin or stpmax, else the cubic step is taken. */ 468 469 mtP->infoc = 4; 470 bound = 0; 471 if (mtP->bracket) { 472 theta = 3 * (*fp - *fy) / (*sty - *stp) + *dy + *dp; 473 s = PetscMax(PetscAbsReal(theta), PetscAbsReal(*dy)); 474 s = PetscMax(s, PetscAbsReal(*dp)); 475 gamma1 = s * PetscSqrtScalar(PetscPowScalar(theta / s, 2.0) - (*dy / s) * (*dp / s)); 476 if (*stp > *sty) gamma1 = -gamma1; 477 p = (gamma1 - *dp) + theta; 478 q = ((gamma1 - *dp) + gamma1) + *dy; 479 r = p / q; 480 stpc = *stp + r * (*sty - *stp); 481 stpf = stpc; 482 } else if (*stp > *stx) { 483 stpf = ls->stepmax; 484 } else { 485 stpf = ls->stepmin; 486 } 487 } 488 489 /* Update the interval of uncertainty. This update does not 490 depend on the new step or the case analysis above. */ 491 492 if (*fp > *fx) { 493 *sty = *stp; 494 *fy = *fp; 495 *dy = *dp; 496 } else { 497 if (sgnd < 0.0) { 498 *sty = *stx; 499 *fy = *fx; 500 *dy = *dx; 501 } 502 *stx = *stp; 503 *fx = *fp; 504 *dx = *dp; 505 } 506 507 /* Compute the new step and safeguard it. */ 508 stpf = PetscMin(ls->stepmax, stpf); 509 stpf = PetscMax(ls->stepmin, stpf); 510 *stp = stpf; 511 if (mtP->bracket && bound) { 512 if (*sty > *stx) *stp = PetscMin(*stx + 0.66 * (*sty - *stx), *stp); 513 else *stp = PetscMax(*stx + 0.66 * (*sty - *stx), *stp); 514 } 515 PetscFunctionReturn(PETSC_SUCCESS); 516 } 517