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