xref: /petsc/src/snes/linesearch/impls/bt/linesearchbt.c (revision d7ca06c0de435eadbf707aa307b64606df8edc03)
1af0996ceSBarry Smith #include <petsc/private/linesearchimpl.h> /*I  "petscsnes.h"  I*/
2af0996ceSBarry Smith #include <petsc/private/snesimpl.h>
371b4ebd2SPeter Brune 
471b4ebd2SPeter Brune typedef struct {
571b4ebd2SPeter Brune   PetscReal alpha;        /* sufficient decrease parameter */
6f1c6b773SPeter Brune } SNESLineSearch_BT;
771b4ebd2SPeter Brune 
82f4102e2SPeter Brune /*@
92f4102e2SPeter Brune    SNESLineSearchBTSetAlpha - Sets the descent parameter, alpha, in the BT linesearch variant.
102f4102e2SPeter Brune 
112f4102e2SPeter Brune    Input Parameters:
122f4102e2SPeter Brune +  linesearch - linesearch context
132f4102e2SPeter Brune -  alpha - The descent parameter
142f4102e2SPeter Brune 
152f4102e2SPeter Brune    Level: intermediate
162f4102e2SPeter Brune 
171a4f838cSPeter Brune .seealso: SNESLineSearchSetLambda(), SNESLineSearchGetTolerances() SNESLINESEARCHBT
182f4102e2SPeter Brune @*/
192f4102e2SPeter Brune PetscErrorCode SNESLineSearchBTSetAlpha(SNESLineSearch linesearch, PetscReal alpha)
202f4102e2SPeter Brune {
21*d7ca06c0SBarry Smith   SNESLineSearch_BT *bt = (SNESLineSearch_BT*)linesearch->data;
226e111a19SKarl Rupp 
232f4102e2SPeter Brune   PetscFunctionBegin;
242f4102e2SPeter Brune   PetscValidHeaderSpecific(linesearch,SNESLINESEARCH_CLASSID,1);
252f4102e2SPeter Brune   bt->alpha = alpha;
262f4102e2SPeter Brune   PetscFunctionReturn(0);
272f4102e2SPeter Brune }
282f4102e2SPeter Brune 
292f4102e2SPeter Brune /*@
302f4102e2SPeter Brune    SNESLineSearchBTGetAlpha - Gets the descent parameter, alpha, in the BT linesearch variant.
312f4102e2SPeter Brune 
322f4102e2SPeter Brune    Input Parameters:
332f4102e2SPeter Brune .  linesearch - linesearch context
348e557f58SPeter Brune 
358e557f58SPeter Brune    Output Parameters:
362f4102e2SPeter Brune .  alpha - The descent parameter
372f4102e2SPeter Brune 
382f4102e2SPeter Brune    Level: intermediate
392f4102e2SPeter Brune 
401a4f838cSPeter Brune .seealso: SNESLineSearchGetLambda(), SNESLineSearchGetTolerances() SNESLINESEARCHBT
412f4102e2SPeter Brune @*/
422f4102e2SPeter Brune PetscErrorCode SNESLineSearchBTGetAlpha(SNESLineSearch linesearch, PetscReal *alpha)
432f4102e2SPeter Brune {
44*d7ca06c0SBarry Smith   SNESLineSearch_BT *bt = (SNESLineSearch_BT*)linesearch->data;
456e111a19SKarl Rupp 
462f4102e2SPeter Brune   PetscFunctionBegin;
472f4102e2SPeter Brune   PetscValidHeaderSpecific(linesearch,SNESLINESEARCH_CLASSID,1);
482f4102e2SPeter Brune   *alpha = bt->alpha;
492f4102e2SPeter Brune   PetscFunctionReturn(0);
502f4102e2SPeter Brune }
512f4102e2SPeter Brune 
52f1c6b773SPeter Brune static PetscErrorCode  SNESLineSearchApply_BT(SNESLineSearch linesearch)
5371b4ebd2SPeter Brune {
5471b4ebd2SPeter Brune   PetscBool         changed_y,changed_w;
5571b4ebd2SPeter Brune   PetscErrorCode    ierr;
5671b4ebd2SPeter Brune   Vec               X,F,Y,W,G;
5771b4ebd2SPeter Brune   SNES              snes;
588a430afbSPeter Brune   PetscReal         fnorm, xnorm, ynorm, gnorm;
593b288129SPeter Brune   PetscReal         lambda,lambdatemp,lambdaprev,minlambda,maxstep,initslope,alpha,stol;
60dfcd3828SPeter Brune   PetscReal         t1,t2,a,b,d;
618a430afbSPeter Brune   PetscReal         f;
628a430afbSPeter Brune   PetscReal         g,gprev;
6371b4ebd2SPeter Brune   PetscViewer       monitor;
6471b4ebd2SPeter Brune   PetscInt          max_its,count;
65*d7ca06c0SBarry Smith   SNESLineSearch_BT *bt = (SNESLineSearch_BT*)linesearch->data;
6671b4ebd2SPeter Brune   Mat               jac;
67bd4a8a71SBarry Smith   PetscErrorCode    (*objective)(SNES,Vec,PetscReal*,void*);
6871b4ebd2SPeter Brune 
6971b4ebd2SPeter Brune   PetscFunctionBegin;
70f1c6b773SPeter Brune   ierr = SNESLineSearchGetVecs(linesearch, &X, &F, &Y, &W, &G);CHKERRQ(ierr);
71f1c6b773SPeter Brune   ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
72f1c6b773SPeter Brune   ierr = SNESLineSearchGetLambda(linesearch, &lambda);CHKERRQ(ierr);
73f1c6b773SPeter Brune   ierr = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr);
74dcf2fd19SBarry Smith   ierr = SNESLineSearchGetDefaultMonitor(linesearch, &monitor);CHKERRQ(ierr);
750298fd71SBarry Smith   ierr = SNESLineSearchGetTolerances(linesearch,&minlambda,&maxstep,NULL,NULL,NULL,&max_its);CHKERRQ(ierr);
760298fd71SBarry Smith   ierr = SNESGetTolerances(snes,NULL,NULL,&stol,NULL,NULL);CHKERRQ(ierr);
770298fd71SBarry Smith   ierr = SNESGetObjective(snes,&objective,NULL);CHKERRQ(ierr);
7871b4ebd2SPeter Brune   alpha = bt->alpha;
7971b4ebd2SPeter Brune 
800298fd71SBarry Smith   ierr = SNESGetJacobian(snes, &jac, NULL, NULL, NULL);CHKERRQ(ierr);
81ce94432eSBarry Smith   if (!jac && !objective) SETERRQ(PetscObjectComm((PetscObject)linesearch), PETSC_ERR_USER, "SNESLineSearchBT requires a Jacobian matrix");
82c69d1a72SBarry Smith 
837b1df9c1SPeter Brune   ierr = SNESLineSearchPreCheck(linesearch,X,Y,&changed_y);CHKERRQ(ierr);
84422a814eSBarry Smith   ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED);CHKERRQ(ierr);
8571b4ebd2SPeter Brune 
863b288129SPeter Brune   ierr = VecNormBegin(Y, NORM_2, &ynorm);CHKERRQ(ierr);
873b288129SPeter Brune   ierr = VecNormBegin(X, NORM_2, &xnorm);CHKERRQ(ierr);
883b288129SPeter Brune   ierr = VecNormEnd(Y, NORM_2, &ynorm);CHKERRQ(ierr);
893b288129SPeter Brune   ierr = VecNormEnd(X, NORM_2, &xnorm);CHKERRQ(ierr);
903b288129SPeter Brune 
9171b4ebd2SPeter Brune   if (ynorm == 0.0) {
9271b4ebd2SPeter Brune     if (monitor) {
93ea5d4fccSPeter Brune       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
9471b4ebd2SPeter Brune       ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
95ea5d4fccSPeter Brune       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
9671b4ebd2SPeter Brune     }
9771b4ebd2SPeter Brune     ierr = VecCopy(X,W);CHKERRQ(ierr);
9871b4ebd2SPeter Brune     ierr = VecCopy(F,G);CHKERRQ(ierr);
9971cee68bSPeter Brune     ierr = SNESLineSearchSetNorms(linesearch,xnorm,fnorm,ynorm);CHKERRQ(ierr);
100e9b602ebSSatish Balay     ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT);CHKERRQ(ierr);
10171b4ebd2SPeter Brune     PetscFunctionReturn(0);
10271b4ebd2SPeter Brune   }
10371b4ebd2SPeter Brune   if (ynorm > maxstep) {        /* Step too big, so scale back */
10471b4ebd2SPeter Brune     if (monitor) {
105ea5d4fccSPeter Brune       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
106c69d1a72SBarry Smith       ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Scaling step by %14.12e old ynorm %14.12e\n", (double)(maxstep/ynorm),(double)ynorm);CHKERRQ(ierr);
107ea5d4fccSPeter Brune       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
10871b4ebd2SPeter Brune     }
10971b4ebd2SPeter Brune     ierr  = VecScale(Y,maxstep/(ynorm));CHKERRQ(ierr);
11071b4ebd2SPeter Brune     ynorm = maxstep;
11171b4ebd2SPeter Brune   }
1128a430afbSPeter Brune 
1138a430afbSPeter Brune   /* if the SNES has an objective set, use that instead of the function value */
114bd4a8a71SBarry Smith   if (objective) {
1158a430afbSPeter Brune     ierr = SNESComputeObjective(snes,X,&f);CHKERRQ(ierr);
1168a430afbSPeter Brune   } else {
1178a430afbSPeter Brune     f = fnorm*fnorm;
1188a430afbSPeter Brune   }
1198a430afbSPeter Brune 
1208a430afbSPeter Brune   /* compute the initial slope */
121bd4a8a71SBarry Smith   if (objective) {
1228a430afbSPeter Brune     /* slope comes from the function (assumed to be the gradient of the objective */
12367392de3SBarry Smith     ierr = VecDotRealPart(Y,F,&initslope);CHKERRQ(ierr);
1248a430afbSPeter Brune   } else {
1258a430afbSPeter Brune     /* slope comes from the normal equations */
12671b4ebd2SPeter Brune     ierr = MatMult(jac,Y,W);CHKERRQ(ierr);
12767392de3SBarry Smith     ierr = VecDotRealPart(F,W,&initslope);CHKERRQ(ierr);
12871b4ebd2SPeter Brune     if (initslope > 0.0)  initslope = -initslope;
12971b4ebd2SPeter Brune     if (initslope == 0.0) initslope = -1.0;
1308a430afbSPeter Brune   }
13171b4ebd2SPeter Brune 
132df019d78SBarry Smith   while (PETSC_TRUE) {
133c427506bSPeter Brune     ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
1349bd66eb0SPeter Brune     if (linesearch->ops->viproject) {
1359bd66eb0SPeter Brune       ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
1369bd66eb0SPeter Brune     }
137e71169deSBarry Smith     if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
13871b4ebd2SPeter Brune       ierr         = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
13971b4ebd2SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
140e9b602ebSSatish Balay       ierr         = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION);CHKERRQ(ierr);
14171b4ebd2SPeter Brune       PetscFunctionReturn(0);
14271b4ebd2SPeter Brune     }
1438a430afbSPeter Brune 
144bd4a8a71SBarry Smith     if (objective) {
1458a430afbSPeter Brune       ierr = SNESComputeObjective(snes,W,&g);CHKERRQ(ierr);
1468a430afbSPeter Brune     } else {
147ce5a860aSPeter Brune       ierr = (*linesearch->ops->snesfunc)(snes,W,G);CHKERRQ(ierr);
1489bd66eb0SPeter Brune       if (linesearch->ops->vinorm) {
1499bd66eb0SPeter Brune         gnorm = fnorm;
1509bd66eb0SPeter Brune         ierr  = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
1519bd66eb0SPeter Brune       } else {
15271b4ebd2SPeter Brune         ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
1538a430afbSPeter Brune       }
15479e7e81bSJed Brown       g = PetscSqr(gnorm);
1559bd66eb0SPeter Brune     }
156dcf2fd19SBarry Smith     ierr = SNESLineSearchMonitor(linesearch);CHKERRQ(ierr);
1579bd66eb0SPeter Brune 
158df019d78SBarry Smith     if (!PetscIsInfOrNanReal(g)) break;
159df019d78SBarry Smith     if (monitor) {
160df019d78SBarry Smith       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
161df019d78SBarry Smith       ierr = PetscViewerASCIIPrintf(monitor,"    Line search: objective function at lambdas = %g is Inf or Nan, cutting lambda\n",(double)lambda);CHKERRQ(ierr);
162df019d78SBarry Smith       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
163df019d78SBarry Smith     }
164df019d78SBarry Smith     if (lambda <= minlambda) {
165df019d78SBarry Smith       ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT);CHKERRQ(ierr);
166c98378a5SBarry Smith       PetscFunctionReturn(0);
167c98378a5SBarry Smith     }
168df019d78SBarry Smith     lambda = .5*lambda;
169df019d78SBarry Smith   }
170df019d78SBarry Smith 
171bd4a8a71SBarry Smith   if (!objective) {
172c69d1a72SBarry Smith     ierr = PetscInfo2(snes,"Initial fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm);CHKERRQ(ierr);
1738a430afbSPeter Brune   }
1748a430afbSPeter Brune   if (.5*g <= .5*f + lambda*alpha*initslope) { /* Sufficient reduction or step tolerance convergence */
17571b4ebd2SPeter Brune     if (monitor) {
176ea5d4fccSPeter Brune       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
177bd4a8a71SBarry Smith       if (!objective) {
178c69d1a72SBarry Smith         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Using full step: fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm);CHKERRQ(ierr);
1798a430afbSPeter Brune       } else {
180df019d78SBarry Smith         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Using full step: obj %14.12e obj %14.12e\n", (double)f, (double)g);CHKERRQ(ierr);
1818a430afbSPeter Brune       }
182ea5d4fccSPeter Brune       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
18371b4ebd2SPeter Brune     }
18471b4ebd2SPeter Brune   } else {
185c21ba15cSPeter Brune     /* Since the full step didn't work and the step is tiny, quit */
186c21ba15cSPeter Brune     if (stol*xnorm > ynorm) {
187ced04f9dSPeter Brune       ierr = SNESLineSearchSetNorms(linesearch,xnorm,fnorm,ynorm);CHKERRQ(ierr);
188efa57af7SBarry Smith       ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED);CHKERRQ(ierr);
189c61ba1e2SPeter Brune       if (monitor) {
190c61ba1e2SPeter Brune         ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
191efa57af7SBarry Smith         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Ended due to ynorm < stol*xnorm (%14.12e < %14.12e).\n",(double)ynorm,(double)stol*xnorm);CHKERRQ(ierr);
192c61ba1e2SPeter Brune         ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
193c61ba1e2SPeter Brune       }
194c21ba15cSPeter Brune       PetscFunctionReturn(0);
195c21ba15cSPeter Brune     }
19671b4ebd2SPeter Brune     /* Fit points with quadratic */
1978a430afbSPeter Brune     lambdatemp = -initslope/(g - f - 2.0*lambda*initslope);
19871b4ebd2SPeter Brune     lambdaprev = lambda;
1998a430afbSPeter Brune     gprev      = g;
20071b4ebd2SPeter Brune     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
20171b4ebd2SPeter Brune     if (lambdatemp <= .1*lambda) lambda = .1*lambda;
20271b4ebd2SPeter Brune     else                         lambda = lambdatemp;
20371b4ebd2SPeter Brune 
20471b4ebd2SPeter Brune     ierr  = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
2059bd66eb0SPeter Brune     if (linesearch->ops->viproject) {
2069bd66eb0SPeter Brune       ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
2079bd66eb0SPeter Brune     }
208e71169deSBarry Smith     if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
20971b4ebd2SPeter Brune       ierr         = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
21071b4ebd2SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
211e9b602ebSSatish Balay       ierr         = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION);CHKERRQ(ierr);
21271b4ebd2SPeter Brune       PetscFunctionReturn(0);
21371b4ebd2SPeter Brune     }
214bd4a8a71SBarry Smith     if (objective) {
2158a430afbSPeter Brune       ierr = SNESComputeObjective(snes,W,&g);CHKERRQ(ierr);
2168a430afbSPeter Brune     } else {
217ce5a860aSPeter Brune       ierr = (*linesearch->ops->snesfunc)(snes,W,G);CHKERRQ(ierr);
2189bd66eb0SPeter Brune       if (linesearch->ops->vinorm) {
2199bd66eb0SPeter Brune         gnorm = fnorm;
2209bd66eb0SPeter Brune         ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
2219bd66eb0SPeter Brune       } else {
22271b4ebd2SPeter Brune         ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
2239bd66eb0SPeter Brune       }
224f1ab69e3SPeter Brune       g = PetscSqr(gnorm);
2258a430afbSPeter Brune     }
226c98378a5SBarry Smith     if (PetscIsInfOrNanReal(g)) {
227422a814eSBarry Smith       ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_NANORINF);CHKERRQ(ierr);
228c61ba1e2SPeter Brune       ierr = PetscInfo(snes,"Aborted due to Nan or Inf in function evaluation\n");CHKERRQ(ierr);
229c98378a5SBarry Smith       PetscFunctionReturn(0);
230c98378a5SBarry Smith     }
23171b4ebd2SPeter Brune     if (monitor) {
232ea5d4fccSPeter Brune       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
233bd4a8a71SBarry Smith       if (!objective) {
234c69d1a72SBarry Smith         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: gnorm after quadratic fit %14.12e\n",(double)gnorm);CHKERRQ(ierr);
2358a430afbSPeter Brune       } else {
2368a430afbSPeter Brune         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: obj after quadratic fit %14.12e\n",(double)g);CHKERRQ(ierr);
2378a430afbSPeter Brune       }
238ea5d4fccSPeter Brune       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
23971b4ebd2SPeter Brune     }
2408a430afbSPeter Brune     if (.5*g < .5*f + lambda*alpha*initslope) { /* sufficient reduction */
24171b4ebd2SPeter Brune       if (monitor) {
242ea5d4fccSPeter Brune         ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
24371b4ebd2SPeter Brune         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",(double)lambda);CHKERRQ(ierr);
244ea5d4fccSPeter Brune         ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
24571b4ebd2SPeter Brune       }
24671b4ebd2SPeter Brune     } else {
24771b4ebd2SPeter Brune       /* Fit points with cubic */
24871b4ebd2SPeter Brune       for (count = 0; count < max_its; count++) {
24971b4ebd2SPeter Brune         if (lambda <= minlambda) {
25071b4ebd2SPeter Brune           if (monitor) {
251ea5d4fccSPeter Brune             ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
25271b4ebd2SPeter Brune             ierr = PetscViewerASCIIPrintf(monitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
253bd4a8a71SBarry Smith             if (!objective) {
2544a2f8832SBarry Smith               ierr = PetscViewerASCIIPrintf(monitor,"    Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",
255c69d1a72SBarry Smith                                                          (double)fnorm, (double)gnorm, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope);CHKERRQ(ierr);
2568a430afbSPeter Brune             } else {
2574a2f8832SBarry Smith               ierr = PetscViewerASCIIPrintf(monitor,"    Line search: obj(0)=%18.16e, obj=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",
2588a430afbSPeter Brune                                                          (double)f, (double)g, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope);CHKERRQ(ierr);
2598a430afbSPeter Brune             }
260ea5d4fccSPeter Brune             ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
26171b4ebd2SPeter Brune           }
262e9b602ebSSatish Balay           ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT);CHKERRQ(ierr);
26371b4ebd2SPeter Brune           PetscFunctionReturn(0);
26471b4ebd2SPeter Brune         }
265b000cd8dSPeter Brune         if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
2668a430afbSPeter Brune           t1 = .5*(g - f) - lambda*initslope;
2678a430afbSPeter Brune           t2 = .5*(gprev  - f) - lambdaprev*initslope;
26871b4ebd2SPeter Brune           a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
26971b4ebd2SPeter Brune           b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
27071b4ebd2SPeter Brune           d  = b*b - 3*a*initslope;
27171b4ebd2SPeter Brune           if (d < 0.0) d = 0.0;
272f5af7f23SKarl Rupp           if (a == 0.0) lambdatemp = -initslope/(2.0*b);
273f5af7f23SKarl Rupp           else lambdatemp = (-b + PetscSqrtReal(d))/(3.0*a);
274f5af7f23SKarl Rupp 
275b000cd8dSPeter Brune         } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) {
2768a430afbSPeter Brune           lambdatemp = -initslope/(g - f - 2.0*initslope);
277ce94432eSBarry Smith         } else SETERRQ(PetscObjectComm((PetscObject)linesearch), PETSC_ERR_SUP, "unsupported line search order for type bt");
27871b4ebd2SPeter Brune         lambdaprev = lambda;
2798a430afbSPeter Brune         gprev      = g;
28071b4ebd2SPeter Brune         if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
28171b4ebd2SPeter Brune         if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
28271b4ebd2SPeter Brune         else                         lambda     = lambdatemp;
28371b4ebd2SPeter Brune         ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
284b7b2e573SPeter Brune         if (linesearch->ops->viproject) {
285b7b2e573SPeter Brune           ierr = (*linesearch->ops->viproject)(snes,W);CHKERRQ(ierr);
286b7b2e573SPeter Brune         }
287e71169deSBarry Smith         if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
28871b4ebd2SPeter Brune           ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
289bd4a8a71SBarry Smith           if (!objective) {
29071b4ebd2SPeter Brune             ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",
291c69d1a72SBarry Smith                               (double)fnorm,(double)gnorm,(double)ynorm,(double)lambda,(double)initslope);CHKERRQ(ierr);
2928a430afbSPeter Brune           }
293e9b602ebSSatish Balay           ierr         = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION);CHKERRQ(ierr);
29471b4ebd2SPeter Brune           snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
29571b4ebd2SPeter Brune           PetscFunctionReturn(0);
29671b4ebd2SPeter Brune         }
297bd4a8a71SBarry Smith         if (objective) {
2988a430afbSPeter Brune           ierr = SNESComputeObjective(snes,W,&g);CHKERRQ(ierr);
2998a430afbSPeter Brune         } else {
300ce5a860aSPeter Brune           ierr = (*linesearch->ops->snesfunc)(snes,W,G);CHKERRQ(ierr);
3019bd66eb0SPeter Brune           if (linesearch->ops->vinorm) {
3029bd66eb0SPeter Brune             gnorm = fnorm;
3039bd66eb0SPeter Brune             ierr  = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
3049bd66eb0SPeter Brune           } else {
30571b4ebd2SPeter Brune             ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
3068a430afbSPeter Brune           }
307f1ab69e3SPeter Brune           g = PetscSqr(gnorm);
3089bd66eb0SPeter Brune         }
3094a2f8832SBarry Smith         if (PetscIsInfOrNanReal(g)) {
310422a814eSBarry Smith           ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_NANORINF);CHKERRQ(ierr);
311c61ba1e2SPeter Brune           ierr = PetscInfo(snes,"Aborted due to Nan or Inf in function evaluation\n");CHKERRQ(ierr);
312c98378a5SBarry Smith           PetscFunctionReturn(0);
313c98378a5SBarry Smith         }
3148a430afbSPeter Brune         if (.5*g < .5*f + lambda*alpha*initslope) { /* is reduction enough? */
31571b4ebd2SPeter Brune           if (monitor) {
316ea5d4fccSPeter Brune             ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
317bd4a8a71SBarry Smith             if (!objective) {
318b000cd8dSPeter Brune               if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
319c69d1a72SBarry Smith                 ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Cubically determined step, current gnorm %14.12e lambda=%18.16e\n",(double)gnorm,(double)lambda);CHKERRQ(ierr);
32071b4ebd2SPeter Brune               } else {
321c69d1a72SBarry Smith                 ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Quadratically determined step, current gnorm %14.12e lambda=%18.16e\n",(double)gnorm,(double)lambda);CHKERRQ(ierr);
32271b4ebd2SPeter Brune               }
323ea5d4fccSPeter Brune               ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
3248a430afbSPeter Brune             } else {
3258a430afbSPeter Brune               if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
3268a430afbSPeter Brune                 ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Cubically determined step, obj %14.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr);
3278a430afbSPeter Brune               } else {
3288a430afbSPeter Brune                 ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Quadratically determined step, obj %14.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr);
3298a430afbSPeter Brune               }
3308a430afbSPeter Brune               ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
3318a430afbSPeter Brune             }
33271b4ebd2SPeter Brune           }
33371b4ebd2SPeter Brune           break;
334f5af7f23SKarl Rupp         } else if (monitor) {
335ea5d4fccSPeter Brune           ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
336bd4a8a71SBarry Smith           if (!objective) {
337b000cd8dSPeter Brune             if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
338c69d1a72SBarry Smith               ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Cubic step no good, shrinking lambda, current gnorm %12.12e lambda=%18.16e\n",(double)gnorm,(double)lambda);CHKERRQ(ierr);
33971b4ebd2SPeter Brune             } else {
340c69d1a72SBarry Smith               ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Quadratic step no good, shrinking lambda, current gnorm %12.12e lambda=%18.16e\n",(double)gnorm,(double)lambda);CHKERRQ(ierr);
34171b4ebd2SPeter Brune             }
342ea5d4fccSPeter Brune             ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
3438a430afbSPeter Brune           } else {
3448a430afbSPeter Brune             if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
3458a430afbSPeter Brune               ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Cubic step no good, shrinking lambda, obj %12.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr);
3468a430afbSPeter Brune             } else {
3478a430afbSPeter Brune               ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Quadratic step no good, shrinking lambda, obj %12.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr);
3488a430afbSPeter Brune             }
3498a430afbSPeter Brune             ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
3508a430afbSPeter Brune           }
35171b4ebd2SPeter Brune         }
35271b4ebd2SPeter Brune       }
35371b4ebd2SPeter Brune     }
35471b4ebd2SPeter Brune   }
35571b4ebd2SPeter Brune 
35671b4ebd2SPeter Brune   /* postcheck */
3577b1df9c1SPeter Brune   ierr = SNESLineSearchPostCheck(linesearch,X,Y,W,&changed_y,&changed_w);CHKERRQ(ierr);
35871b4ebd2SPeter Brune   if (changed_y) {
35971b4ebd2SPeter Brune     ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
3609bd66eb0SPeter Brune     if (linesearch->ops->viproject) {
3619bd66eb0SPeter Brune       ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
3629bd66eb0SPeter Brune     }
36371b4ebd2SPeter Brune   }
364bd4a8a71SBarry Smith   if (changed_y || changed_w || objective) { /* recompute the function norm if the step has changed or the objective isn't the norm */
365ce5a860aSPeter Brune     ierr = (*linesearch->ops->snesfunc)(snes,W,G);CHKERRQ(ierr);
3669bd66eb0SPeter Brune     if (linesearch->ops->vinorm) {
3679bd66eb0SPeter Brune       gnorm = fnorm;
3689bd66eb0SPeter Brune       ierr  = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
3699bd66eb0SPeter Brune     } else {
3709bd66eb0SPeter Brune       ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
3719bd66eb0SPeter Brune     }
3729bd66eb0SPeter Brune     ierr = VecNorm(Y,NORM_2,&ynorm);CHKERRQ(ierr);
373c98378a5SBarry Smith     if (PetscIsInfOrNanReal(gnorm)) {
374422a814eSBarry Smith       ierr = SNESLineSearchSetReason(linesearch,SNES_LINESEARCH_FAILED_NANORINF);CHKERRQ(ierr);
375c61ba1e2SPeter Brune       ierr = PetscInfo(snes,"Aborted due to Nan or Inf in function evaluation\n");CHKERRQ(ierr);
376c98378a5SBarry Smith       PetscFunctionReturn(0);
377c98378a5SBarry Smith     }
378c427506bSPeter Brune   }
37971b4ebd2SPeter Brune 
38071b4ebd2SPeter Brune   /* copy the solution over */
38171b4ebd2SPeter Brune   ierr = VecCopy(W, X);CHKERRQ(ierr);
382c427506bSPeter Brune   ierr = VecCopy(G, F);CHKERRQ(ierr);
383c427506bSPeter Brune   ierr = VecNorm(X, NORM_2, &xnorm);CHKERRQ(ierr);
384f1c6b773SPeter Brune   ierr = SNESLineSearchSetLambda(linesearch, lambda);CHKERRQ(ierr);
385f1c6b773SPeter Brune   ierr = SNESLineSearchSetNorms(linesearch, xnorm, gnorm, ynorm);CHKERRQ(ierr);
38671b4ebd2SPeter Brune   PetscFunctionReturn(0);
38771b4ebd2SPeter Brune }
38871b4ebd2SPeter Brune 
3897f1410a3SPeter Brune PetscErrorCode SNESLineSearchView_BT(SNESLineSearch linesearch, PetscViewer viewer)
3907f1410a3SPeter Brune {
3917f1410a3SPeter Brune   PetscErrorCode    ierr;
3927f1410a3SPeter Brune   PetscBool         iascii;
393*d7ca06c0SBarry Smith   SNESLineSearch_BT *bt = (SNESLineSearch_BT*)linesearch->data;
394075cc632SBarry Smith 
3957f1410a3SPeter Brune   PetscFunctionBegin;
396251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
3977f1410a3SPeter Brune   if (iascii) {
398b000cd8dSPeter Brune     if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
3997f1410a3SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "  interpolation: cubic\n");CHKERRQ(ierr);
400b000cd8dSPeter Brune     } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) {
4017f1410a3SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "  interpolation: quadratic\n");CHKERRQ(ierr);
4027f1410a3SPeter Brune     }
4037904a332SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer, "  alpha=%e\n", (double)bt->alpha);CHKERRQ(ierr);
4047f1410a3SPeter Brune   }
4057f1410a3SPeter Brune   PetscFunctionReturn(0);
4067f1410a3SPeter Brune }
4077f1410a3SPeter Brune 
408f1c6b773SPeter Brune static PetscErrorCode SNESLineSearchDestroy_BT(SNESLineSearch linesearch)
409731c067cSJed Brown {
410731c067cSJed Brown   PetscErrorCode ierr;
41171b4ebd2SPeter Brune 
41271b4ebd2SPeter Brune   PetscFunctionBegin;
413731c067cSJed Brown   ierr = PetscFree(linesearch->data);CHKERRQ(ierr);
41471b4ebd2SPeter Brune   PetscFunctionReturn(0);
41571b4ebd2SPeter Brune }
41671b4ebd2SPeter Brune 
4174416b707SBarry Smith static PetscErrorCode SNESLineSearchSetFromOptions_BT(PetscOptionItems *PetscOptionsObject,SNESLineSearch linesearch)
41871b4ebd2SPeter Brune {
41971b4ebd2SPeter Brune   PetscErrorCode    ierr;
420eb23ba39SBarry Smith   SNESLineSearch_BT *bt = (SNESLineSearch_BT*)linesearch->data;
42171b4ebd2SPeter Brune 
4226e111a19SKarl Rupp   PetscFunctionBegin;
423e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"SNESLineSearch BT options");CHKERRQ(ierr);
4240298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_linesearch_alpha",   "Descent tolerance",        "SNESLineSearchBT", bt->alpha, &bt->alpha, NULL);CHKERRQ(ierr);
42571b4ebd2SPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
42671b4ebd2SPeter Brune   PetscFunctionReturn(0);
42771b4ebd2SPeter Brune }
42871b4ebd2SPeter Brune 
429954494b2SJed Brown /*MC
430db609ea7SPeter Brune    SNESLINESEARCHBT - Backtracking line search.
431954494b2SJed Brown 
432db609ea7SPeter Brune    This line search finds the minimum of a polynomial fitting of the L2 norm of the
433eb23ba39SBarry Smith    function or the objective function if it is provided with SNESSetObjective(). If this fit does not satisfy the conditions for progress, the interval shrinks
434db609ea7SPeter Brune    and the fit is reattempted at most max_it times or until lambda is below minlambda.
435954494b2SJed Brown 
436cd7522eaSPeter Brune    Options Database Keys:
437cd7522eaSPeter Brune +  -snes_linesearch_alpha<1e-4> - slope descent parameter
438db609ea7SPeter Brune .  -snes_linesearch_damping<1.0> - initial step length
439eb23ba39SBarry Smith .  -snes_linesearch_maxstep <length> - if the length the initial step is larger than this then the
440e1bc860dSBarry Smith                                        step is scaled back to be of this length at the beginning of the line search
441db609ea7SPeter Brune .  -snes_linesearch_max_it<40> - maximum number of shrinking step
442db609ea7SPeter Brune .  -snes_linesearch_minlambda<1e-12> - minimum step length allowed
443cd7522eaSPeter Brune -  -snes_linesearch_order<cubic,quadratic> - order of the approximation
444cd7522eaSPeter Brune 
445954494b2SJed Brown    Level: advanced
446954494b2SJed Brown 
447db609ea7SPeter Brune    Notes:
448db609ea7SPeter Brune    This line search is taken from "Numerical Methods for Unconstrained
449db609ea7SPeter Brune    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
450db609ea7SPeter Brune 
451f1c6b773SPeter Brune .keywords: SNES, SNESLineSearch, damping
452954494b2SJed Brown 
453f1c6b773SPeter Brune .seealso: SNESLineSearchCreate(), SNESLineSearchSetType()
454954494b2SJed Brown M*/
4558cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_BT(SNESLineSearch linesearch)
45671b4ebd2SPeter Brune {
45771b4ebd2SPeter Brune 
458f1c6b773SPeter Brune   SNESLineSearch_BT *bt;
45971b4ebd2SPeter Brune   PetscErrorCode    ierr;
46071b4ebd2SPeter Brune 
46171b4ebd2SPeter Brune   PetscFunctionBegin;
462f1c6b773SPeter Brune   linesearch->ops->apply          = SNESLineSearchApply_BT;
463f1c6b773SPeter Brune   linesearch->ops->destroy        = SNESLineSearchDestroy_BT;
464f1c6b773SPeter Brune   linesearch->ops->setfromoptions = SNESLineSearchSetFromOptions_BT;
4650298fd71SBarry Smith   linesearch->ops->reset          = NULL;
4667f1410a3SPeter Brune   linesearch->ops->view           = SNESLineSearchView_BT;
4670298fd71SBarry Smith   linesearch->ops->setup          = NULL;
46871b4ebd2SPeter Brune 
469b00a9115SJed Brown   ierr = PetscNewLog(linesearch,&bt);CHKERRQ(ierr);
470f5af7f23SKarl Rupp 
47171b4ebd2SPeter Brune   linesearch->data    = (void*)bt;
47271b4ebd2SPeter Brune   linesearch->max_its = 40;
473b000cd8dSPeter Brune   linesearch->order   = SNES_LINESEARCH_ORDER_CUBIC;
47471b4ebd2SPeter Brune   bt->alpha           = 1e-4;
47571b4ebd2SPeter Brune   PetscFunctionReturn(0);
47671b4ebd2SPeter Brune }
477