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