xref: /petsc/src/tao/linesearch/impls/morethuente/morethuente.c (revision f13dfd9ea68e0ddeee984e65c377a1819eab8a8a)
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