xref: /petsc/src/tao/unconstrained/impls/nls/nls.c (revision 5f309d014d30c8e30ef8d484fee079cd79b2cbfc)
1 #include <petsctaolinesearch.h>
2 #include <../src/tao/matrix/lmvmmat.h>
3 #include <../src/tao/unconstrained/impls/nls/nlsimpl.h>
4 
5 #include <petscksp.h>
6 
7 #define NLS_PC_NONE     0
8 #define NLS_PC_AHESS    1
9 #define NLS_PC_BFGS     2
10 #define NLS_PC_PETSC    3
11 #define NLS_PC_TYPES    4
12 
13 #define BFGS_SCALE_AHESS        0
14 #define BFGS_SCALE_PHESS        1
15 #define BFGS_SCALE_BFGS         2
16 #define BFGS_SCALE_TYPES        3
17 
18 #define NLS_INIT_CONSTANT         0
19 #define NLS_INIT_DIRECTION        1
20 #define NLS_INIT_INTERPOLATION    2
21 #define NLS_INIT_TYPES            3
22 
23 #define NLS_UPDATE_STEP           0
24 #define NLS_UPDATE_REDUCTION      1
25 #define NLS_UPDATE_INTERPOLATION  2
26 #define NLS_UPDATE_TYPES          3
27 
28 static const char *NLS_PC[64] = {"none", "ahess", "bfgs", "petsc"};
29 
30 static const char *BFGS_SCALE[64] = {"ahess", "phess", "bfgs"};
31 
32 static const char *NLS_INIT[64] = {"constant", "direction", "interpolation"};
33 
34 static const char *NLS_UPDATE[64] = {"step", "reduction", "interpolation"};
35 
36 /* Routine for BFGS preconditioner */
37 
38 #undef __FUNCT__
39 #define __FUNCT__ "MatLMVMSolveShell"
40 static PetscErrorCode MatLMVMSolveShell(PC pc, Vec b, Vec x)
41 {
42   PetscErrorCode ierr;
43   Mat            M;
44 
45   PetscFunctionBegin;
46   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
47   PetscValidHeaderSpecific(b,VEC_CLASSID,2);
48   PetscValidHeaderSpecific(x,VEC_CLASSID,3);
49   ierr = PCShellGetContext(pc,(void**)&M);CHKERRQ(ierr);
50   ierr = MatLMVMSolve(M, b, x);CHKERRQ(ierr);
51   PetscFunctionReturn(0);
52 }
53 
54 /*
55  Implements Newton's Method with a line search approach for solving
56  unconstrained minimization problems.  A More'-Thuente line search
57  is used to guarantee that the bfgs preconditioner remains positive
58  definite.
59 
60  The method can shift the Hessian matrix.  The shifting procedure is
61  adapted from the PATH algorithm for solving complementarity
62  problems.
63 
64  The linear system solve should be done with a conjugate gradient
65  method, although any method can be used.
66 */
67 
68 #define NLS_NEWTON              0
69 #define NLS_BFGS                1
70 #define NLS_SCALED_GRADIENT     2
71 #define NLS_GRADIENT            3
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "TaoSolve_NLS"
75 static PetscErrorCode TaoSolve_NLS(Tao tao)
76 {
77   PetscErrorCode               ierr;
78   TAO_NLS                      *nlsP = (TAO_NLS *)tao->data;
79   KSPType                      ksp_type;
80   PetscBool                    is_nash,is_stcg,is_gltr;
81   KSPConvergedReason           ksp_reason;
82   PC                           pc;
83   TaoConvergedReason           reason;
84   TaoLineSearchConvergedReason ls_reason;
85 
86   PetscReal                    fmin, ftrial, f_full, prered, actred, kappa, sigma;
87   PetscReal                    tau, tau_1, tau_2, tau_max, tau_min, max_radius;
88   PetscReal                    f, fold, gdx, gnorm, pert;
89   PetscReal                    step = 1.0;
90   PetscReal                    delta;
91   PetscReal                    norm_d = 0.0, e_min;
92 
93   PetscInt                     stepType;
94   PetscInt                     bfgsUpdates = 0;
95   PetscInt                     n,N,kspits;
96   PetscInt                     needH = 1;
97 
98   PetscInt                     i_max = 5;
99   PetscInt                     j_max = 1;
100   PetscInt                     i, j;
101 
102   PetscFunctionBegin;
103   if (tao->XL || tao->XU || tao->ops->computebounds) {
104     ierr = PetscPrintf(((PetscObject)tao)->comm,"WARNING: Variable bounds have been set but will be ignored by nls algorithm\n");CHKERRQ(ierr);
105   }
106 
107   /* Initialized variables */
108   pert = nlsP->sval;
109 
110   /* Number of times ksp stopped because of these reasons */
111   nlsP->ksp_atol = 0;
112   nlsP->ksp_rtol = 0;
113   nlsP->ksp_dtol = 0;
114   nlsP->ksp_ctol = 0;
115   nlsP->ksp_negc = 0;
116   nlsP->ksp_iter = 0;
117   nlsP->ksp_othr = 0;
118 
119   /* Initialize trust-region radius when using nash, stcg, or gltr
120      Command automatically ignored for other methods
121      Will be reset during the first iteration
122   */
123   ierr = KSPGetType(tao->ksp,&ksp_type);CHKERRQ(ierr);
124   ierr = PetscStrcmp(ksp_type,KSPCGNASH,&is_nash);CHKERRQ(ierr);
125   ierr = PetscStrcmp(ksp_type,KSPCGSTCG,&is_stcg);CHKERRQ(ierr);
126   ierr = PetscStrcmp(ksp_type,KSPCGGLTR,&is_gltr);CHKERRQ(ierr);
127 
128   ierr = KSPCGSetRadius(tao->ksp,nlsP->max_radius);CHKERRQ(ierr);
129 
130   if (is_nash || is_stcg || is_gltr) {
131     if (tao->trust0 < 0.0) SETERRQ(PETSC_COMM_SELF,1,"Initial radius negative");
132     tao->trust = tao->trust0;
133     tao->trust = PetscMax(tao->trust, nlsP->min_radius);
134     tao->trust = PetscMin(tao->trust, nlsP->max_radius);
135   }
136 
137   /* Get vectors we will need */
138   if (NLS_PC_BFGS == nlsP->pc_type && !nlsP->M) {
139     ierr = VecGetLocalSize(tao->solution,&n);CHKERRQ(ierr);
140     ierr = VecGetSize(tao->solution,&N);CHKERRQ(ierr);
141     ierr = MatCreateLMVM(((PetscObject)tao)->comm,n,N,&nlsP->M);CHKERRQ(ierr);
142     ierr = MatLMVMAllocateVectors(nlsP->M,tao->solution);CHKERRQ(ierr);
143   }
144 
145   /* Check convergence criteria */
146   ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient);CHKERRQ(ierr);
147   ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
148   if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
149 
150   ierr = TaoMonitor(tao, tao->niter, f, gnorm, 0.0, 1.0, &reason);CHKERRQ(ierr);
151   if (reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
152 
153   /* create vectors for the limited memory preconditioner */
154   if ((NLS_PC_BFGS == nlsP->pc_type) && (BFGS_SCALE_BFGS != nlsP->bfgs_scale_type)) {
155     if (!nlsP->Diag) {
156       ierr = VecDuplicate(tao->solution,&nlsP->Diag);CHKERRQ(ierr);
157     }
158   }
159 
160   /* Modify the preconditioner to use the bfgs approximation */
161   ierr = KSPGetPC(tao->ksp, &pc);CHKERRQ(ierr);
162   switch(nlsP->pc_type) {
163   case NLS_PC_NONE:
164     ierr = PCSetType(pc, PCNONE);CHKERRQ(ierr);
165     ierr = PCSetFromOptions(pc);CHKERRQ(ierr);
166     break;
167 
168   case NLS_PC_AHESS:
169     ierr = PCSetType(pc, PCJACOBI);CHKERRQ(ierr);
170     ierr = PCSetFromOptions(pc);CHKERRQ(ierr);
171     ierr = PCJacobiSetUseAbs(pc,PETSC_TRUE);CHKERRQ(ierr);
172     break;
173 
174   case NLS_PC_BFGS:
175     ierr = PCSetType(pc, PCSHELL);CHKERRQ(ierr);
176     ierr = PCSetFromOptions(pc);CHKERRQ(ierr);
177     ierr = PCShellSetName(pc, "bfgs");CHKERRQ(ierr);
178     ierr = PCShellSetContext(pc, nlsP->M);CHKERRQ(ierr);
179     ierr = PCShellSetApply(pc, MatLMVMSolveShell);CHKERRQ(ierr);
180     break;
181 
182   default:
183     /* Use the pc method set by pc_type */
184     break;
185   }
186 
187   /* Initialize trust-region radius.  The initialization is only performed
188      when we are using Nash, Steihaug-Toint or the Generalized Lanczos method. */
189   if (is_nash || is_stcg || is_gltr) {
190     switch(nlsP->init_type) {
191     case NLS_INIT_CONSTANT:
192       /* Use the initial radius specified */
193       break;
194 
195     case NLS_INIT_INTERPOLATION:
196       /* Use the initial radius specified */
197       max_radius = 0.0;
198 
199       for (j = 0; j < j_max; ++j) {
200         fmin = f;
201         sigma = 0.0;
202 
203         if (needH) {
204           ierr  = TaoComputeHessian(tao, tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
205           needH = 0;
206         }
207 
208         for (i = 0; i < i_max; ++i) {
209           ierr = VecCopy(tao->solution,nlsP->W);CHKERRQ(ierr);
210           ierr = VecAXPY(nlsP->W,-tao->trust/gnorm,tao->gradient);CHKERRQ(ierr);
211           ierr = TaoComputeObjective(tao, nlsP->W, &ftrial);CHKERRQ(ierr);
212           if (PetscIsInfOrNanReal(ftrial)) {
213             tau = nlsP->gamma1_i;
214           } else {
215             if (ftrial < fmin) {
216               fmin = ftrial;
217               sigma = -tao->trust / gnorm;
218             }
219 
220             ierr = MatMult(tao->hessian, tao->gradient, nlsP->D);CHKERRQ(ierr);
221             ierr = VecDot(tao->gradient, nlsP->D, &prered);CHKERRQ(ierr);
222 
223             prered = tao->trust * (gnorm - 0.5 * tao->trust * prered / (gnorm * gnorm));
224             actred = f - ftrial;
225             if ((PetscAbsScalar(actred) <= nlsP->epsilon) && (PetscAbsScalar(prered) <= nlsP->epsilon)) {
226               kappa = 1.0;
227             } else {
228               kappa = actred / prered;
229             }
230 
231             tau_1 = nlsP->theta_i * gnorm * tao->trust / (nlsP->theta_i * gnorm * tao->trust + (1.0 - nlsP->theta_i) * prered - actred);
232             tau_2 = nlsP->theta_i * gnorm * tao->trust / (nlsP->theta_i * gnorm * tao->trust - (1.0 + nlsP->theta_i) * prered + actred);
233             tau_min = PetscMin(tau_1, tau_2);
234             tau_max = PetscMax(tau_1, tau_2);
235 
236             if (PetscAbsScalar(kappa - 1.0) <= nlsP->mu1_i) {
237               /* Great agreement */
238               max_radius = PetscMax(max_radius, tao->trust);
239 
240               if (tau_max < 1.0) {
241                 tau = nlsP->gamma3_i;
242               } else if (tau_max > nlsP->gamma4_i) {
243                 tau = nlsP->gamma4_i;
244               } else if (tau_1 >= 1.0 && tau_1 <= nlsP->gamma4_i && tau_2 < 1.0) {
245                 tau = tau_1;
246               } else if (tau_2 >= 1.0 && tau_2 <= nlsP->gamma4_i && tau_1 < 1.0) {
247                 tau = tau_2;
248               } else {
249                 tau = tau_max;
250               }
251             } else if (PetscAbsScalar(kappa - 1.0) <= nlsP->mu2_i) {
252               /* Good agreement */
253               max_radius = PetscMax(max_radius, tao->trust);
254 
255               if (tau_max < nlsP->gamma2_i) {
256                 tau = nlsP->gamma2_i;
257               } else if (tau_max > nlsP->gamma3_i) {
258                 tau = nlsP->gamma3_i;
259               } else {
260                 tau = tau_max;
261               }
262             } else {
263               /* Not good agreement */
264               if (tau_min > 1.0) {
265                 tau = nlsP->gamma2_i;
266               } else if (tau_max < nlsP->gamma1_i) {
267                 tau = nlsP->gamma1_i;
268               } else if ((tau_min < nlsP->gamma1_i) && (tau_max >= 1.0)) {
269                 tau = nlsP->gamma1_i;
270               } else if ((tau_1 >= nlsP->gamma1_i) && (tau_1 < 1.0) && ((tau_2 < nlsP->gamma1_i) || (tau_2 >= 1.0))) {
271                 tau = tau_1;
272               } else if ((tau_2 >= nlsP->gamma1_i) && (tau_2 < 1.0) && ((tau_1 < nlsP->gamma1_i) || (tau_2 >= 1.0))) {
273                 tau = tau_2;
274               } else {
275                 tau = tau_max;
276               }
277             }
278           }
279           tao->trust = tau * tao->trust;
280         }
281 
282         if (fmin < f) {
283           f = fmin;
284           ierr = VecAXPY(tao->solution,sigma,tao->gradient);CHKERRQ(ierr);
285           ierr = TaoComputeGradient(tao,tao->solution,tao->gradient);CHKERRQ(ierr);
286 
287           ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
288           if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute gradient generated Inf or NaN");
289           needH = 1;
290 
291           ierr = TaoMonitor(tao, tao->niter, f, gnorm, 0.0, 1.0, &reason);CHKERRQ(ierr);
292           if (reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
293         }
294       }
295       tao->trust = PetscMax(tao->trust, max_radius);
296 
297       /* Modify the radius if it is too large or small */
298       tao->trust = PetscMax(tao->trust, nlsP->min_radius);
299       tao->trust = PetscMin(tao->trust, nlsP->max_radius);
300       break;
301 
302     default:
303       /* Norm of the first direction will initialize radius */
304       tao->trust = 0.0;
305       break;
306     }
307   }
308 
309   /* Set initial scaling for the BFGS preconditioner
310      This step is done after computing the initial trust-region radius
311      since the function value may have decreased */
312   if (NLS_PC_BFGS == nlsP->pc_type) {
313     if (f != 0.0) {
314       delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
315     } else {
316       delta = 2.0 / (gnorm*gnorm);
317     }
318     ierr = MatLMVMSetDelta(nlsP->M,delta);CHKERRQ(ierr);
319   }
320 
321   /* Set counter for gradient/reset steps*/
322   nlsP->newt = 0;
323   nlsP->bfgs = 0;
324   nlsP->sgrad = 0;
325   nlsP->grad = 0;
326 
327   /* Have not converged; continue with Newton method */
328   while (reason == TAO_CONTINUE_ITERATING) {
329     ++tao->niter;
330     tao->ksp_its=0;
331 
332     /* Compute the Hessian */
333     if (needH) {
334       ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
335     }
336 
337     if ((NLS_PC_BFGS == nlsP->pc_type) && (BFGS_SCALE_AHESS == nlsP->bfgs_scale_type)) {
338       /* Obtain diagonal for the bfgs preconditioner  */
339       ierr = MatGetDiagonal(tao->hessian, nlsP->Diag);CHKERRQ(ierr);
340       ierr = VecAbs(nlsP->Diag);CHKERRQ(ierr);
341       ierr = VecReciprocal(nlsP->Diag);CHKERRQ(ierr);
342       ierr = MatLMVMSetScale(nlsP->M,nlsP->Diag);CHKERRQ(ierr);
343     }
344 
345     /* Shift the Hessian matrix */
346     if (pert > 0) {
347       ierr = MatShift(tao->hessian, pert);CHKERRQ(ierr);
348       if (tao->hessian != tao->hessian_pre) {
349         ierr = MatShift(tao->hessian_pre, pert);CHKERRQ(ierr);
350       }
351     }
352 
353     if (NLS_PC_BFGS == nlsP->pc_type) {
354       if (BFGS_SCALE_PHESS == nlsP->bfgs_scale_type) {
355         /* Obtain diagonal for the bfgs preconditioner  */
356         ierr = MatGetDiagonal(tao->hessian, nlsP->Diag);CHKERRQ(ierr);
357         ierr = VecAbs(nlsP->Diag);CHKERRQ(ierr);
358         ierr = VecReciprocal(nlsP->Diag);CHKERRQ(ierr);
359         ierr = MatLMVMSetScale(nlsP->M,nlsP->Diag);CHKERRQ(ierr);
360       }
361       /* Update the limited memory preconditioner */
362       ierr = MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);CHKERRQ(ierr);
363       ++bfgsUpdates;
364     }
365 
366     /* Solve the Newton system of equations */
367     ierr = KSPSetOperators(tao->ksp,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
368     if (is_nash || is_stcg || is_gltr) {
369       ierr = KSPCGSetRadius(tao->ksp,nlsP->max_radius);CHKERRQ(ierr);
370       ierr = KSPSolve(tao->ksp, tao->gradient, nlsP->D);CHKERRQ(ierr);
371       ierr = KSPGetIterationNumber(tao->ksp,&kspits);CHKERRQ(ierr);
372       tao->ksp_its+=kspits;
373       tao->ksp_tot_its+=kspits;
374       ierr = KSPCGGetNormD(tao->ksp,&norm_d);CHKERRQ(ierr);
375 
376       if (0.0 == tao->trust) {
377         /* Radius was uninitialized; use the norm of the direction */
378         if (norm_d > 0.0) {
379           tao->trust = norm_d;
380 
381           /* Modify the radius if it is too large or small */
382           tao->trust = PetscMax(tao->trust, nlsP->min_radius);
383           tao->trust = PetscMin(tao->trust, nlsP->max_radius);
384         } else {
385           /* The direction was bad; set radius to default value and re-solve
386              the trust-region subproblem to get a direction */
387           tao->trust = tao->trust0;
388 
389           /* Modify the radius if it is too large or small */
390           tao->trust = PetscMax(tao->trust, nlsP->min_radius);
391           tao->trust = PetscMin(tao->trust, nlsP->max_radius);
392 
393           ierr = KSPCGSetRadius(tao->ksp,nlsP->max_radius);CHKERRQ(ierr);
394           ierr = KSPSolve(tao->ksp, tao->gradient, nlsP->D);CHKERRQ(ierr);
395           ierr = KSPGetIterationNumber(tao->ksp,&kspits);CHKERRQ(ierr);
396           tao->ksp_its+=kspits;
397           tao->ksp_tot_its+=kspits;
398           ierr = KSPCGGetNormD(tao->ksp,&norm_d);CHKERRQ(ierr);
399 
400           if (norm_d == 0.0) SETERRQ(PETSC_COMM_SELF,1, "Initial direction zero");
401         }
402       }
403     } else {
404       ierr = KSPSolve(tao->ksp, tao->gradient, nlsP->D);CHKERRQ(ierr);
405       ierr = KSPGetIterationNumber(tao->ksp, &kspits);CHKERRQ(ierr);
406       tao->ksp_its += kspits;
407       tao->ksp_tot_its+=kspits;
408     }
409     ierr = VecScale(nlsP->D, -1.0);CHKERRQ(ierr);
410     ierr = KSPGetConvergedReason(tao->ksp, &ksp_reason);CHKERRQ(ierr);
411     if ((KSP_DIVERGED_INDEFINITE_PC == ksp_reason) &&  (NLS_PC_BFGS == nlsP->pc_type) && (bfgsUpdates > 1)) {
412       /* Preconditioner is numerically indefinite; reset the
413          approximate if using BFGS preconditioning. */
414 
415       if (f != 0.0) {
416         delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
417       } else {
418         delta = 2.0 / (gnorm*gnorm);
419       }
420       ierr = MatLMVMSetDelta(nlsP->M,delta);CHKERRQ(ierr);
421       ierr = MatLMVMReset(nlsP->M);CHKERRQ(ierr);
422       ierr = MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);CHKERRQ(ierr);
423       bfgsUpdates = 1;
424     }
425 
426     if (KSP_CONVERGED_ATOL == ksp_reason) {
427       ++nlsP->ksp_atol;
428     } else if (KSP_CONVERGED_RTOL == ksp_reason) {
429       ++nlsP->ksp_rtol;
430     } else if (KSP_CONVERGED_CG_CONSTRAINED == ksp_reason) {
431       ++nlsP->ksp_ctol;
432     } else if (KSP_CONVERGED_CG_NEG_CURVE == ksp_reason) {
433       ++nlsP->ksp_negc;
434     } else if (KSP_DIVERGED_DTOL == ksp_reason) {
435       ++nlsP->ksp_dtol;
436     } else if (KSP_DIVERGED_ITS == ksp_reason) {
437       ++nlsP->ksp_iter;
438     } else {
439       ++nlsP->ksp_othr;
440     }
441 
442     /* Check for success (descent direction) */
443     ierr = VecDot(nlsP->D, tao->gradient, &gdx);CHKERRQ(ierr);
444     if ((gdx >= 0.0) || PetscIsInfOrNanReal(gdx)) {
445       /* Newton step is not descent or direction produced Inf or NaN
446          Update the perturbation for next time */
447       if (pert <= 0.0) {
448         /* Initialize the perturbation */
449         pert = PetscMin(nlsP->imax, PetscMax(nlsP->imin, nlsP->imfac * gnorm));
450         if (is_gltr) {
451           ierr = KSPCGGLTRGetMinEig(tao->ksp,&e_min);CHKERRQ(ierr);
452           pert = PetscMax(pert, -e_min);
453         }
454       } else {
455         /* Increase the perturbation */
456         pert = PetscMin(nlsP->pmax, PetscMax(nlsP->pgfac * pert, nlsP->pmgfac * gnorm));
457       }
458 
459       if (NLS_PC_BFGS != nlsP->pc_type) {
460         /* We don't have the bfgs matrix around and updated
461            Must use gradient direction in this case */
462         ierr = VecCopy(tao->gradient, nlsP->D);CHKERRQ(ierr);
463         ierr = VecScale(nlsP->D, -1.0);CHKERRQ(ierr);
464         ++nlsP->grad;
465         stepType = NLS_GRADIENT;
466       } else {
467         /* Attempt to use the BFGS direction */
468         ierr = MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);CHKERRQ(ierr);
469         ierr = VecScale(nlsP->D, -1.0);CHKERRQ(ierr);
470 
471         /* Check for success (descent direction) */
472         ierr = VecDot(tao->gradient, nlsP->D, &gdx);CHKERRQ(ierr);
473         if ((gdx >= 0) || PetscIsInfOrNanReal(gdx)) {
474           /* BFGS direction is not descent or direction produced not a number
475              We can assert bfgsUpdates > 1 in this case because
476              the first solve produces the scaled gradient direction,
477              which is guaranteed to be descent */
478 
479           /* Use steepest descent direction (scaled) */
480 
481           if (f != 0.0) {
482             delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
483           } else {
484             delta = 2.0 / (gnorm*gnorm);
485           }
486           ierr = MatLMVMSetDelta(nlsP->M, delta);CHKERRQ(ierr);
487           ierr = MatLMVMReset(nlsP->M);CHKERRQ(ierr);
488           ierr = MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);CHKERRQ(ierr);
489           ierr = MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);CHKERRQ(ierr);
490           ierr = VecScale(nlsP->D, -1.0);CHKERRQ(ierr);
491 
492           bfgsUpdates = 1;
493           ++nlsP->sgrad;
494           stepType = NLS_SCALED_GRADIENT;
495         } else {
496           if (1 == bfgsUpdates) {
497             /* The first BFGS direction is always the scaled gradient */
498             ++nlsP->sgrad;
499             stepType = NLS_SCALED_GRADIENT;
500           } else {
501             ++nlsP->bfgs;
502             stepType = NLS_BFGS;
503           }
504         }
505       }
506     } else {
507       /* Computed Newton step is descent */
508       switch (ksp_reason) {
509       case KSP_DIVERGED_NANORINF:
510       case KSP_DIVERGED_BREAKDOWN:
511       case KSP_DIVERGED_INDEFINITE_MAT:
512       case KSP_DIVERGED_INDEFINITE_PC:
513       case KSP_CONVERGED_CG_NEG_CURVE:
514         /* Matrix or preconditioner is indefinite; increase perturbation */
515         if (pert <= 0.0) {
516           /* Initialize the perturbation */
517           pert = PetscMin(nlsP->imax, PetscMax(nlsP->imin, nlsP->imfac * gnorm));
518           if (is_gltr) {
519             ierr = KSPCGGLTRGetMinEig(tao->ksp, &e_min);CHKERRQ(ierr);
520             pert = PetscMax(pert, -e_min);
521           }
522         } else {
523           /* Increase the perturbation */
524           pert = PetscMin(nlsP->pmax, PetscMax(nlsP->pgfac * pert, nlsP->pmgfac * gnorm));
525         }
526         break;
527 
528       default:
529         /* Newton step computation is good; decrease perturbation */
530         pert = PetscMin(nlsP->psfac * pert, nlsP->pmsfac * gnorm);
531         if (pert < nlsP->pmin) {
532           pert = 0.0;
533         }
534         break;
535       }
536 
537       ++nlsP->newt;
538       stepType = NLS_NEWTON;
539     }
540 
541     /* Perform the linesearch */
542     fold = f;
543     ierr = VecCopy(tao->solution, nlsP->Xold);CHKERRQ(ierr);
544     ierr = VecCopy(tao->gradient, nlsP->Gold);CHKERRQ(ierr);
545 
546     ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, nlsP->D, &step, &ls_reason);CHKERRQ(ierr);
547     ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
548 
549     while (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER && stepType != NLS_GRADIENT) {      /* Linesearch failed */
550       f = fold;
551       ierr = VecCopy(nlsP->Xold, tao->solution);CHKERRQ(ierr);
552       ierr = VecCopy(nlsP->Gold, tao->gradient);CHKERRQ(ierr);
553 
554       switch(stepType) {
555       case NLS_NEWTON:
556         /* Failed to obtain acceptable iterate with Newton 1step
557            Update the perturbation for next time */
558         if (pert <= 0.0) {
559           /* Initialize the perturbation */
560           pert = PetscMin(nlsP->imax, PetscMax(nlsP->imin, nlsP->imfac * gnorm));
561           if (is_gltr) {
562             ierr = KSPCGGLTRGetMinEig(tao->ksp,&e_min);CHKERRQ(ierr);
563             pert = PetscMax(pert, -e_min);
564           }
565         } else {
566           /* Increase the perturbation */
567           pert = PetscMin(nlsP->pmax, PetscMax(nlsP->pgfac * pert, nlsP->pmgfac * gnorm));
568         }
569 
570         if (NLS_PC_BFGS != nlsP->pc_type) {
571           /* We don't have the bfgs matrix around and being updated
572              Must use gradient direction in this case */
573           ierr = VecCopy(tao->gradient, nlsP->D);CHKERRQ(ierr);
574           ++nlsP->grad;
575           stepType = NLS_GRADIENT;
576         } else {
577           /* Attempt to use the BFGS direction */
578           ierr = MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);CHKERRQ(ierr);
579           /* Check for success (descent direction) */
580           ierr = VecDot(tao->solution, nlsP->D, &gdx);CHKERRQ(ierr);
581           if ((gdx <= 0) || PetscIsInfOrNanReal(gdx)) {
582             /* BFGS direction is not descent or direction produced not a number
583                We can assert bfgsUpdates > 1 in this case
584                Use steepest descent direction (scaled) */
585 
586             if (f != 0.0) {
587               delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
588             } else {
589               delta = 2.0 / (gnorm*gnorm);
590             }
591             ierr = MatLMVMSetDelta(nlsP->M, delta);CHKERRQ(ierr);
592             ierr = MatLMVMReset(nlsP->M);CHKERRQ(ierr);
593             ierr = MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);CHKERRQ(ierr);
594             ierr = MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);CHKERRQ(ierr);
595 
596             bfgsUpdates = 1;
597             ++nlsP->sgrad;
598             stepType = NLS_SCALED_GRADIENT;
599           } else {
600             if (1 == bfgsUpdates) {
601               /* The first BFGS direction is always the scaled gradient */
602               ++nlsP->sgrad;
603               stepType = NLS_SCALED_GRADIENT;
604             } else {
605               ++nlsP->bfgs;
606               stepType = NLS_BFGS;
607             }
608           }
609         }
610         break;
611 
612       case NLS_BFGS:
613         /* Can only enter if pc_type == NLS_PC_BFGS
614            Failed to obtain acceptable iterate with BFGS step
615            Attempt to use the scaled gradient direction */
616 
617         if (f != 0.0) {
618           delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
619         } else {
620           delta = 2.0 / (gnorm*gnorm);
621         }
622         ierr = MatLMVMSetDelta(nlsP->M, delta);CHKERRQ(ierr);
623         ierr = MatLMVMReset(nlsP->M);CHKERRQ(ierr);
624         ierr = MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);CHKERRQ(ierr);
625         ierr = MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);CHKERRQ(ierr);
626 
627         bfgsUpdates = 1;
628         ++nlsP->sgrad;
629         stepType = NLS_SCALED_GRADIENT;
630         break;
631 
632       case NLS_SCALED_GRADIENT:
633         /* Can only enter if pc_type == NLS_PC_BFGS
634            The scaled gradient step did not produce a new iterate;
635            attemp to use the gradient direction.
636            Need to make sure we are not using a different diagonal scaling */
637 
638         ierr = MatLMVMSetScale(nlsP->M,0);CHKERRQ(ierr);
639         ierr = MatLMVMSetDelta(nlsP->M,1.0);CHKERRQ(ierr);
640         ierr = MatLMVMReset(nlsP->M);CHKERRQ(ierr);
641         ierr = MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);CHKERRQ(ierr);
642         ierr = MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);CHKERRQ(ierr);
643 
644         bfgsUpdates = 1;
645         ++nlsP->grad;
646         stepType = NLS_GRADIENT;
647         break;
648       }
649       ierr = VecScale(nlsP->D, -1.0);CHKERRQ(ierr);
650 
651       ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, nlsP->D, &step, &ls_reason);CHKERRQ(ierr);
652       ierr = TaoLineSearchGetFullStepObjective(tao->linesearch, &f_full);CHKERRQ(ierr);
653       ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
654     }
655 
656     if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) {
657       /* Failed to find an improving point */
658       f = fold;
659       ierr = VecCopy(nlsP->Xold, tao->solution);CHKERRQ(ierr);
660       ierr = VecCopy(nlsP->Gold, tao->gradient);CHKERRQ(ierr);
661       step = 0.0;
662       reason = TAO_DIVERGED_LS_FAILURE;
663       tao->reason = TAO_DIVERGED_LS_FAILURE;
664       break;
665     }
666 
667     /* Update trust region radius */
668     if (is_nash || is_stcg || is_gltr) {
669       switch(nlsP->update_type) {
670       case NLS_UPDATE_STEP:
671         if (stepType == NLS_NEWTON) {
672           if (step < nlsP->nu1) {
673             /* Very bad step taken; reduce radius */
674             tao->trust = nlsP->omega1 * PetscMin(norm_d, tao->trust);
675           } else if (step < nlsP->nu2) {
676             /* Reasonably bad step taken; reduce radius */
677             tao->trust = nlsP->omega2 * PetscMin(norm_d, tao->trust);
678           } else if (step < nlsP->nu3) {
679             /*  Reasonable step was taken; leave radius alone */
680             if (nlsP->omega3 < 1.0) {
681               tao->trust = nlsP->omega3 * PetscMin(norm_d, tao->trust);
682             } else if (nlsP->omega3 > 1.0) {
683               tao->trust = PetscMax(nlsP->omega3 * norm_d, tao->trust);
684             }
685           } else if (step < nlsP->nu4) {
686             /*  Full step taken; increase the radius */
687             tao->trust = PetscMax(nlsP->omega4 * norm_d, tao->trust);
688           } else {
689             /*  More than full step taken; increase the radius */
690             tao->trust = PetscMax(nlsP->omega5 * norm_d, tao->trust);
691           }
692         } else {
693           /*  Newton step was not good; reduce the radius */
694           tao->trust = nlsP->omega1 * PetscMin(norm_d, tao->trust);
695         }
696         break;
697 
698       case NLS_UPDATE_REDUCTION:
699         if (stepType == NLS_NEWTON) {
700           /*  Get predicted reduction */
701 
702           ierr = KSPCGGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr);
703           if (prered >= 0.0) {
704             /*  The predicted reduction has the wrong sign.  This cannot */
705             /*  happen in infinite precision arithmetic.  Step should */
706             /*  be rejected! */
707             tao->trust = nlsP->alpha1 * PetscMin(tao->trust, norm_d);
708           } else {
709             if (PetscIsInfOrNanReal(f_full)) {
710               tao->trust = nlsP->alpha1 * PetscMin(tao->trust, norm_d);
711             } else {
712               /*  Compute and actual reduction */
713               actred = fold - f_full;
714               prered = -prered;
715               if ((PetscAbsScalar(actred) <= nlsP->epsilon) &&
716                   (PetscAbsScalar(prered) <= nlsP->epsilon)) {
717                 kappa = 1.0;
718               } else {
719                 kappa = actred / prered;
720               }
721 
722               /*  Accept of reject the step and update radius */
723               if (kappa < nlsP->eta1) {
724                 /*  Very bad step */
725                 tao->trust = nlsP->alpha1 * PetscMin(tao->trust, norm_d);
726               } else if (kappa < nlsP->eta2) {
727                 /*  Marginal bad step */
728                 tao->trust = nlsP->alpha2 * PetscMin(tao->trust, norm_d);
729               } else if (kappa < nlsP->eta3) {
730                 /*  Reasonable step */
731                 if (nlsP->alpha3 < 1.0) {
732                   tao->trust = nlsP->alpha3 * PetscMin(norm_d, tao->trust);
733                 } else if (nlsP->alpha3 > 1.0) {
734                   tao->trust = PetscMax(nlsP->alpha3 * norm_d, tao->trust);
735                 }
736               } else if (kappa < nlsP->eta4) {
737                 /*  Good step */
738                 tao->trust = PetscMax(nlsP->alpha4 * norm_d, tao->trust);
739               } else {
740                 /*  Very good step */
741                 tao->trust = PetscMax(nlsP->alpha5 * norm_d, tao->trust);
742               }
743             }
744           }
745         } else {
746           /*  Newton step was not good; reduce the radius */
747           tao->trust = nlsP->alpha1 * PetscMin(norm_d, tao->trust);
748         }
749         break;
750 
751       default:
752         if (stepType == NLS_NEWTON) {
753           ierr = KSPCGGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr);
754           if (prered >= 0.0) {
755             /*  The predicted reduction has the wrong sign.  This cannot */
756             /*  happen in infinite precision arithmetic.  Step should */
757             /*  be rejected! */
758             tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
759           } else {
760             if (PetscIsInfOrNanReal(f_full)) {
761               tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
762             } else {
763               actred = fold - f_full;
764               prered = -prered;
765               if ((PetscAbsScalar(actred) <= nlsP->epsilon) && (PetscAbsScalar(prered) <= nlsP->epsilon)) {
766                 kappa = 1.0;
767               } else {
768                 kappa = actred / prered;
769               }
770 
771               tau_1 = nlsP->theta * gdx / (nlsP->theta * gdx - (1.0 - nlsP->theta) * prered + actred);
772               tau_2 = nlsP->theta * gdx / (nlsP->theta * gdx + (1.0 + nlsP->theta) * prered - actred);
773               tau_min = PetscMin(tau_1, tau_2);
774               tau_max = PetscMax(tau_1, tau_2);
775 
776               if (kappa >= 1.0 - nlsP->mu1) {
777                 /*  Great agreement */
778                 if (tau_max < 1.0) {
779                   tao->trust = PetscMax(tao->trust, nlsP->gamma3 * norm_d);
780                 } else if (tau_max > nlsP->gamma4) {
781                   tao->trust = PetscMax(tao->trust, nlsP->gamma4 * norm_d);
782                 } else {
783                   tao->trust = PetscMax(tao->trust, tau_max * norm_d);
784                 }
785               } else if (kappa >= 1.0 - nlsP->mu2) {
786                 /*  Good agreement */
787 
788                 if (tau_max < nlsP->gamma2) {
789                   tao->trust = nlsP->gamma2 * PetscMin(tao->trust, norm_d);
790                 } else if (tau_max > nlsP->gamma3) {
791                   tao->trust = PetscMax(tao->trust, nlsP->gamma3 * norm_d);
792                 } else if (tau_max < 1.0) {
793                   tao->trust = tau_max * PetscMin(tao->trust, norm_d);
794                 } else {
795                   tao->trust = PetscMax(tao->trust, tau_max * norm_d);
796                 }
797               } else {
798                 /*  Not good agreement */
799                 if (tau_min > 1.0) {
800                   tao->trust = nlsP->gamma2 * PetscMin(tao->trust, norm_d);
801                 } else if (tau_max < nlsP->gamma1) {
802                   tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
803                 } else if ((tau_min < nlsP->gamma1) && (tau_max >= 1.0)) {
804                   tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
805                 } else if ((tau_1 >= nlsP->gamma1) && (tau_1 < 1.0) && ((tau_2 < nlsP->gamma1) || (tau_2 >= 1.0))) {
806                   tao->trust = tau_1 * PetscMin(tao->trust, norm_d);
807                 } else if ((tau_2 >= nlsP->gamma1) && (tau_2 < 1.0) && ((tau_1 < nlsP->gamma1) || (tau_2 >= 1.0))) {
808                   tao->trust = tau_2 * PetscMin(tao->trust, norm_d);
809                 } else {
810                   tao->trust = tau_max * PetscMin(tao->trust, norm_d);
811                 }
812               }
813             }
814           }
815         } else {
816           /*  Newton step was not good; reduce the radius */
817           tao->trust = nlsP->gamma1 * PetscMin(norm_d, tao->trust);
818         }
819         break;
820       }
821 
822       /*  The radius may have been increased; modify if it is too large */
823       tao->trust = PetscMin(tao->trust, nlsP->max_radius);
824     }
825 
826     /*  Check for termination */
827     ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
828     if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
829     needH = 1;
830     ierr = TaoMonitor(tao, tao->niter, f, gnorm, 0.0, step, &reason);CHKERRQ(ierr);
831   }
832   PetscFunctionReturn(0);
833 }
834 
835 /* ---------------------------------------------------------- */
836 #undef __FUNCT__
837 #define __FUNCT__ "TaoSetUp_NLS"
838 static PetscErrorCode TaoSetUp_NLS(Tao tao)
839 {
840   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;
841   PetscErrorCode ierr;
842 
843   PetscFunctionBegin;
844   if (!tao->gradient) {ierr = VecDuplicate(tao->solution,&tao->gradient);CHKERRQ(ierr);}
845   if (!tao->stepdirection) {ierr = VecDuplicate(tao->solution,&tao->stepdirection);CHKERRQ(ierr);}
846   if (!nlsP->W) {ierr = VecDuplicate(tao->solution,&nlsP->W);CHKERRQ(ierr);}
847   if (!nlsP->D) {ierr = VecDuplicate(tao->solution,&nlsP->D);CHKERRQ(ierr);}
848   if (!nlsP->Xold) {ierr = VecDuplicate(tao->solution,&nlsP->Xold);CHKERRQ(ierr);}
849   if (!nlsP->Gold) {ierr = VecDuplicate(tao->solution,&nlsP->Gold);CHKERRQ(ierr);}
850   nlsP->Diag = 0;
851   nlsP->M = 0;
852   PetscFunctionReturn(0);
853 }
854 
855 /*------------------------------------------------------------*/
856 #undef __FUNCT__
857 #define __FUNCT__ "TaoDestroy_NLS"
858 static PetscErrorCode TaoDestroy_NLS(Tao tao)
859 {
860   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;
861   PetscErrorCode ierr;
862 
863   PetscFunctionBegin;
864   if (tao->setupcalled) {
865     ierr = VecDestroy(&nlsP->D);CHKERRQ(ierr);
866     ierr = VecDestroy(&nlsP->W);CHKERRQ(ierr);
867     ierr = VecDestroy(&nlsP->Xold);CHKERRQ(ierr);
868     ierr = VecDestroy(&nlsP->Gold);CHKERRQ(ierr);
869   }
870   ierr = VecDestroy(&nlsP->Diag);CHKERRQ(ierr);
871   ierr = MatDestroy(&nlsP->M);CHKERRQ(ierr);
872   ierr = PetscFree(tao->data);CHKERRQ(ierr);
873   PetscFunctionReturn(0);
874 }
875 
876 /*------------------------------------------------------------*/
877 #undef __FUNCT__
878 #define __FUNCT__ "TaoSetFromOptions_NLS"
879 static PetscErrorCode TaoSetFromOptions_NLS(PetscOptionItems *PetscOptionsObject,Tao tao)
880 {
881   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;
882   PetscErrorCode ierr;
883 
884   PetscFunctionBegin;
885   ierr = PetscOptionsHead(PetscOptionsObject,"Newton line search method for unconstrained optimization");CHKERRQ(ierr);
886   ierr = PetscOptionsEList("-tao_nls_pc_type", "pc type", "", NLS_PC, NLS_PC_TYPES, NLS_PC[nlsP->pc_type], &nlsP->pc_type, 0);CHKERRQ(ierr);
887   ierr = PetscOptionsEList("-tao_nls_bfgs_scale_type", "bfgs scale type", "", BFGS_SCALE, BFGS_SCALE_TYPES, BFGS_SCALE[nlsP->bfgs_scale_type], &nlsP->bfgs_scale_type, 0);CHKERRQ(ierr);
888   ierr = PetscOptionsEList("-tao_nls_init_type", "radius initialization type", "", NLS_INIT, NLS_INIT_TYPES, NLS_INIT[nlsP->init_type], &nlsP->init_type, 0);CHKERRQ(ierr);
889   ierr = PetscOptionsEList("-tao_nls_update_type", "radius update type", "", NLS_UPDATE, NLS_UPDATE_TYPES, NLS_UPDATE[nlsP->update_type], &nlsP->update_type, 0);CHKERRQ(ierr);
890   ierr = PetscOptionsReal("-tao_nls_sval", "perturbation starting value", "", nlsP->sval, &nlsP->sval,NULL);CHKERRQ(ierr);
891   ierr = PetscOptionsReal("-tao_nls_imin", "minimum initial perturbation", "", nlsP->imin, &nlsP->imin,NULL);CHKERRQ(ierr);
892   ierr = PetscOptionsReal("-tao_nls_imax", "maximum initial perturbation", "", nlsP->imax, &nlsP->imax,NULL);CHKERRQ(ierr);
893   ierr = PetscOptionsReal("-tao_nls_imfac", "initial merit factor", "", nlsP->imfac, &nlsP->imfac,NULL);CHKERRQ(ierr);
894   ierr = PetscOptionsReal("-tao_nls_pmin", "minimum perturbation", "", nlsP->pmin, &nlsP->pmin,NULL);CHKERRQ(ierr);
895   ierr = PetscOptionsReal("-tao_nls_pmax", "maximum perturbation", "", nlsP->pmax, &nlsP->pmax,NULL);CHKERRQ(ierr);
896   ierr = PetscOptionsReal("-tao_nls_pgfac", "growth factor", "", nlsP->pgfac, &nlsP->pgfac,NULL);CHKERRQ(ierr);
897   ierr = PetscOptionsReal("-tao_nls_psfac", "shrink factor", "", nlsP->psfac, &nlsP->psfac,NULL);CHKERRQ(ierr);
898   ierr = PetscOptionsReal("-tao_nls_pmgfac", "merit growth factor", "", nlsP->pmgfac, &nlsP->pmgfac,NULL);CHKERRQ(ierr);
899   ierr = PetscOptionsReal("-tao_nls_pmsfac", "merit shrink factor", "", nlsP->pmsfac, &nlsP->pmsfac,NULL);CHKERRQ(ierr);
900   ierr = PetscOptionsReal("-tao_nls_eta1", "poor steplength; reduce radius", "", nlsP->eta1, &nlsP->eta1,NULL);CHKERRQ(ierr);
901   ierr = PetscOptionsReal("-tao_nls_eta2", "reasonable steplength; leave radius alone", "", nlsP->eta2, &nlsP->eta2,NULL);CHKERRQ(ierr);
902   ierr = PetscOptionsReal("-tao_nls_eta3", "good steplength; increase radius", "", nlsP->eta3, &nlsP->eta3,NULL);CHKERRQ(ierr);
903   ierr = PetscOptionsReal("-tao_nls_eta4", "excellent steplength; greatly increase radius", "", nlsP->eta4, &nlsP->eta4,NULL);CHKERRQ(ierr);
904   ierr = PetscOptionsReal("-tao_nls_alpha1", "", "", nlsP->alpha1, &nlsP->alpha1,NULL);CHKERRQ(ierr);
905   ierr = PetscOptionsReal("-tao_nls_alpha2", "", "", nlsP->alpha2, &nlsP->alpha2,NULL);CHKERRQ(ierr);
906   ierr = PetscOptionsReal("-tao_nls_alpha3", "", "", nlsP->alpha3, &nlsP->alpha3,NULL);CHKERRQ(ierr);
907   ierr = PetscOptionsReal("-tao_nls_alpha4", "", "", nlsP->alpha4, &nlsP->alpha4,NULL);CHKERRQ(ierr);
908   ierr = PetscOptionsReal("-tao_nls_alpha5", "", "", nlsP->alpha5, &nlsP->alpha5,NULL);CHKERRQ(ierr);
909   ierr = PetscOptionsReal("-tao_nls_nu1", "poor steplength; reduce radius", "", nlsP->nu1, &nlsP->nu1,NULL);CHKERRQ(ierr);
910   ierr = PetscOptionsReal("-tao_nls_nu2", "reasonable steplength; leave radius alone", "", nlsP->nu2, &nlsP->nu2,NULL);CHKERRQ(ierr);
911   ierr = PetscOptionsReal("-tao_nls_nu3", "good steplength; increase radius", "", nlsP->nu3, &nlsP->nu3,NULL);CHKERRQ(ierr);
912   ierr = PetscOptionsReal("-tao_nls_nu4", "excellent steplength; greatly increase radius", "", nlsP->nu4, &nlsP->nu4,NULL);CHKERRQ(ierr);
913   ierr = PetscOptionsReal("-tao_nls_omega1", "", "", nlsP->omega1, &nlsP->omega1,NULL);CHKERRQ(ierr);
914   ierr = PetscOptionsReal("-tao_nls_omega2", "", "", nlsP->omega2, &nlsP->omega2,NULL);CHKERRQ(ierr);
915   ierr = PetscOptionsReal("-tao_nls_omega3", "", "", nlsP->omega3, &nlsP->omega3,NULL);CHKERRQ(ierr);
916   ierr = PetscOptionsReal("-tao_nls_omega4", "", "", nlsP->omega4, &nlsP->omega4,NULL);CHKERRQ(ierr);
917   ierr = PetscOptionsReal("-tao_nls_omega5", "", "", nlsP->omega5, &nlsP->omega5,NULL);CHKERRQ(ierr);
918   ierr = PetscOptionsReal("-tao_nls_mu1_i", "", "", nlsP->mu1_i, &nlsP->mu1_i,NULL);CHKERRQ(ierr);
919   ierr = PetscOptionsReal("-tao_nls_mu2_i", "", "", nlsP->mu2_i, &nlsP->mu2_i,NULL);CHKERRQ(ierr);
920   ierr = PetscOptionsReal("-tao_nls_gamma1_i", "", "", nlsP->gamma1_i, &nlsP->gamma1_i,NULL);CHKERRQ(ierr);
921   ierr = PetscOptionsReal("-tao_nls_gamma2_i", "", "", nlsP->gamma2_i, &nlsP->gamma2_i,NULL);CHKERRQ(ierr);
922   ierr = PetscOptionsReal("-tao_nls_gamma3_i", "", "", nlsP->gamma3_i, &nlsP->gamma3_i,NULL);CHKERRQ(ierr);
923   ierr = PetscOptionsReal("-tao_nls_gamma4_i", "", "", nlsP->gamma4_i, &nlsP->gamma4_i,NULL);CHKERRQ(ierr);
924   ierr = PetscOptionsReal("-tao_nls_theta_i", "", "", nlsP->theta_i, &nlsP->theta_i,NULL);CHKERRQ(ierr);
925   ierr = PetscOptionsReal("-tao_nls_mu1", "", "", nlsP->mu1, &nlsP->mu1,NULL);CHKERRQ(ierr);
926   ierr = PetscOptionsReal("-tao_nls_mu2", "", "", nlsP->mu2, &nlsP->mu2,NULL);CHKERRQ(ierr);
927   ierr = PetscOptionsReal("-tao_nls_gamma1", "", "", nlsP->gamma1, &nlsP->gamma1,NULL);CHKERRQ(ierr);
928   ierr = PetscOptionsReal("-tao_nls_gamma2", "", "", nlsP->gamma2, &nlsP->gamma2,NULL);CHKERRQ(ierr);
929   ierr = PetscOptionsReal("-tao_nls_gamma3", "", "", nlsP->gamma3, &nlsP->gamma3,NULL);CHKERRQ(ierr);
930   ierr = PetscOptionsReal("-tao_nls_gamma4", "", "", nlsP->gamma4, &nlsP->gamma4,NULL);CHKERRQ(ierr);
931   ierr = PetscOptionsReal("-tao_nls_theta", "", "", nlsP->theta, &nlsP->theta,NULL);CHKERRQ(ierr);
932   ierr = PetscOptionsReal("-tao_nls_min_radius", "lower bound on initial radius", "", nlsP->min_radius, &nlsP->min_radius,NULL);CHKERRQ(ierr);
933   ierr = PetscOptionsReal("-tao_nls_max_radius", "upper bound on radius", "", nlsP->max_radius, &nlsP->max_radius,NULL);CHKERRQ(ierr);
934   ierr = PetscOptionsReal("-tao_nls_epsilon", "tolerance used when computing actual and predicted reduction", "", nlsP->epsilon, &nlsP->epsilon,NULL);CHKERRQ(ierr);
935   ierr = PetscOptionsTail();CHKERRQ(ierr);
936   ierr = TaoLineSearchSetFromOptions(tao->linesearch);CHKERRQ(ierr);
937   ierr = KSPSetFromOptions(tao->ksp);CHKERRQ(ierr);
938   PetscFunctionReturn(0);
939 }
940 
941 
942 /*------------------------------------------------------------*/
943 #undef __FUNCT__
944 #define __FUNCT__ "TaoView_NLS"
945 static PetscErrorCode TaoView_NLS(Tao tao, PetscViewer viewer)
946 {
947   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;
948   PetscInt       nrejects;
949   PetscBool      isascii;
950   PetscErrorCode ierr;
951 
952   PetscFunctionBegin;
953   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
954   if (isascii) {
955     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
956     if (NLS_PC_BFGS == nlsP->pc_type && nlsP->M) {
957       ierr = MatLMVMGetRejects(nlsP->M,&nrejects);CHKERRQ(ierr);
958       ierr = PetscViewerASCIIPrintf(viewer, "Rejected matrix updates: %D\n",nrejects);CHKERRQ(ierr);
959     }
960     ierr = PetscViewerASCIIPrintf(viewer, "Newton steps: %D\n", nlsP->newt);CHKERRQ(ierr);
961     ierr = PetscViewerASCIIPrintf(viewer, "BFGS steps: %D\n", nlsP->bfgs);CHKERRQ(ierr);
962     ierr = PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %D\n", nlsP->sgrad);CHKERRQ(ierr);
963     ierr = PetscViewerASCIIPrintf(viewer, "Gradient steps: %D\n", nlsP->grad);CHKERRQ(ierr);
964 
965     ierr = PetscViewerASCIIPrintf(viewer, "nls ksp atol: %D\n", nlsP->ksp_atol);CHKERRQ(ierr);
966     ierr = PetscViewerASCIIPrintf(viewer, "nls ksp rtol: %D\n", nlsP->ksp_rtol);CHKERRQ(ierr);
967     ierr = PetscViewerASCIIPrintf(viewer, "nls ksp ctol: %D\n", nlsP->ksp_ctol);CHKERRQ(ierr);
968     ierr = PetscViewerASCIIPrintf(viewer, "nls ksp negc: %D\n", nlsP->ksp_negc);CHKERRQ(ierr);
969     ierr = PetscViewerASCIIPrintf(viewer, "nls ksp dtol: %D\n", nlsP->ksp_dtol);CHKERRQ(ierr);
970     ierr = PetscViewerASCIIPrintf(viewer, "nls ksp iter: %D\n", nlsP->ksp_iter);CHKERRQ(ierr);
971     ierr = PetscViewerASCIIPrintf(viewer, "nls ksp othr: %D\n", nlsP->ksp_othr);CHKERRQ(ierr);
972     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
973   }
974   PetscFunctionReturn(0);
975 }
976 
977 /* ---------------------------------------------------------- */
978 /*MC
979   TAONLS - Newton's method with linesearch for unconstrained minimization.
980   At each iteration, the Newton line search method solves the symmetric
981   system of equations to obtain the step diretion dk:
982               Hk dk = -gk
983   a More-Thuente line search is applied on the direction dk to approximately
984   solve
985               min_t f(xk + t d_k)
986 
987     Options Database Keys:
988 + -tao_nls_pc_type - "none","ahess","bfgs","petsc"
989 . -tao_nls_bfgs_scale_type - "ahess","phess","bfgs"
990 . -tao_nls_init_type - "constant","direction","interpolation"
991 . -tao_nls_update_type - "step","direction","interpolation"
992 . -tao_nls_sval - perturbation starting value
993 . -tao_nls_imin - minimum initial perturbation
994 . -tao_nls_imax - maximum initial perturbation
995 . -tao_nls_pmin - minimum perturbation
996 . -tao_nls_pmax - maximum perturbation
997 . -tao_nls_pgfac - growth factor
998 . -tao_nls_psfac - shrink factor
999 . -tao_nls_imfac - initial merit factor
1000 . -tao_nls_pmgfac - merit growth factor
1001 . -tao_nls_pmsfac - merit shrink factor
1002 . -tao_nls_eta1 - poor steplength; reduce radius
1003 . -tao_nls_eta2 - reasonable steplength; leave radius
1004 . -tao_nls_eta3 - good steplength; increase readius
1005 . -tao_nls_eta4 - excellent steplength; greatly increase radius
1006 . -tao_nls_alpha1 - alpha1 reduction
1007 . -tao_nls_alpha2 - alpha2 reduction
1008 . -tao_nls_alpha3 - alpha3 reduction
1009 . -tao_nls_alpha4 - alpha4 reduction
1010 . -tao_nls_alpha - alpha5 reduction
1011 . -tao_nls_mu1 - mu1 interpolation update
1012 . -tao_nls_mu2 - mu2 interpolation update
1013 . -tao_nls_gamma1 - gamma1 interpolation update
1014 . -tao_nls_gamma2 - gamma2 interpolation update
1015 . -tao_nls_gamma3 - gamma3 interpolation update
1016 . -tao_nls_gamma4 - gamma4 interpolation update
1017 . -tao_nls_theta - theta interpolation update
1018 . -tao_nls_omega1 - omega1 step update
1019 . -tao_nls_omega2 - omega2 step update
1020 . -tao_nls_omega3 - omega3 step update
1021 . -tao_nls_omega4 - omega4 step update
1022 . -tao_nls_omega5 - omega5 step update
1023 . -tao_nls_mu1_i -  mu1 interpolation init factor
1024 . -tao_nls_mu2_i -  mu2 interpolation init factor
1025 . -tao_nls_gamma1_i -  gamma1 interpolation init factor
1026 . -tao_nls_gamma2_i -  gamma2 interpolation init factor
1027 . -tao_nls_gamma3_i -  gamma3 interpolation init factor
1028 . -tao_nls_gamma4_i -  gamma4 interpolation init factor
1029 - -tao_nls_theta_i -  theta interpolation init factor
1030 
1031   Level: beginner
1032 M*/
1033 
1034 #undef __FUNCT__
1035 #define __FUNCT__ "TaoCreate_NLS"
1036 PETSC_EXTERN PetscErrorCode TaoCreate_NLS(Tao tao)
1037 {
1038   TAO_NLS        *nlsP;
1039   const char     *morethuente_type = TAOLINESEARCHMT;
1040   PetscErrorCode ierr;
1041 
1042   PetscFunctionBegin;
1043   ierr = PetscNewLog(tao,&nlsP);CHKERRQ(ierr);
1044 
1045   tao->ops->setup = TaoSetUp_NLS;
1046   tao->ops->solve = TaoSolve_NLS;
1047   tao->ops->view = TaoView_NLS;
1048   tao->ops->setfromoptions = TaoSetFromOptions_NLS;
1049   tao->ops->destroy = TaoDestroy_NLS;
1050 
1051   /* Override default settings (unless already changed) */
1052   if (!tao->max_it_changed) tao->max_it = 50;
1053   if (!tao->trust0_changed) tao->trust0 = 100.0;
1054 
1055   tao->data = (void*)nlsP;
1056 
1057   nlsP->sval   = 0.0;
1058   nlsP->imin   = 1.0e-4;
1059   nlsP->imax   = 1.0e+2;
1060   nlsP->imfac  = 1.0e-1;
1061 
1062   nlsP->pmin   = 1.0e-12;
1063   nlsP->pmax   = 1.0e+2;
1064   nlsP->pgfac  = 1.0e+1;
1065   nlsP->psfac  = 4.0e-1;
1066   nlsP->pmgfac = 1.0e-1;
1067   nlsP->pmsfac = 1.0e-1;
1068 
1069   /*  Default values for trust-region radius update based on steplength */
1070   nlsP->nu1 = 0.25;
1071   nlsP->nu2 = 0.50;
1072   nlsP->nu3 = 1.00;
1073   nlsP->nu4 = 1.25;
1074 
1075   nlsP->omega1 = 0.25;
1076   nlsP->omega2 = 0.50;
1077   nlsP->omega3 = 1.00;
1078   nlsP->omega4 = 2.00;
1079   nlsP->omega5 = 4.00;
1080 
1081   /*  Default values for trust-region radius update based on reduction */
1082   nlsP->eta1 = 1.0e-4;
1083   nlsP->eta2 = 0.25;
1084   nlsP->eta3 = 0.50;
1085   nlsP->eta4 = 0.90;
1086 
1087   nlsP->alpha1 = 0.25;
1088   nlsP->alpha2 = 0.50;
1089   nlsP->alpha3 = 1.00;
1090   nlsP->alpha4 = 2.00;
1091   nlsP->alpha5 = 4.00;
1092 
1093   /*  Default values for trust-region radius update based on interpolation */
1094   nlsP->mu1 = 0.10;
1095   nlsP->mu2 = 0.50;
1096 
1097   nlsP->gamma1 = 0.25;
1098   nlsP->gamma2 = 0.50;
1099   nlsP->gamma3 = 2.00;
1100   nlsP->gamma4 = 4.00;
1101 
1102   nlsP->theta = 0.05;
1103 
1104   /*  Default values for trust region initialization based on interpolation */
1105   nlsP->mu1_i = 0.35;
1106   nlsP->mu2_i = 0.50;
1107 
1108   nlsP->gamma1_i = 0.0625;
1109   nlsP->gamma2_i = 0.5;
1110   nlsP->gamma3_i = 2.0;
1111   nlsP->gamma4_i = 5.0;
1112 
1113   nlsP->theta_i = 0.25;
1114 
1115   /*  Remaining parameters */
1116   nlsP->min_radius = 1.0e-10;
1117   nlsP->max_radius = 1.0e10;
1118   nlsP->epsilon = 1.0e-6;
1119 
1120   nlsP->pc_type         = NLS_PC_BFGS;
1121   nlsP->bfgs_scale_type = BFGS_SCALE_PHESS;
1122   nlsP->init_type       = NLS_INIT_INTERPOLATION;
1123   nlsP->update_type     = NLS_UPDATE_STEP;
1124 
1125   ierr = TaoLineSearchCreate(((PetscObject)tao)->comm,&tao->linesearch);CHKERRQ(ierr);
1126   ierr = TaoLineSearchSetType(tao->linesearch,morethuente_type);CHKERRQ(ierr);
1127   ierr = TaoLineSearchUseTaoRoutines(tao->linesearch,tao);CHKERRQ(ierr);
1128   ierr = TaoLineSearchSetOptionsPrefix(tao->linesearch,tao->hdr.prefix);CHKERRQ(ierr);
1129 
1130   /*  Set linear solver to default for symmetric matrices */
1131   ierr = KSPCreate(((PetscObject)tao)->comm,&tao->ksp);CHKERRQ(ierr);
1132   ierr = KSPSetOptionsPrefix(tao->ksp,tao->hdr.prefix);CHKERRQ(ierr);
1133   ierr = KSPSetType(tao->ksp,KSPCGSTCG);CHKERRQ(ierr);
1134   PetscFunctionReturn(0);
1135 }
1136 
1137