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