xref: /petsc/src/snes/impls/ls/ls.c (revision 052efed2d4d49f85092290ff2aaacf5d901780e1)
15e76c431SBarry Smith #ifndef lint
2*052efed2SBarry Smith static char vcid[] = "$Id: ls.c,v 1.56 1996/01/12 23:03:12 balay Exp bsmith $";
35e76c431SBarry Smith #endif
45e76c431SBarry Smith 
55e76c431SBarry Smith #include <math.h>
6fbe28522SBarry Smith #include "ls.h"
7b16a3bb1SBarry Smith #include "pinclude/pviewer.h"
85e42470aSBarry Smith 
95e42470aSBarry Smith /*
105e42470aSBarry Smith      Implements a line search variant of Newton's Method
115e76c431SBarry Smith     for solving systems of nonlinear equations.
125e76c431SBarry Smith 
135e76c431SBarry Smith     Input parameters:
145e42470aSBarry Smith .   snes - nonlinear context obtained from SNESCreate()
155e76c431SBarry Smith 
165e42470aSBarry Smith     Output Parameters:
17a935fc98SLois Curfman McInnes .   outits  - Number of global iterations until termination.
185e76c431SBarry Smith 
195e76c431SBarry Smith     Notes:
205e76c431SBarry Smith     This implements essentially a truncated Newton method with a
215e76c431SBarry Smith     line search.  By default a cubic backtracking line search
225e76c431SBarry Smith     is employed, as described in the text "Numerical Methods for
235e76c431SBarry Smith     Unconstrained Optimization and Nonlinear Equations" by Dennis
24393d2d9aSLois Curfman McInnes     and Schnabel.
255e76c431SBarry Smith */
265e76c431SBarry Smith 
275e42470aSBarry Smith int SNESSolve_LS(SNES snes,int *outits)
285e76c431SBarry Smith {
295e42470aSBarry Smith   SNES_LS      *neP = (SNES_LS *) snes->data;
30761aaf1bSLois Curfman McInnes   int          maxits, i, history_len, ierr, lits, lsfail;
31df60cc22SBarry Smith   MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN;
326b5873e3SBarry Smith   double       fnorm, gnorm, xnorm, ynorm, *history;
335e42470aSBarry Smith   Vec          Y, X, F, G, W, TMP;
345e76c431SBarry Smith 
355e42470aSBarry Smith   history	= snes->conv_hist;	/* convergence history */
365e42470aSBarry Smith   history_len	= snes->conv_hist_len;	/* convergence history length */
375e42470aSBarry Smith   maxits	= snes->max_its;	/* maximum number of iterations */
385e42470aSBarry Smith   X		= snes->vec_sol;	/* solution vector */
3939e2f89bSBarry Smith   F		= snes->vec_func;	/* residual vector */
405e42470aSBarry Smith   Y		= snes->work[0];	/* work vectors */
415e42470aSBarry Smith   G		= snes->work[1];
425e42470aSBarry Smith   W		= snes->work[2];
435e76c431SBarry Smith 
44cddf8d76SBarry Smith   ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);               /* xnorm = || X || */
455334005bSBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr);          /*  F(X)      */
46cddf8d76SBarry Smith   ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr);	        /* fnorm <- ||F||  */
475e42470aSBarry Smith   snes->norm = fnorm;
485e76c431SBarry Smith   if (history && history_len > 0) history[0] = fnorm;
49ddd12767SBarry Smith   if (snes->monitor) {ierr = (*snes->monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);}
505e76c431SBarry Smith 
515e76c431SBarry Smith   for ( i=0; i<maxits; i++ ) {
525e42470aSBarry Smith     snes->iter = i+1;
535e76c431SBarry Smith 
545e76c431SBarry Smith     /* Solve J Y = -F, where J is Jacobian matrix */
555334005bSBarry Smith     ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr);
565334005bSBarry Smith     ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr);
5778b31e54SBarry Smith     ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr);
5881b6cf68SLois Curfman McInnes     ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr);
59ddd12767SBarry Smith     ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);CHKERRQ(ierr);
60761aaf1bSLois Curfman McInnes     if (lsfail) snes->nfailures++;
615e76c431SBarry Smith 
6239e2f89bSBarry Smith     TMP = F; F = G; snes->vec_func_always = F; G = TMP;
6339e2f89bSBarry Smith     TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
645e76c431SBarry Smith     fnorm = gnorm;
655e76c431SBarry Smith 
665e42470aSBarry Smith     snes->norm = fnorm;
675e76c431SBarry Smith     if (history && history_len > i+1) history[i+1] = fnorm;
68cddf8d76SBarry Smith     ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr);	/* xnorm = || X || */
69ddd12767SBarry Smith     if (snes->monitor) {ierr = (*snes->monitor)(snes,i+1,fnorm,snes->monP);CHKERRQ(ierr);}
705e76c431SBarry Smith 
715e76c431SBarry Smith     /* Test for convergence */
72bbb6d6a8SBarry Smith     if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) {
7339e2f89bSBarry Smith       if (X != snes->vec_sol) {
74393d2d9aSLois Curfman McInnes         ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr);
7539e2f89bSBarry Smith         snes->vec_sol_always = snes->vec_sol;
7639e2f89bSBarry Smith         snes->vec_func_always = snes->vec_func;
7739e2f89bSBarry Smith       }
785e76c431SBarry Smith       break;
795e76c431SBarry Smith     }
805e76c431SBarry Smith   }
8152392280SLois Curfman McInnes   if (i == maxits) {
8252392280SLois Curfman McInnes     PLogInfo((PetscObject)snes,
83ddd12767SBarry Smith       "SNESSolve_LS: Maximum number of iterations has been reached: %d\n",maxits);
8452392280SLois Curfman McInnes     i--;
8552392280SLois Curfman McInnes   }
865e42470aSBarry Smith   *outits = i+1;
875e42470aSBarry Smith   return 0;
885e76c431SBarry Smith }
895e76c431SBarry Smith /* ------------------------------------------------------------ */
905e42470aSBarry Smith int SNESSetUp_LS(SNES snes )
915e76c431SBarry Smith {
925e42470aSBarry Smith   int ierr;
9381b6cf68SLois Curfman McInnes   snes->nwork = 4;
94d7e8b826SBarry Smith   ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work); CHKERRQ(ierr);
955e42470aSBarry Smith   PLogObjectParents(snes,snes->nwork,snes->work);
9681b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
975e42470aSBarry Smith   return 0;
985e76c431SBarry Smith }
995e76c431SBarry Smith /* ------------------------------------------------------------ */
1005e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj)
1015e76c431SBarry Smith {
1025e42470aSBarry Smith   SNES snes = (SNES) obj;
103393d2d9aSLois Curfman McInnes   int  ierr;
1044b0e389bSBarry Smith   ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr);
1050452661fSBarry Smith   PetscFree(snes->data);
1065e42470aSBarry Smith   return 0;
1075e76c431SBarry Smith }
1085e76c431SBarry Smith /* ------------------------------------------------------------ */
1095e76c431SBarry Smith /*ARGSUSED*/
1104b828684SBarry Smith /*@C
1115e42470aSBarry Smith    SNESNoLineSearch - This routine is not a line search at all;
1125e76c431SBarry Smith    it simply uses the full Newton step.  Thus, this routine is intended
1135e76c431SBarry Smith    to serve as a template and is not recommended for general use.
1145e76c431SBarry Smith 
1155e76c431SBarry Smith    Input Parameters:
1165e42470aSBarry Smith .  snes - nonlinear context
1175e76c431SBarry Smith .  x - current iterate
1185e76c431SBarry Smith .  f - residual evaluated at x
1195e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1205e76c431SBarry Smith .  w - work vector
1215e76c431SBarry Smith .  fnorm - 2-norm of f
1225e76c431SBarry Smith 
123c4a48953SLois Curfman McInnes    Output Parameters:
1245e76c431SBarry Smith .  g - residual evaluated at new iterate y
1255e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1265e76c431SBarry Smith .  gnorm - 2-norm of g
1275e76c431SBarry Smith .  ynorm - 2-norm of search length
128761aaf1bSLois Curfman McInnes .  flag - set to 0, indicating a successful line search
1295e76c431SBarry Smith 
130c4a48953SLois Curfman McInnes    Options Database Key:
131c4a48953SLois Curfman McInnes $  -snes_line_search basic
132c4a48953SLois Curfman McInnes 
13328ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
13428ae5a21SLois Curfman McInnes 
135f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(),
136a935fc98SLois Curfman McInnes           SNESSetLineSearchRoutine()
1375e76c431SBarry Smith @*/
1385e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
139761aaf1bSLois Curfman McInnes                      double fnorm, double *ynorm, double *gnorm,int *flag )
1405e76c431SBarry Smith {
1415e42470aSBarry Smith   int    ierr;
1425334005bSBarry Smith   Scalar mone = -1.0;
1435334005bSBarry Smith 
144761aaf1bSLois Curfman McInnes   *flag = 0;
1457857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
146cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);              /* ynorm = || y || */
1475334005bSBarry Smith   ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr);                   /* y <- x + y      */
1485334005bSBarry Smith   ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr);        /*  F(y)      */
149cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);              /* gnorm = || g || */
1507857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
151761aaf1bSLois Curfman McInnes   return 0;
1525e76c431SBarry Smith }
1535e76c431SBarry Smith /* ------------------------------------------------------------------ */
1544b828684SBarry Smith /*@C
155f59ffdedSLois Curfman McInnes    SNESCubicLineSearch - This routine performs a cubic line search and
156f59ffdedSLois Curfman McInnes    is the default line search method.
1575e76c431SBarry Smith 
1585e76c431SBarry Smith    Input Parameters:
1595e42470aSBarry Smith .  snes - nonlinear context
1605e76c431SBarry Smith .  x - current iterate
1615e76c431SBarry Smith .  f - residual evaluated at x
1625e76c431SBarry Smith .  y - search direction (contains new iterate on output)
1635e76c431SBarry Smith .  w - work vector
1645e76c431SBarry Smith .  fnorm - 2-norm of f
1655e76c431SBarry Smith 
166393d2d9aSLois Curfman McInnes    Output Parameters:
1675e76c431SBarry Smith .  g - residual evaluated at new iterate y
1685e76c431SBarry Smith .  y - new iterate (contains search direction on input)
1695e76c431SBarry Smith .  gnorm - 2-norm of g
1705e76c431SBarry Smith .  ynorm - 2-norm of search length
171761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
1725e76c431SBarry Smith 
173c4a48953SLois Curfman McInnes    Options Database Key:
174c4a48953SLois Curfman McInnes $  -snes_line_search cubic
175c4a48953SLois Curfman McInnes 
1765e76c431SBarry Smith    Notes:
1775e76c431SBarry Smith    This line search is taken from "Numerical Methods for Unconstrained
1785e76c431SBarry Smith    Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325.
1795e76c431SBarry Smith 
18028ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic
18128ae5a21SLois Curfman McInnes 
182f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
1835e76c431SBarry Smith @*/
1845e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
185761aaf1bSLois Curfman McInnes                         double fnorm, double *ynorm, double *gnorm,int *flag)
1865e76c431SBarry Smith {
187ddd12767SBarry Smith   double  steptol, initslope,lambdaprev, gnormprev,a, b, d, t1, t2;
188ddd12767SBarry Smith   double  maxstep,minlambda,alpha,lambda,lambdatemp;
1896b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
1905e42470aSBarry Smith   Scalar  cinitslope,clambda;
1916b5873e3SBarry Smith #endif
1925e42470aSBarry Smith   int     ierr, count;
1935e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
1945334005bSBarry Smith   Scalar  mone = -1.0,scale;
1955e76c431SBarry Smith 
1967857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
197761aaf1bSLois Curfman McInnes   *flag   = 0;
1985e76c431SBarry Smith   alpha   = neP->alpha;
1995e76c431SBarry Smith   maxstep = neP->maxstep;
2005e76c431SBarry Smith   steptol = neP->steptol;
2015e76c431SBarry Smith 
202cddf8d76SBarry Smith   ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr);
2035e76c431SBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
2045e42470aSBarry Smith     scale = maxstep/(*ynorm);
2056b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
206ddd12767SBarry Smith     PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale));
2076b5873e3SBarry Smith #else
208ddd12767SBarry Smith     PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Scaling step by %g\n",scale);
2096b5873e3SBarry Smith #endif
210393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
2115e76c431SBarry Smith     *ynorm = maxstep;
2125e76c431SBarry Smith   }
2135e76c431SBarry Smith   minlambda = steptol/(*ynorm);
214a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
2155e42470aSBarry Smith #if defined(PETSC_COMPLEX)
216a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
2175e42470aSBarry Smith   initslope = real(cinitslope);
2185e42470aSBarry Smith #else
219a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
2205e42470aSBarry Smith #endif
2215e76c431SBarry Smith   if (initslope > 0.0) initslope = -initslope;
2225e76c431SBarry Smith   if (initslope == 0.0) initslope = -1.0;
2235e76c431SBarry Smith 
224393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
2255334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
22678b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
227cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm);
2285e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
229393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
2304b828684SBarry Smith     PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Using full step\n");
231d93a2b8dSBarry Smith     goto theend;
2325e76c431SBarry Smith   }
2335e76c431SBarry Smith 
2345e76c431SBarry Smith   /* Fit points with quadratic */
2355e76c431SBarry Smith   lambda = 1.0; count = 0;
236a703fe33SLois Curfman McInnes   lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
2375e76c431SBarry Smith   lambdaprev = lambda;
2385e76c431SBarry Smith   gnormprev = *gnorm;
239ddd12767SBarry Smith   if (lambdatemp <= .1*lambda) lambda = .1*lambda;
240ddd12767SBarry Smith   else lambda = lambdatemp;
241393d2d9aSLois Curfman McInnes   ierr   = VecCopy(x,w); CHKERRQ(ierr);
2425334005bSBarry Smith   lambda = -lambda;
2435e42470aSBarry Smith #if defined(PETSC_COMPLEX)
244393d2d9aSLois Curfman McInnes   clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2455e42470aSBarry Smith #else
246393d2d9aSLois Curfman McInnes   ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
2475e42470aSBarry Smith #endif
24878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
249cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
2505e76c431SBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
251393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
2524b828684SBarry Smith     PLogInfo((PetscObject)snes,
2534b828684SBarry Smith              "SNESCubicLineSearch: Quadratically determined step, lambda %g\n",lambda);
254d93a2b8dSBarry Smith     goto theend;
2555e76c431SBarry Smith   }
2565e76c431SBarry Smith 
2575e76c431SBarry Smith   /* Fit points with cubic */
2585e76c431SBarry Smith   count = 1;
2595e76c431SBarry Smith   while (1) {
2605e76c431SBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
2614b828684SBarry Smith       PLogInfo((PetscObject)snes,
2624b828684SBarry Smith          "SNESCubicLineSearch:Unable to find good step length! %d \n",count);
2634b828684SBarry Smith       PLogInfo((PetscObject)snes,
264*052efed2SBarry Smith          "SNESCubicLineSearch:f %g fnew %g ynorm %g lambda %g initial slope %g\n",fnorm,*gnorm,*ynorm,lambda,initslope);
265393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
266761aaf1bSLois Curfman McInnes       *flag = -1; break;
2675e76c431SBarry Smith     }
2685e76c431SBarry Smith     t1 = *gnorm - fnorm - lambda*initslope;
2695e76c431SBarry Smith     t2 = gnormprev  - fnorm - lambdaprev*initslope;
270ddd12767SBarry Smith     a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2715e76c431SBarry Smith     b = (-lambdaprev*t1/(lambda*lambda) +
2725e76c431SBarry Smith                              lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev);
2735e76c431SBarry Smith     d = b*b - 3*a*initslope;
2745e76c431SBarry Smith     if (d < 0.0) d = 0.0;
2755e76c431SBarry Smith     if (a == 0.0) {
2765e76c431SBarry Smith       lambdatemp = -initslope/(2.0*b);
2775e76c431SBarry Smith     } else {
2785e76c431SBarry Smith       lambdatemp = (-b + sqrt(d))/(3.0*a);
2795e76c431SBarry Smith     }
2805e76c431SBarry Smith     if (lambdatemp > .5*lambda) {
2815e76c431SBarry Smith       lambdatemp = .5*lambda;
2825e76c431SBarry Smith     }
2835e76c431SBarry Smith     lambdaprev = lambda;
2845e76c431SBarry Smith     gnormprev = *gnorm;
2855e76c431SBarry Smith     if (lambdatemp <= .1*lambda) {
2865e76c431SBarry Smith       lambda = .1*lambda;
2875e76c431SBarry Smith     }
2885e76c431SBarry Smith     else lambda = lambdatemp;
289393d2d9aSLois Curfman McInnes     ierr = VecCopy( x, w ); CHKERRQ(ierr);
2905334005bSBarry Smith     lambda = -lambda;
2915e42470aSBarry Smith #if defined(PETSC_COMPLEX)
2925334005bSBarry Smith     clambda = lambda;
293393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
2945e42470aSBarry Smith #else
295393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
2965e42470aSBarry Smith #endif
29778b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
298cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
2995e76c431SBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* is reduction enough */
300393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
3014b828684SBarry Smith       PLogInfo((PetscObject)snes,
3024b828684SBarry Smith                 "SNESCubicLineSearch: Cubically determined step, lambda %g\n",lambda);
303761aaf1bSLois Curfman McInnes       *flag = -1; break;
3045e76c431SBarry Smith     }
3055e76c431SBarry Smith     count++;
3065e76c431SBarry Smith   }
307d93a2b8dSBarry Smith   theend:
3087857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
3095e42470aSBarry Smith   return 0;
3105e76c431SBarry Smith }
31152392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
3124b828684SBarry Smith /*@C
3135e42470aSBarry Smith    SNESQuadraticLineSearch - This routine performs a cubic line search.
3145e76c431SBarry Smith 
3155e42470aSBarry Smith    Input Parameters:
316f59ffdedSLois Curfman McInnes .  snes - the SNES context
3175e42470aSBarry Smith .  x - current iterate
3185e42470aSBarry Smith .  f - residual evaluated at x
3195e42470aSBarry Smith .  y - search direction (contains new iterate on output)
3205e42470aSBarry Smith .  w - work vector
3215e42470aSBarry Smith .  fnorm - 2-norm of f
3225e42470aSBarry Smith 
323c4a48953SLois Curfman McInnes    Output Parameters:
3245e42470aSBarry Smith .  g - residual evaluated at new iterate y
3255e42470aSBarry Smith .  y - new iterate (contains search direction on input)
3265e42470aSBarry Smith .  gnorm - 2-norm of g
3275e42470aSBarry Smith .  ynorm - 2-norm of search length
328761aaf1bSLois Curfman McInnes .  flag - 0 if line search succeeds; -1 on failure.
3295e42470aSBarry Smith 
330c4a48953SLois Curfman McInnes    Options Database Key:
331c4a48953SLois Curfman McInnes $  -snes_line_search quadratic
332c4a48953SLois Curfman McInnes 
3335e42470aSBarry Smith    Notes:
334f59ffdedSLois Curfman McInnes    Use SNESSetLineSearchRoutine()
335ddd12767SBarry Smith    to set this routine within the SNES_EQ_NLS method.
3365e42470aSBarry Smith 
337f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search
338f59ffdedSLois Curfman McInnes 
339f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine()
3405e42470aSBarry Smith @*/
3415e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w,
342761aaf1bSLois Curfman McInnes                            double fnorm, double *ynorm, double *gnorm,int *flag)
3435e76c431SBarry Smith {
344ddd12767SBarry Smith   double  steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp;
3456b5873e3SBarry Smith #if defined(PETSC_COMPLEX)
3465e42470aSBarry Smith   Scalar  cinitslope,clambda;
3476b5873e3SBarry Smith #endif
3485e42470aSBarry Smith   int     ierr,count;
3495e42470aSBarry Smith   SNES_LS *neP = (SNES_LS *) snes->data;
3505334005bSBarry Smith   Scalar  mone = -1.0,scale;
3515e76c431SBarry Smith 
3527857610eSBarry Smith   PLogEventBegin(SNES_LineSearch,snes,x,f,g);
353761aaf1bSLois Curfman McInnes   *flag = 0;
3545e42470aSBarry Smith   alpha   = neP->alpha;
3555e42470aSBarry Smith   maxstep = neP->maxstep;
3565e42470aSBarry Smith   steptol = neP->steptol;
3575e76c431SBarry Smith 
358cddf8d76SBarry Smith   VecNorm(y, NORM_2,ynorm );
3595e42470aSBarry Smith   if (*ynorm > maxstep) {	/* Step too big, so scale back */
3605e42470aSBarry Smith     scale = maxstep/(*ynorm);
361393d2d9aSLois Curfman McInnes     ierr = VecScale(&scale,y); CHKERRQ(ierr);
3625e42470aSBarry Smith     *ynorm = maxstep;
3635e76c431SBarry Smith   }
3645e42470aSBarry Smith   minlambda = steptol/(*ynorm);
365a703fe33SLois Curfman McInnes   ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr);
3665e42470aSBarry Smith #if defined(PETSC_COMPLEX)
367a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr);
3685e42470aSBarry Smith   initslope = real(cinitslope);
3695e42470aSBarry Smith #else
370a703fe33SLois Curfman McInnes   ierr = VecDot(f,w,&initslope); CHKERRQ(ierr);
3715e42470aSBarry Smith #endif
3725e42470aSBarry Smith   if (initslope > 0.0) initslope = -initslope;
3735e42470aSBarry Smith   if (initslope == 0.0) initslope = -1.0;
3745e42470aSBarry Smith 
375393d2d9aSLois Curfman McInnes   ierr = VecCopy(y,w); CHKERRQ(ierr);
3765334005bSBarry Smith   ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr);
37778b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
378cddf8d76SBarry Smith   ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
3795e42470aSBarry Smith   if (*gnorm <= fnorm + alpha*initslope) {	/* Sufficient reduction */
380393d2d9aSLois Curfman McInnes     ierr = VecCopy(w,y); CHKERRQ(ierr);
3814b828684SBarry Smith     PLogInfo((PetscObject)snes,"SNESQuadraticLineSearch: Using full step\n");
382d93a2b8dSBarry Smith     goto theend;
3835e42470aSBarry Smith   }
3845e42470aSBarry Smith 
3855e42470aSBarry Smith   /* Fit points with quadratic */
3865e42470aSBarry Smith   lambda = 1.0; count = 0;
3875e42470aSBarry Smith   count = 1;
3885e42470aSBarry Smith   while (1) {
3895e42470aSBarry Smith     if (lambda <= minlambda) { /* bad luck; use full step */
3904b828684SBarry Smith       PLogInfo((PetscObject)snes,
3914b828684SBarry Smith           "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count);
3924b828684SBarry Smith       PLogInfo((PetscObject)snes,
393ddd12767SBarry Smith       "SNESQuadraticLineSearch:f %g fnew %g ynorm %g lambda %g\n",fnorm,*gnorm,*ynorm,lambda);
394393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
395761aaf1bSLois Curfman McInnes       *flag = -1; break;
3965e42470aSBarry Smith     }
397a703fe33SLois Curfman McInnes     lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope);
3985e42470aSBarry Smith     lambdaprev = lambda;
3995e42470aSBarry Smith     gnormprev = *gnorm;
4005e42470aSBarry Smith     if (lambdatemp <= .1*lambda) {
4015e42470aSBarry Smith       lambda = .1*lambda;
4025e42470aSBarry Smith     } else lambda = lambdatemp;
403393d2d9aSLois Curfman McInnes     ierr = VecCopy(x,w); CHKERRQ(ierr);
4045334005bSBarry Smith     lambda = -lambda;
4055e42470aSBarry Smith #if defined(PETSC_COMPLEX)
406393d2d9aSLois Curfman McInnes     clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr);
4075e42470aSBarry Smith #else
408393d2d9aSLois Curfman McInnes     ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr);
4095e42470aSBarry Smith #endif
41078b31e54SBarry Smith     ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr);
411cddf8d76SBarry Smith     ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr);
4125e42470aSBarry Smith     if (*gnorm <= fnorm + alpha*initslope) {      /* sufficient reduction */
413393d2d9aSLois Curfman McInnes       ierr = VecCopy(w,y); CHKERRQ(ierr);
4144b828684SBarry Smith       PLogInfo((PetscObject)snes,
415ddd12767SBarry Smith         "SNESQuadraticLineSearch:Quadratically determined step, lambda %g\n",lambda);
41606259719SBarry Smith       break;
4175e42470aSBarry Smith     }
4185e42470aSBarry Smith     count++;
4195e42470aSBarry Smith   }
420d93a2b8dSBarry Smith   theend:
4217857610eSBarry Smith   PLogEventEnd(SNES_LineSearch,snes,x,f,g);
4225e42470aSBarry Smith   return 0;
4235e76c431SBarry Smith }
4245e76c431SBarry Smith /* ------------------------------------------------------------ */
425c9e6a524SLois Curfman McInnes /*@C
4265e42470aSBarry Smith    SNESSetLineSearchRoutine - Sets the line search routine to be used
427fbe28522SBarry Smith    by the method SNES_LS.
4285e76c431SBarry Smith 
4295e76c431SBarry Smith    Input Parameters:
430eafb4bcbSBarry Smith .  snes - nonlinear context obtained from SNESCreate()
4315e76c431SBarry Smith .  func - pointer to int function
4325e76c431SBarry Smith 
433c4a48953SLois Curfman McInnes    Available Routines:
434f59ffdedSLois Curfman McInnes .  SNESCubicLineSearch() - default line search
435f59ffdedSLois Curfman McInnes .  SNESQuadraticLineSearch() - quadratic line search
436f59ffdedSLois Curfman McInnes .  SNESNoLineSearch() - the full Newton step (actually not a line search)
4375e76c431SBarry Smith 
438c4a48953SLois Curfman McInnes     Options Database Keys:
439c4a48953SLois Curfman McInnes $   -snes_line_search [basic,quadratic,cubic]
440c4a48953SLois Curfman McInnes 
4415e76c431SBarry Smith    Calling sequence of func:
442f59ffdedSLois Curfman McInnes    func (SNES snes, Vec x, Vec f, Vec g, Vec y,
443761aaf1bSLois Curfman McInnes          Vec w, double fnorm, double *ynorm,
444761aaf1bSLois Curfman McInnes          double *gnorm, *flag)
4455e76c431SBarry Smith 
4465e76c431SBarry Smith     Input parameters for func:
4475e42470aSBarry Smith .   snes - nonlinear context
4485e76c431SBarry Smith .   x - current iterate
4495e76c431SBarry Smith .   f - residual evaluated at x
4505e76c431SBarry Smith .   y - search direction (contains new iterate on output)
4515e76c431SBarry Smith .   w - work vector
4525e76c431SBarry Smith .   fnorm - 2-norm of f
4535e76c431SBarry Smith 
4545e76c431SBarry Smith     Output parameters for func:
4555e76c431SBarry Smith .   g - residual evaluated at new iterate y
4565e76c431SBarry Smith .   y - new iterate (contains search direction on input)
4575e76c431SBarry Smith .   gnorm - 2-norm of g
4585e76c431SBarry Smith .   ynorm - 2-norm of search length
459761aaf1bSLois Curfman McInnes .   flag - set to 0 if the line search succeeds; a nonzero integer
460761aaf1bSLois Curfman McInnes            on failure.
461f59ffdedSLois Curfman McInnes 
462f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine
463f59ffdedSLois Curfman McInnes 
464f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch()
4655e76c431SBarry Smith @*/
4665e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec,
467761aaf1bSLois Curfman McInnes                              double,double*,double*,int*))
4685e76c431SBarry Smith {
4695334005bSBarry Smith   if ((snes)->type == SNES_EQ_NLS) ((SNES_LS *)(snes->data))->LineSearch = func;
4705e42470aSBarry Smith   return 0;
4715e76c431SBarry Smith }
47252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
4736daaf66cSBarry Smith static int SNESPrintHelp_LS(SNES snes,char *p)
4745e42470aSBarry Smith {
4755e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
4766daaf66cSBarry Smith 
47752392280SLois Curfman McInnes   MPIU_printf(snes->comm," method ls (system of nonlinear equations):\n");
47852392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search [basic,quadratic,cubic]\n",p);
47952392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_alpha alpha (default %g)\n",p,ls->alpha);
48052392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_maxstep max (default %g)\n",p,ls->maxstep);
48152392280SLois Curfman McInnes   MPIU_printf(snes->comm,"   %ssnes_line_search_steptol tol (default %g)\n",p,ls->steptol);
4826b5873e3SBarry Smith   return 0;
4835e42470aSBarry Smith }
48452392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
485a935fc98SLois Curfman McInnes static int SNESView_LS(PetscObject obj,Viewer viewer)
486a935fc98SLois Curfman McInnes {
487a935fc98SLois Curfman McInnes   SNES    snes = (SNES)obj;
488a935fc98SLois Curfman McInnes   SNES_LS *ls = (SNES_LS *)snes->data;
489d636dbe3SBarry Smith   FILE    *fd;
490a935fc98SLois Curfman McInnes   char    *cstring;
49151695f54SLois Curfman McInnes   int     ierr;
492a935fc98SLois Curfman McInnes 
493a447f0b5SLois Curfman McInnes   ierr = ViewerFileGetPointer_Private(viewer,&fd); CHKERRQ(ierr);
494ddd12767SBarry Smith   if (ls->LineSearch == SNESNoLineSearch) cstring = "SNESNoLineSearch";
495ddd12767SBarry Smith   else if (ls->LineSearch == SNESQuadraticLineSearch) cstring = "SNESQuadraticLineSearch";
496ddd12767SBarry Smith   else if (ls->LineSearch == SNESCubicLineSearch) cstring = "SNESCubicLineSearch";
497ddd12767SBarry Smith   else cstring = "unknown";
498a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    line search variant: %s\n",cstring);
499a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    alpha=%g, maxstep=%g, steptol=%g\n",
500a935fc98SLois Curfman McInnes                ls->alpha,ls->maxstep,ls->steptol);
501a935fc98SLois Curfman McInnes   return 0;
502a935fc98SLois Curfman McInnes }
50352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */
5045e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes)
5055e42470aSBarry Smith {
5065e42470aSBarry Smith   SNES_LS *ls = (SNES_LS *)snes->data;
5075e42470aSBarry Smith   char    ver[16];
5085e42470aSBarry Smith   double  tmp;
50925cdf11fSBarry Smith   int     ierr,flg;
5105e42470aSBarry Smith 
511ee8b94d1SSatish Balay   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp, &flg);CHKERRQ(ierr);
51225cdf11fSBarry Smith   if (flg) {
5135e42470aSBarry Smith     ls->alpha = tmp;
5145e42470aSBarry Smith   }
515ee8b94d1SSatish Balay   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp, &flg);CHKERRQ(ierr);
51625cdf11fSBarry Smith   if (flg) {
5175e42470aSBarry Smith     ls->maxstep = tmp;
5185e42470aSBarry Smith   }
519ee8b94d1SSatish Balay   ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp, &flg);CHKERRQ(ierr);
52025cdf11fSBarry Smith   if (flg) {
5215e42470aSBarry Smith     ls->steptol = tmp;
5225e42470aSBarry Smith   }
523ee8b94d1SSatish Balay   ierr = OptionsGetString(snes->prefix,"-snes_line_search",ver,16, &flg); CHKERRQ(ierr);
52425cdf11fSBarry Smith   if (flg) {
52548d91487SBarry Smith     if (!PetscStrcmp(ver,"basic")) {
5265e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESNoLineSearch);
5275e42470aSBarry Smith     }
52848d91487SBarry Smith     else if (!PetscStrcmp(ver,"quadratic")) {
5295e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch);
5305e42470aSBarry Smith     }
53148d91487SBarry Smith     else if (!PetscStrcmp(ver,"cubic")) {
5325e42470aSBarry Smith       SNESSetLineSearchRoutine(snes,SNESCubicLineSearch);
5335e42470aSBarry Smith     }
5348c48e012SBarry Smith     else {SETERRQ(1,"SNESSetFromOptions_LS:Unknown line search");}
5355e42470aSBarry Smith   }
5365e42470aSBarry Smith   return 0;
5375e42470aSBarry Smith }
5385e42470aSBarry Smith /* ------------------------------------------------------------ */
5395e42470aSBarry Smith int SNESCreate_LS(SNES  snes )
5405e42470aSBarry Smith {
5415e42470aSBarry Smith   SNES_LS *neP;
5425e42470aSBarry Smith 
543ddd12767SBarry Smith   if (snes->method_class != SNES_NONLINEAR_EQUATIONS)
544ddd12767SBarry Smith     SETERRQ(1,"SNESCreate_LS:For SNES_NONLINEAR_EQUATIONS only");
54525c7317fSLois Curfman McInnes   snes->type		= SNES_EQ_NLS;
54649e3953dSBarry Smith   snes->setup		= SNESSetUp_LS;
54749e3953dSBarry Smith   snes->solve		= SNESSolve_LS;
5485e42470aSBarry Smith   snes->destroy		= SNESDestroy_LS;
549bbb6d6a8SBarry Smith   snes->converged	= SNESDefaultConverged;
55049e3953dSBarry Smith   snes->printhelp       = SNESPrintHelp_LS;
55149e3953dSBarry Smith   snes->setfromoptions  = SNESSetFromOptions_LS;
552a935fc98SLois Curfman McInnes   snes->view            = SNESView_LS;
5535e42470aSBarry Smith 
5540452661fSBarry Smith   neP			= PetscNew(SNES_LS);   CHKPTRQ(neP);
555ff782a9fSLois Curfman McInnes   PLogObjectMemory(snes,sizeof(SNES_LS));
5565e42470aSBarry Smith   snes->data    	= (void *) neP;
5575e42470aSBarry Smith   neP->alpha		= 1.e-4;
5585e42470aSBarry Smith   neP->maxstep		= 1.e8;
5595e42470aSBarry Smith   neP->steptol		= 1.e-12;
5605e42470aSBarry Smith   neP->LineSearch       = SNESCubicLineSearch;
5615e42470aSBarry Smith   return 0;
5625e42470aSBarry Smith }
5635e42470aSBarry Smith 
5645e42470aSBarry Smith 
5655e42470aSBarry Smith 
5665e42470aSBarry Smith 
567