xref: /petsc/src/snes/linesearch/impls/bt/linesearchbt.c (revision dcf2fd19addf68f961057cf0cf7f6217b6b499d5)
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 
871b4ebd2SPeter Brune #undef __FUNCT__
92f4102e2SPeter Brune #define __FUNCT__ "SNESLineSearchBTSetAlpha"
102f4102e2SPeter Brune /*@
112f4102e2SPeter Brune    SNESLineSearchBTSetAlpha - Sets the descent parameter, alpha, in the BT linesearch variant.
122f4102e2SPeter Brune 
132f4102e2SPeter Brune    Input Parameters:
142f4102e2SPeter Brune +  linesearch - linesearch context
152f4102e2SPeter Brune -  alpha - The descent parameter
162f4102e2SPeter Brune 
172f4102e2SPeter Brune    Level: intermediate
182f4102e2SPeter Brune 
191a4f838cSPeter Brune .seealso: SNESLineSearchSetLambda(), SNESLineSearchGetTolerances() SNESLINESEARCHBT
202f4102e2SPeter Brune @*/
212f4102e2SPeter Brune PetscErrorCode SNESLineSearchBTSetAlpha(SNESLineSearch linesearch, PetscReal alpha)
222f4102e2SPeter Brune {
232f4102e2SPeter Brune   SNESLineSearch_BT *bt;
246e111a19SKarl Rupp 
252f4102e2SPeter Brune   PetscFunctionBegin;
262f4102e2SPeter Brune   PetscValidHeaderSpecific(linesearch,SNESLINESEARCH_CLASSID,1);
272f4102e2SPeter Brune   bt        = (SNESLineSearch_BT*)linesearch->data;
282f4102e2SPeter Brune   bt->alpha = alpha;
292f4102e2SPeter Brune   PetscFunctionReturn(0);
302f4102e2SPeter Brune }
312f4102e2SPeter Brune 
322f4102e2SPeter Brune 
332f4102e2SPeter Brune #undef __FUNCT__
342f4102e2SPeter Brune #define __FUNCT__ "SNESLineSearchBTGetAlpha"
352f4102e2SPeter Brune /*@
362f4102e2SPeter Brune    SNESLineSearchBTGetAlpha - Gets the descent parameter, alpha, in the BT linesearch variant.
372f4102e2SPeter Brune 
382f4102e2SPeter Brune    Input Parameters:
392f4102e2SPeter Brune .  linesearch - linesearch context
408e557f58SPeter Brune 
418e557f58SPeter Brune    Output Parameters:
422f4102e2SPeter Brune .  alpha - The descent parameter
432f4102e2SPeter Brune 
442f4102e2SPeter Brune    Level: intermediate
452f4102e2SPeter Brune 
461a4f838cSPeter Brune .seealso: SNESLineSearchGetLambda(), SNESLineSearchGetTolerances() SNESLINESEARCHBT
472f4102e2SPeter Brune @*/
482f4102e2SPeter Brune PetscErrorCode SNESLineSearchBTGetAlpha(SNESLineSearch linesearch, PetscReal *alpha)
492f4102e2SPeter Brune {
502f4102e2SPeter Brune   SNESLineSearch_BT *bt;
516e111a19SKarl Rupp 
522f4102e2SPeter Brune   PetscFunctionBegin;
532f4102e2SPeter Brune   PetscValidHeaderSpecific(linesearch,SNESLINESEARCH_CLASSID,1);
542f4102e2SPeter Brune   bt     = (SNESLineSearch_BT*)linesearch->data;
552f4102e2SPeter Brune   *alpha = bt->alpha;
562f4102e2SPeter Brune   PetscFunctionReturn(0);
572f4102e2SPeter Brune }
582f4102e2SPeter Brune 
592f4102e2SPeter Brune #undef __FUNCT__
60f1c6b773SPeter Brune #define __FUNCT__ "SNESLineSearchApply_BT"
61f1c6b773SPeter Brune static PetscErrorCode  SNESLineSearchApply_BT(SNESLineSearch linesearch)
6271b4ebd2SPeter Brune {
6371b4ebd2SPeter Brune   PetscBool         changed_y,changed_w;
6471b4ebd2SPeter Brune   PetscErrorCode    ierr;
6571b4ebd2SPeter Brune   Vec               X,F,Y,W,G;
6671b4ebd2SPeter Brune   SNES              snes;
678a430afbSPeter Brune   PetscReal         fnorm, xnorm, ynorm, gnorm;
683b288129SPeter Brune   PetscReal         lambda,lambdatemp,lambdaprev,minlambda,maxstep,initslope,alpha,stol;
69dfcd3828SPeter Brune   PetscReal         t1,t2,a,b,d;
708a430afbSPeter Brune   PetscReal         f;
718a430afbSPeter Brune   PetscReal         g,gprev;
7271b4ebd2SPeter Brune   PetscViewer       monitor;
7371b4ebd2SPeter Brune   PetscInt          max_its,count;
74f1c6b773SPeter Brune   SNESLineSearch_BT *bt;
7571b4ebd2SPeter Brune   Mat               jac;
76bd4a8a71SBarry Smith   PetscErrorCode    (*objective)(SNES,Vec,PetscReal*,void*);
7771b4ebd2SPeter Brune 
7871b4ebd2SPeter Brune   PetscFunctionBegin;
79f1c6b773SPeter Brune   ierr = SNESLineSearchGetVecs(linesearch, &X, &F, &Y, &W, &G);CHKERRQ(ierr);
80f1c6b773SPeter Brune   ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
81f1c6b773SPeter Brune   ierr = SNESLineSearchGetLambda(linesearch, &lambda);CHKERRQ(ierr);
82f1c6b773SPeter Brune   ierr = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr);
83*dcf2fd19SBarry Smith   ierr = SNESLineSearchGetDefaultMonitor(linesearch, &monitor);CHKERRQ(ierr);
840298fd71SBarry Smith   ierr = SNESLineSearchGetTolerances(linesearch,&minlambda,&maxstep,NULL,NULL,NULL,&max_its);CHKERRQ(ierr);
850298fd71SBarry Smith   ierr = SNESGetTolerances(snes,NULL,NULL,&stol,NULL,NULL);CHKERRQ(ierr);
860298fd71SBarry Smith   ierr = SNESGetObjective(snes,&objective,NULL);CHKERRQ(ierr);
87f1c6b773SPeter Brune   bt   = (SNESLineSearch_BT*)linesearch->data;
8871b4ebd2SPeter Brune   alpha = bt->alpha;
8971b4ebd2SPeter Brune 
900298fd71SBarry Smith   ierr = SNESGetJacobian(snes, &jac, NULL, NULL, NULL);CHKERRQ(ierr);
91ce94432eSBarry Smith   if (!jac && !objective) SETERRQ(PetscObjectComm((PetscObject)linesearch), PETSC_ERR_USER, "SNESLineSearchBT requires a Jacobian matrix");
92c69d1a72SBarry Smith 
937b1df9c1SPeter Brune   ierr = SNESLineSearchPreCheck(linesearch,X,Y,&changed_y);CHKERRQ(ierr);
94422a814eSBarry Smith   ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED);CHKERRQ(ierr);
9571b4ebd2SPeter Brune 
963b288129SPeter Brune   ierr = VecNormBegin(Y, NORM_2, &ynorm);CHKERRQ(ierr);
973b288129SPeter Brune   ierr = VecNormBegin(X, NORM_2, &xnorm);CHKERRQ(ierr);
983b288129SPeter Brune   ierr = VecNormEnd(Y, NORM_2, &ynorm);CHKERRQ(ierr);
993b288129SPeter Brune   ierr = VecNormEnd(X, NORM_2, &xnorm);CHKERRQ(ierr);
1003b288129SPeter Brune 
10171b4ebd2SPeter Brune   if (ynorm == 0.0) {
10271b4ebd2SPeter Brune     if (monitor) {
103ea5d4fccSPeter Brune       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
10471b4ebd2SPeter Brune       ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Initial direction and size is 0\n");CHKERRQ(ierr);
105ea5d4fccSPeter Brune       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
10671b4ebd2SPeter Brune     }
10771b4ebd2SPeter Brune     ierr = VecCopy(X,W);CHKERRQ(ierr);
10871b4ebd2SPeter Brune     ierr = VecCopy(F,G);CHKERRQ(ierr);
10971cee68bSPeter Brune     ierr = SNESLineSearchSetNorms(linesearch,xnorm,fnorm,ynorm);CHKERRQ(ierr);
110e9b602ebSSatish Balay     ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT);CHKERRQ(ierr);
11171b4ebd2SPeter Brune     PetscFunctionReturn(0);
11271b4ebd2SPeter Brune   }
11371b4ebd2SPeter Brune   if (ynorm > maxstep) {        /* Step too big, so scale back */
11471b4ebd2SPeter Brune     if (monitor) {
115ea5d4fccSPeter Brune       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
116c69d1a72SBarry Smith       ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Scaling step by %14.12e old ynorm %14.12e\n", (double)(maxstep/ynorm),(double)ynorm);CHKERRQ(ierr);
117ea5d4fccSPeter Brune       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
11871b4ebd2SPeter Brune     }
11971b4ebd2SPeter Brune     ierr  = VecScale(Y,maxstep/(ynorm));CHKERRQ(ierr);
12071b4ebd2SPeter Brune     ynorm = maxstep;
12171b4ebd2SPeter Brune   }
1228a430afbSPeter Brune 
1238a430afbSPeter Brune   /* if the SNES has an objective set, use that instead of the function value */
124bd4a8a71SBarry Smith   if (objective) {
1258a430afbSPeter Brune     ierr = SNESComputeObjective(snes,X,&f);CHKERRQ(ierr);
1268a430afbSPeter Brune   } else {
1278a430afbSPeter Brune     f = fnorm*fnorm;
1288a430afbSPeter Brune   }
1298a430afbSPeter Brune 
1308a430afbSPeter Brune   /* compute the initial slope */
131bd4a8a71SBarry Smith   if (objective) {
1328a430afbSPeter Brune     /* slope comes from the function (assumed to be the gradient of the objective */
13367392de3SBarry Smith     ierr = VecDotRealPart(Y,F,&initslope);CHKERRQ(ierr);
1348a430afbSPeter Brune   } else {
1358a430afbSPeter Brune     /* slope comes from the normal equations */
13671b4ebd2SPeter Brune     ierr = MatMult(jac,Y,W);CHKERRQ(ierr);
13767392de3SBarry Smith     ierr = VecDotRealPart(F,W,&initslope);CHKERRQ(ierr);
13871b4ebd2SPeter Brune     if (initslope > 0.0)  initslope = -initslope;
13971b4ebd2SPeter Brune     if (initslope == 0.0) initslope = -1.0;
1408a430afbSPeter Brune   }
14171b4ebd2SPeter Brune 
142c427506bSPeter Brune   ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
1439bd66eb0SPeter Brune   if (linesearch->ops->viproject) {
1449bd66eb0SPeter Brune     ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
1459bd66eb0SPeter Brune   }
14671b4ebd2SPeter Brune   if (snes->nfuncs >= snes->max_funcs) {
14771b4ebd2SPeter Brune     ierr         = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr);
14871b4ebd2SPeter Brune     snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
149e9b602ebSSatish Balay     ierr         = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION);CHKERRQ(ierr);
15071b4ebd2SPeter Brune     PetscFunctionReturn(0);
15171b4ebd2SPeter Brune   }
1528a430afbSPeter Brune 
153bd4a8a71SBarry Smith   if (objective) {
1548a430afbSPeter Brune     ierr = SNESComputeObjective(snes,W,&g);CHKERRQ(ierr);
1558a430afbSPeter Brune   } else {
156ce5a860aSPeter Brune     ierr = (*linesearch->ops->snesfunc)(snes,W,G);CHKERRQ(ierr);
1579bd66eb0SPeter Brune     if (linesearch->ops->vinorm) {
1589bd66eb0SPeter Brune       gnorm = fnorm;
1599bd66eb0SPeter Brune       ierr  = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
1609bd66eb0SPeter Brune     } else {
16171b4ebd2SPeter Brune       ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
1628a430afbSPeter Brune     }
16379e7e81bSJed Brown     g = PetscSqr(gnorm);
1649bd66eb0SPeter Brune   }
165*dcf2fd19SBarry Smith   ierr = SNESLineSearchMonitor(linesearch);CHKERRQ(ierr);
1669bd66eb0SPeter Brune 
167c98378a5SBarry Smith   if (PetscIsInfOrNanReal(g)) {
168422a814eSBarry Smith     ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_NANORINF);CHKERRQ(ierr);
169c61ba1e2SPeter Brune     ierr = PetscInfo(snes,"Aborted due to Nan or Inf in function evaluation\n");CHKERRQ(ierr);
170c98378a5SBarry Smith     PetscFunctionReturn(0);
171c98378a5SBarry Smith   }
172bd4a8a71SBarry Smith   if (!objective) {
173c69d1a72SBarry Smith     ierr = PetscInfo2(snes,"Initial fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm);CHKERRQ(ierr);
1748a430afbSPeter Brune   }
1758a430afbSPeter Brune   if (.5*g <= .5*f + lambda*alpha*initslope) { /* Sufficient reduction or step tolerance convergence */
17671b4ebd2SPeter Brune     if (monitor) {
177ea5d4fccSPeter Brune       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
178bd4a8a71SBarry Smith       if (!objective) {
179c69d1a72SBarry Smith         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Using full step: fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm);CHKERRQ(ierr);
1808a430afbSPeter Brune       } else {
1818a430afbSPeter Brune         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Using full step: obj0 %14.12e obj %14.12e\n", (double)f, (double)g);CHKERRQ(ierr);
1828a430afbSPeter Brune       }
183ea5d4fccSPeter Brune       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
18471b4ebd2SPeter Brune     }
18571b4ebd2SPeter Brune   } else {
186c21ba15cSPeter Brune     /* Since the full step didn't work and the step is tiny, quit */
187c21ba15cSPeter Brune     if (stol*xnorm > ynorm) {
188ced04f9dSPeter Brune       ierr = SNESLineSearchSetNorms(linesearch,xnorm,fnorm,ynorm);CHKERRQ(ierr);
189e9b602ebSSatish Balay       ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT);CHKERRQ(ierr);
190c61ba1e2SPeter Brune       if (monitor) {
191c61ba1e2SPeter Brune         ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
19208ed2907SPeter Brune         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Aborted due to ynorm < stol*xnorm (%14.12e < %14.12e) and inadequate full step.\n",(double)ynorm,(double)stol*xnorm);CHKERRQ(ierr);
193c61ba1e2SPeter Brune         ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
194c61ba1e2SPeter Brune       }
195c21ba15cSPeter Brune       PetscFunctionReturn(0);
196c21ba15cSPeter Brune     }
19771b4ebd2SPeter Brune     /* Fit points with quadratic */
1988a430afbSPeter Brune     lambdatemp = -initslope/(g - f - 2.0*lambda*initslope);
19971b4ebd2SPeter Brune     lambdaprev = lambda;
2008a430afbSPeter Brune     gprev      = g;
20171b4ebd2SPeter Brune     if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
20271b4ebd2SPeter Brune     if (lambdatemp <= .1*lambda) lambda = .1*lambda;
20371b4ebd2SPeter Brune     else                         lambda = lambdatemp;
20471b4ebd2SPeter Brune 
20571b4ebd2SPeter Brune     ierr  = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
2069bd66eb0SPeter Brune     if (linesearch->ops->viproject) {
2079bd66eb0SPeter Brune       ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
2089bd66eb0SPeter Brune     }
20971b4ebd2SPeter Brune     if (snes->nfuncs >= snes->max_funcs) {
21071b4ebd2SPeter Brune       ierr         = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr);
21171b4ebd2SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
212e9b602ebSSatish Balay       ierr         = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION);CHKERRQ(ierr);
21371b4ebd2SPeter Brune       PetscFunctionReturn(0);
21471b4ebd2SPeter Brune     }
215bd4a8a71SBarry Smith     if (objective) {
2168a430afbSPeter Brune       ierr = SNESComputeObjective(snes,W,&g);CHKERRQ(ierr);
2178a430afbSPeter Brune     } else {
218ce5a860aSPeter Brune       ierr = (*linesearch->ops->snesfunc)(snes,W,G);CHKERRQ(ierr);
2199bd66eb0SPeter Brune       if (linesearch->ops->vinorm) {
2209bd66eb0SPeter Brune         gnorm = fnorm;
2219bd66eb0SPeter Brune         ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
2229bd66eb0SPeter Brune       } else {
22371b4ebd2SPeter Brune         ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
2249bd66eb0SPeter Brune       }
225f1ab69e3SPeter Brune       g = PetscSqr(gnorm);
2268a430afbSPeter Brune     }
227c98378a5SBarry Smith     if (PetscIsInfOrNanReal(g)) {
228422a814eSBarry Smith       ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_NANORINF);CHKERRQ(ierr);
229c61ba1e2SPeter Brune       ierr = PetscInfo(snes,"Aborted due to Nan or Inf in function evaluation\n");CHKERRQ(ierr);
230c98378a5SBarry Smith       PetscFunctionReturn(0);
231c98378a5SBarry Smith     }
23271b4ebd2SPeter Brune     if (monitor) {
233ea5d4fccSPeter Brune       ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
234bd4a8a71SBarry Smith       if (!objective) {
235c69d1a72SBarry Smith         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: gnorm after quadratic fit %14.12e\n",(double)gnorm);CHKERRQ(ierr);
2368a430afbSPeter Brune       } else {
2378a430afbSPeter Brune         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: obj after quadratic fit %14.12e\n",(double)g);CHKERRQ(ierr);
2388a430afbSPeter Brune       }
239ea5d4fccSPeter Brune       ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
24071b4ebd2SPeter Brune     }
2418a430afbSPeter Brune     if (.5*g < .5*f + lambda*alpha*initslope) { /* sufficient reduction */
24271b4ebd2SPeter Brune       if (monitor) {
243ea5d4fccSPeter Brune         ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
24471b4ebd2SPeter Brune         ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Quadratically determined step, lambda=%18.16e\n",(double)lambda);CHKERRQ(ierr);
245ea5d4fccSPeter Brune         ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
24671b4ebd2SPeter Brune       }
24771b4ebd2SPeter Brune     } else {
24871b4ebd2SPeter Brune       /* Fit points with cubic */
24971b4ebd2SPeter Brune       for (count = 0; count < max_its; count++) {
25071b4ebd2SPeter Brune         if (lambda <= minlambda) {
25171b4ebd2SPeter Brune           if (monitor) {
252ea5d4fccSPeter Brune             ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
25371b4ebd2SPeter Brune             ierr = PetscViewerASCIIPrintf(monitor,"    Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr);
254bd4a8a71SBarry Smith             if (!objective) {
25571b4ebd2SPeter Brune               ierr = PetscViewerASCIIPrintf(monitor,
25671b4ebd2SPeter Brune                                             "    Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",
257c69d1a72SBarry Smith                                             (double)fnorm, (double)gnorm, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope);CHKERRQ(ierr);
2588a430afbSPeter Brune             } else {
2598a430afbSPeter Brune               ierr = PetscViewerASCIIPrintf(monitor,
2608a430afbSPeter Brune                                             "    Line search: obj(0)=%18.16e, obj=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",
2618a430afbSPeter Brune                                             (double)f, (double)g, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope);CHKERRQ(ierr);
2628a430afbSPeter Brune             }
263ea5d4fccSPeter Brune             ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
26471b4ebd2SPeter Brune           }
265e9b602ebSSatish Balay           ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT);CHKERRQ(ierr);
26671b4ebd2SPeter Brune           PetscFunctionReturn(0);
26771b4ebd2SPeter Brune         }
268b000cd8dSPeter Brune         if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
2698a430afbSPeter Brune           t1 = .5*(g - f) - lambda*initslope;
2708a430afbSPeter Brune           t2 = .5*(gprev  - f) - lambdaprev*initslope;
27171b4ebd2SPeter Brune           a  = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
27271b4ebd2SPeter Brune           b  = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
27371b4ebd2SPeter Brune           d  = b*b - 3*a*initslope;
27471b4ebd2SPeter Brune           if (d < 0.0) d = 0.0;
275f5af7f23SKarl Rupp           if (a == 0.0) lambdatemp = -initslope/(2.0*b);
276f5af7f23SKarl Rupp           else lambdatemp = (-b + PetscSqrtReal(d))/(3.0*a);
277f5af7f23SKarl Rupp 
278b000cd8dSPeter Brune         } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) {
2798a430afbSPeter Brune           lambdatemp = -initslope/(g - f - 2.0*initslope);
280ce94432eSBarry Smith         } else SETERRQ(PetscObjectComm((PetscObject)linesearch), PETSC_ERR_SUP, "unsupported line search order for type bt");
28171b4ebd2SPeter Brune         lambdaprev = lambda;
2828a430afbSPeter Brune         gprev      = g;
28371b4ebd2SPeter Brune         if (lambdatemp > .5*lambda)  lambdatemp = .5*lambda;
28471b4ebd2SPeter Brune         if (lambdatemp <= .1*lambda) lambda     = .1*lambda;
28571b4ebd2SPeter Brune         else                         lambda     = lambdatemp;
28671b4ebd2SPeter Brune         ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
287b7b2e573SPeter Brune         if (linesearch->ops->viproject) {
288b7b2e573SPeter Brune           ierr = (*linesearch->ops->viproject)(snes,W);CHKERRQ(ierr);
289b7b2e573SPeter Brune         }
29071b4ebd2SPeter Brune         if (snes->nfuncs >= snes->max_funcs) {
29171b4ebd2SPeter Brune           ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr);
292bd4a8a71SBarry Smith           if (!objective) {
29371b4ebd2SPeter Brune             ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",
294c69d1a72SBarry Smith                               (double)fnorm,(double)gnorm,(double)ynorm,(double)lambda,(double)initslope);CHKERRQ(ierr);
2958a430afbSPeter Brune           }
296e9b602ebSSatish Balay           ierr         = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION);CHKERRQ(ierr);
29771b4ebd2SPeter Brune           snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
29871b4ebd2SPeter Brune           PetscFunctionReturn(0);
29971b4ebd2SPeter Brune         }
300bd4a8a71SBarry Smith         if (objective) {
3018a430afbSPeter Brune           ierr = SNESComputeObjective(snes,W,&g);CHKERRQ(ierr);
3028a430afbSPeter Brune         } else {
303ce5a860aSPeter Brune           ierr = (*linesearch->ops->snesfunc)(snes,W,G);CHKERRQ(ierr);
3049bd66eb0SPeter Brune           if (linesearch->ops->vinorm) {
3059bd66eb0SPeter Brune             gnorm = fnorm;
3069bd66eb0SPeter Brune             ierr  = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
3079bd66eb0SPeter Brune           } else {
30871b4ebd2SPeter Brune             ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
3098a430afbSPeter Brune           }
310f1ab69e3SPeter Brune           g = PetscSqr(gnorm);
3119bd66eb0SPeter Brune         }
312c98378a5SBarry Smith         if (PetscIsInfOrNanReal(gnorm)) {
313422a814eSBarry Smith           ierr = SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_NANORINF);CHKERRQ(ierr);
314c61ba1e2SPeter Brune           ierr = PetscInfo(snes,"Aborted due to Nan or Inf in function evaluation\n");CHKERRQ(ierr);
315c98378a5SBarry Smith           PetscFunctionReturn(0);
316c98378a5SBarry Smith         }
3178a430afbSPeter Brune         if (.5*g < .5*f + lambda*alpha*initslope) { /* is reduction enough? */
31871b4ebd2SPeter Brune           if (monitor) {
319ea5d4fccSPeter Brune             ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
320bd4a8a71SBarry Smith             if (!objective) {
321b000cd8dSPeter Brune               if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
322c69d1a72SBarry Smith                 ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Cubically determined step, current gnorm %14.12e lambda=%18.16e\n",(double)gnorm,(double)lambda);CHKERRQ(ierr);
32371b4ebd2SPeter Brune               } else {
324c69d1a72SBarry Smith                 ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Quadratically determined step, current gnorm %14.12e lambda=%18.16e\n",(double)gnorm,(double)lambda);CHKERRQ(ierr);
32571b4ebd2SPeter Brune               }
326ea5d4fccSPeter Brune               ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
3278a430afbSPeter Brune             } else {
3288a430afbSPeter Brune               if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
3298a430afbSPeter Brune                 ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Cubically determined step, obj %14.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr);
3308a430afbSPeter Brune               } else {
3318a430afbSPeter Brune                 ierr = PetscViewerASCIIPrintf(monitor,"    Line search: Quadratically determined step, obj %14.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr);
3328a430afbSPeter Brune               }
3338a430afbSPeter Brune               ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
3348a430afbSPeter Brune             }
33571b4ebd2SPeter Brune           }
33671b4ebd2SPeter Brune           break;
337f5af7f23SKarl Rupp         } else if (monitor) {
338ea5d4fccSPeter Brune           ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
339bd4a8a71SBarry Smith           if (!objective) {
340b000cd8dSPeter Brune             if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
341c69d1a72SBarry 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);
34271b4ebd2SPeter Brune             } else {
343c69d1a72SBarry 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);
34471b4ebd2SPeter Brune             }
345ea5d4fccSPeter Brune             ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
3468a430afbSPeter Brune           } else {
3478a430afbSPeter Brune             if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
3488a430afbSPeter 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);
3498a430afbSPeter Brune             } else {
3508a430afbSPeter 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);
3518a430afbSPeter Brune             }
3528a430afbSPeter Brune             ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr);
3538a430afbSPeter Brune           }
35471b4ebd2SPeter Brune         }
35571b4ebd2SPeter Brune       }
35671b4ebd2SPeter Brune     }
35771b4ebd2SPeter Brune   }
35871b4ebd2SPeter Brune 
35971b4ebd2SPeter Brune   /* postcheck */
3607b1df9c1SPeter Brune   ierr = SNESLineSearchPostCheck(linesearch,X,Y,W,&changed_y,&changed_w);CHKERRQ(ierr);
36171b4ebd2SPeter Brune   if (changed_y) {
36271b4ebd2SPeter Brune     ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr);
3639bd66eb0SPeter Brune     if (linesearch->ops->viproject) {
3649bd66eb0SPeter Brune       ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr);
3659bd66eb0SPeter Brune     }
36671b4ebd2SPeter Brune   }
367bd4a8a71SBarry Smith   if (changed_y || changed_w || objective) { /* recompute the function norm if the step has changed or the objective isn't the norm */
368ce5a860aSPeter Brune     ierr = (*linesearch->ops->snesfunc)(snes,W,G);CHKERRQ(ierr);
3699bd66eb0SPeter Brune     if (linesearch->ops->vinorm) {
3709bd66eb0SPeter Brune       gnorm = fnorm;
3719bd66eb0SPeter Brune       ierr  = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr);
3729bd66eb0SPeter Brune     } else {
3739bd66eb0SPeter Brune       ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr);
3749bd66eb0SPeter Brune     }
3759bd66eb0SPeter Brune     ierr = VecNorm(Y,NORM_2,&ynorm);CHKERRQ(ierr);
376c98378a5SBarry Smith     if (PetscIsInfOrNanReal(gnorm)) {
377422a814eSBarry Smith       ierr = SNESLineSearchSetReason(linesearch,SNES_LINESEARCH_FAILED_NANORINF);CHKERRQ(ierr);
378c61ba1e2SPeter Brune       ierr = PetscInfo(snes,"Aborted due to Nan or Inf in function evaluation\n");CHKERRQ(ierr);
379c98378a5SBarry Smith       PetscFunctionReturn(0);
380c98378a5SBarry Smith     }
381c427506bSPeter Brune   }
38271b4ebd2SPeter Brune 
38371b4ebd2SPeter Brune   /* copy the solution over */
38471b4ebd2SPeter Brune   ierr = VecCopy(W, X);CHKERRQ(ierr);
385c427506bSPeter Brune   ierr = VecCopy(G, F);CHKERRQ(ierr);
386c427506bSPeter Brune   ierr = VecNorm(X, NORM_2, &xnorm);CHKERRQ(ierr);
387f1c6b773SPeter Brune   ierr = SNESLineSearchSetLambda(linesearch, lambda);CHKERRQ(ierr);
388f1c6b773SPeter Brune   ierr = SNESLineSearchSetNorms(linesearch, xnorm, gnorm, ynorm);CHKERRQ(ierr);
38971b4ebd2SPeter Brune   PetscFunctionReturn(0);
39071b4ebd2SPeter Brune }
39171b4ebd2SPeter Brune 
39271b4ebd2SPeter Brune #undef __FUNCT__
3937f1410a3SPeter Brune #define __FUNCT__ "SNESLineSearchView_BT"
3947f1410a3SPeter Brune PetscErrorCode SNESLineSearchView_BT(SNESLineSearch linesearch, PetscViewer viewer)
3957f1410a3SPeter Brune {
3967f1410a3SPeter Brune   PetscErrorCode    ierr;
3977f1410a3SPeter Brune   PetscBool         iascii;
3987f1410a3SPeter Brune   SNESLineSearch_BT *bt;
399075cc632SBarry Smith 
4007f1410a3SPeter Brune   PetscFunctionBegin;
401251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
4027f1410a3SPeter Brune   bt   = (SNESLineSearch_BT*)linesearch->data;
4037f1410a3SPeter Brune   if (iascii) {
404b000cd8dSPeter Brune     if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) {
4057f1410a3SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "  interpolation: cubic\n");CHKERRQ(ierr);
406b000cd8dSPeter Brune     } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) {
4077f1410a3SPeter Brune       ierr = PetscViewerASCIIPrintf(viewer, "  interpolation: quadratic\n");CHKERRQ(ierr);
4087f1410a3SPeter Brune     }
4097904a332SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer, "  alpha=%e\n", (double)bt->alpha);CHKERRQ(ierr);
4107f1410a3SPeter Brune   }
4117f1410a3SPeter Brune   PetscFunctionReturn(0);
4127f1410a3SPeter Brune }
4137f1410a3SPeter Brune 
4147f1410a3SPeter Brune 
4157f1410a3SPeter Brune #undef __FUNCT__
416f1c6b773SPeter Brune #define __FUNCT__ "SNESLineSearchDestroy_BT"
417f1c6b773SPeter Brune static PetscErrorCode SNESLineSearchDestroy_BT(SNESLineSearch linesearch)
418731c067cSJed Brown {
419731c067cSJed Brown   PetscErrorCode ierr;
42071b4ebd2SPeter Brune 
42171b4ebd2SPeter Brune   PetscFunctionBegin;
422731c067cSJed Brown   ierr = PetscFree(linesearch->data);CHKERRQ(ierr);
42371b4ebd2SPeter Brune   PetscFunctionReturn(0);
42471b4ebd2SPeter Brune }
42571b4ebd2SPeter Brune 
42671b4ebd2SPeter Brune 
42771b4ebd2SPeter Brune #undef __FUNCT__
428f1c6b773SPeter Brune #define __FUNCT__ "SNESLineSearchSetFromOptions_BT"
4294416b707SBarry Smith static PetscErrorCode SNESLineSearchSetFromOptions_BT(PetscOptionItems *PetscOptionsObject,SNESLineSearch linesearch)
43071b4ebd2SPeter Brune {
43171b4ebd2SPeter Brune 
43271b4ebd2SPeter Brune   PetscErrorCode    ierr;
433eb23ba39SBarry Smith   SNESLineSearch_BT *bt = (SNESLineSearch_BT*)linesearch->data;
43471b4ebd2SPeter Brune 
4356e111a19SKarl Rupp   PetscFunctionBegin;
436e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"SNESLineSearch BT options");CHKERRQ(ierr);
4370298fd71SBarry Smith   ierr = PetscOptionsReal("-snes_linesearch_alpha",   "Descent tolerance",        "SNESLineSearchBT", bt->alpha, &bt->alpha, NULL);CHKERRQ(ierr);
43871b4ebd2SPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
43971b4ebd2SPeter Brune   PetscFunctionReturn(0);
44071b4ebd2SPeter Brune }
44171b4ebd2SPeter Brune 
44271b4ebd2SPeter Brune 
44371b4ebd2SPeter Brune #undef __FUNCT__
444f1c6b773SPeter Brune #define __FUNCT__ "SNESLineSearchCreate_BT"
445954494b2SJed Brown /*MC
446db609ea7SPeter Brune    SNESLINESEARCHBT - Backtracking line search.
447954494b2SJed Brown 
448db609ea7SPeter Brune    This line search finds the minimum of a polynomial fitting of the L2 norm of the
449eb23ba39SBarry 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
450db609ea7SPeter Brune    and the fit is reattempted at most max_it times or until lambda is below minlambda.
451954494b2SJed Brown 
452cd7522eaSPeter Brune    Options Database Keys:
453cd7522eaSPeter Brune +  -snes_linesearch_alpha<1e-4> - slope descent parameter
454db609ea7SPeter Brune .  -snes_linesearch_damping<1.0> - initial step length
455eb23ba39SBarry Smith .  -snes_linesearch_maxstep <length> - if the length the initial step is larger than this then the
456e1bc860dSBarry Smith                                        step is scaled back to be of this length at the beginning of the line search
457db609ea7SPeter Brune .  -snes_linesearch_max_it<40> - maximum number of shrinking step
458db609ea7SPeter Brune .  -snes_linesearch_minlambda<1e-12> - minimum step length allowed
459cd7522eaSPeter Brune -  -snes_linesearch_order<cubic,quadratic> - order of the approximation
460cd7522eaSPeter Brune 
461954494b2SJed Brown    Level: advanced
462954494b2SJed Brown 
463db609ea7SPeter Brune    Notes:
464db609ea7SPeter Brune    This line search is taken from "Numerical Methods for Unconstrained
465db609ea7SPeter Brune    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
466db609ea7SPeter Brune 
467f1c6b773SPeter Brune .keywords: SNES, SNESLineSearch, damping
468954494b2SJed Brown 
469f1c6b773SPeter Brune .seealso: SNESLineSearchCreate(), SNESLineSearchSetType()
470954494b2SJed Brown M*/
4718cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_BT(SNESLineSearch linesearch)
47271b4ebd2SPeter Brune {
47371b4ebd2SPeter Brune 
474f1c6b773SPeter Brune   SNESLineSearch_BT *bt;
47571b4ebd2SPeter Brune   PetscErrorCode    ierr;
47671b4ebd2SPeter Brune 
47771b4ebd2SPeter Brune   PetscFunctionBegin;
478f1c6b773SPeter Brune   linesearch->ops->apply          = SNESLineSearchApply_BT;
479f1c6b773SPeter Brune   linesearch->ops->destroy        = SNESLineSearchDestroy_BT;
480f1c6b773SPeter Brune   linesearch->ops->setfromoptions = SNESLineSearchSetFromOptions_BT;
4810298fd71SBarry Smith   linesearch->ops->reset          = NULL;
4827f1410a3SPeter Brune   linesearch->ops->view           = SNESLineSearchView_BT;
4830298fd71SBarry Smith   linesearch->ops->setup          = NULL;
48471b4ebd2SPeter Brune 
485b00a9115SJed Brown   ierr = PetscNewLog(linesearch,&bt);CHKERRQ(ierr);
486f5af7f23SKarl Rupp 
48771b4ebd2SPeter Brune   linesearch->data    = (void*)bt;
48871b4ebd2SPeter Brune   linesearch->max_its = 40;
489b000cd8dSPeter Brune   linesearch->order   = SNES_LINESEARCH_ORDER_CUBIC;
49071b4ebd2SPeter Brune   bt->alpha           = 1e-4;
49171b4ebd2SPeter Brune   PetscFunctionReturn(0);
49271b4ebd2SPeter Brune }
493