xref: /petsc/src/tao/unconstrained/impls/ntr/ntr.c (revision 5f309d014d30c8e30ef8d484fee079cd79b2cbfc)
1 #include <../src/tao/matrix/lmvmmat.h>
2 #include <../src/tao/unconstrained/impls/ntr/ntrimpl.h>
3 
4 #include <petscksp.h>
5 
6 #define NTR_PC_NONE     0
7 #define NTR_PC_AHESS    1
8 #define NTR_PC_BFGS     2
9 #define NTR_PC_PETSC    3
10 #define NTR_PC_TYPES    4
11 
12 #define BFGS_SCALE_AHESS   0
13 #define BFGS_SCALE_BFGS    1
14 #define BFGS_SCALE_TYPES   2
15 
16 #define NTR_INIT_CONSTANT         0
17 #define NTR_INIT_DIRECTION        1
18 #define NTR_INIT_INTERPOLATION    2
19 #define NTR_INIT_TYPES            3
20 
21 #define NTR_UPDATE_REDUCTION      0
22 #define NTR_UPDATE_INTERPOLATION  1
23 #define NTR_UPDATE_TYPES          2
24 
25 static const char *NTR_PC[64] = {"none","ahess","bfgs","petsc"};
26 
27 static const char *BFGS_SCALE[64] = {"ahess","bfgs"};
28 
29 static const char *NTR_INIT[64] = {"constant","direction","interpolation"};
30 
31 static const char *NTR_UPDATE[64] = {"reduction","interpolation"};
32 
33 /*  Routine for BFGS preconditioner */
34 #undef __FUNCT__
35 #define __FUNCT__ "MatLMVMSolveShell"
36 static PetscErrorCode MatLMVMSolveShell(PC pc, Vec b, Vec x)
37 {
38     PetscErrorCode ierr;
39     Mat M;
40     PetscFunctionBegin;
41     PetscValidHeaderSpecific(pc,PC_CLASSID,1);
42     PetscValidHeaderSpecific(b,VEC_CLASSID,2);
43     PetscValidHeaderSpecific(x,VEC_CLASSID,3);
44     ierr = PCShellGetContext(pc,(void**)&M);CHKERRQ(ierr);
45     ierr = MatLMVMSolve(M, b, x);CHKERRQ(ierr);
46     PetscFunctionReturn(0);
47 }
48 
49 /*
50    TaoSolve_NTR - Implements Newton's Method with a trust region approach
51    for solving unconstrained minimization problems.
52 
53    The basic algorithm is taken from MINPACK-2 (dstrn).
54 
55    TaoSolve_NTR computes a local minimizer of a twice differentiable function
56    f by applying a trust region variant of Newton's method.  At each stage
57    of the algorithm, we use the prconditioned conjugate gradient method to
58    determine an approximate minimizer of the quadratic equation
59 
60         q(s) = <s, Hs + g>
61 
62    subject to the trust region constraint
63 
64         || s ||_M <= radius,
65 
66    where radius is the trust region radius and M is a symmetric positive
67    definite matrix (the preconditioner).  Here g is the gradient and H
68    is the Hessian matrix.
69 
70    Note:  TaoSolve_NTR MUST use the iterative solver KSPCGNASH, KSPCGSTCG,
71           or KSPCGGLTR.  Thus, we set KSPCGNASH, KSPCGSTCG, or KSPCGGLTR in this
72           routine regardless of what the user may have previously specified.
73 */
74 #undef __FUNCT__
75 #define __FUNCT__ "TaoSolve_NTR"
76 static PetscErrorCode TaoSolve_NTR(Tao tao)
77 {
78   TAO_NTR            *tr = (TAO_NTR *)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   PetscReal          fmin, ftrial, prered, actred, kappa, sigma, beta;
85   PetscReal          tau, tau_1, tau_2, tau_max, tau_min, max_radius;
86   PetscReal          f, gnorm;
87 
88   PetscReal          delta;
89   PetscReal          norm_d;
90   PetscErrorCode     ierr;
91   PetscInt           bfgsUpdates = 0;
92   PetscInt           needH;
93 
94   PetscInt           i_max = 5;
95   PetscInt           j_max = 1;
96   PetscInt           i, j, N, n, its;
97 
98   PetscFunctionBegin;
99   if (tao->XL || tao->XU || tao->ops->computebounds) {
100     ierr = PetscPrintf(((PetscObject)tao)->comm,"WARNING: Variable bounds have been set but will be ignored by ntr algorithm\n");CHKERRQ(ierr);
101   }
102 
103   ierr = KSPGetType(tao->ksp,&ksp_type);CHKERRQ(ierr);
104   ierr = PetscStrcmp(ksp_type,KSPCGNASH,&is_nash);CHKERRQ(ierr);
105   ierr = PetscStrcmp(ksp_type,KSPCGSTCG,&is_stcg);CHKERRQ(ierr);
106   ierr = PetscStrcmp(ksp_type,KSPCGGLTR,&is_gltr);CHKERRQ(ierr);
107   if (!is_nash && !is_stcg && !is_gltr) {
108     SETERRQ(PETSC_COMM_SELF,1,"TAO_NTR requires nash, stcg, or gltr for the KSP");
109   }
110 
111   /* Initialize the radius and modify if it is too large or small */
112   tao->trust = tao->trust0;
113   tao->trust = PetscMax(tao->trust, tr->min_radius);
114   tao->trust = PetscMin(tao->trust, tr->max_radius);
115 
116   if (NTR_PC_BFGS == tr->pc_type && !tr->M) {
117     ierr = VecGetLocalSize(tao->solution,&n);CHKERRQ(ierr);
118     ierr = VecGetSize(tao->solution,&N);CHKERRQ(ierr);
119     ierr = MatCreateLMVM(((PetscObject)tao)->comm,n,N,&tr->M);CHKERRQ(ierr);
120     ierr = MatLMVMAllocateVectors(tr->M,tao->solution);CHKERRQ(ierr);
121   }
122 
123   /* Check convergence criteria */
124   ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient);CHKERRQ(ierr);
125   ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
126   if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Inf or NaN");
127   needH = 1;
128 
129   ierr = TaoMonitor(tao, tao->niter, f, gnorm, 0.0, 1.0, &reason);CHKERRQ(ierr);
130   if (reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
131 
132   /* Create vectors for the limited memory preconditioner */
133   if ((NTR_PC_BFGS == tr->pc_type) && (BFGS_SCALE_BFGS != tr->bfgs_scale_type)) {
134     if (!tr->Diag) {
135         ierr = VecDuplicate(tao->solution, &tr->Diag);CHKERRQ(ierr);
136     }
137   }
138 
139   /*  Modify the preconditioner to use the bfgs approximation */
140   ierr = KSPGetPC(tao->ksp, &pc);CHKERRQ(ierr);
141   switch(tr->pc_type) {
142   case NTR_PC_NONE:
143     ierr = PCSetType(pc, PCNONE);CHKERRQ(ierr);
144     ierr = PCSetFromOptions(pc);CHKERRQ(ierr);
145     break;
146 
147   case NTR_PC_AHESS:
148     ierr = PCSetType(pc, PCJACOBI);CHKERRQ(ierr);
149     ierr = PCSetFromOptions(pc);CHKERRQ(ierr);
150     ierr = PCJacobiSetUseAbs(pc,PETSC_TRUE);CHKERRQ(ierr);
151     break;
152 
153   case NTR_PC_BFGS:
154     ierr = PCSetType(pc, PCSHELL);CHKERRQ(ierr);
155     ierr = PCSetFromOptions(pc);CHKERRQ(ierr);
156     ierr = PCShellSetName(pc, "bfgs");CHKERRQ(ierr);
157     ierr = PCShellSetContext(pc, tr->M);CHKERRQ(ierr);
158     ierr = PCShellSetApply(pc, MatLMVMSolveShell);CHKERRQ(ierr);
159     break;
160 
161   default:
162     /*  Use the pc method set by pc_type */
163     break;
164   }
165 
166   /*  Initialize trust-region radius */
167   switch(tr->init_type) {
168   case NTR_INIT_CONSTANT:
169     /*  Use the initial radius specified */
170     break;
171 
172   case NTR_INIT_INTERPOLATION:
173     /*  Use the initial radius specified */
174     max_radius = 0.0;
175 
176     for (j = 0; j < j_max; ++j) {
177       fmin = f;
178       sigma = 0.0;
179 
180       if (needH) {
181         ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
182         needH = 0;
183       }
184 
185       for (i = 0; i < i_max; ++i) {
186 
187         ierr = VecCopy(tao->solution, tr->W);CHKERRQ(ierr);
188         ierr = VecAXPY(tr->W, -tao->trust/gnorm, tao->gradient);CHKERRQ(ierr);
189         ierr = TaoComputeObjective(tao, tr->W, &ftrial);CHKERRQ(ierr);
190 
191         if (PetscIsInfOrNanReal(ftrial)) {
192           tau = tr->gamma1_i;
193         }
194         else {
195           if (ftrial < fmin) {
196             fmin = ftrial;
197             sigma = -tao->trust / gnorm;
198           }
199 
200           ierr = MatMult(tao->hessian, tao->gradient, tao->stepdirection);CHKERRQ(ierr);
201           ierr = VecDot(tao->gradient, tao->stepdirection, &prered);CHKERRQ(ierr);
202 
203           prered = tao->trust * (gnorm - 0.5 * tao->trust * prered / (gnorm * gnorm));
204           actred = f - ftrial;
205           if ((PetscAbsScalar(actred) <= tr->epsilon) &&
206               (PetscAbsScalar(prered) <= tr->epsilon)) {
207             kappa = 1.0;
208           }
209           else {
210             kappa = actred / prered;
211           }
212 
213           tau_1 = tr->theta_i * gnorm * tao->trust / (tr->theta_i * gnorm * tao->trust + (1.0 - tr->theta_i) * prered - actred);
214           tau_2 = tr->theta_i * gnorm * tao->trust / (tr->theta_i * gnorm * tao->trust - (1.0 + tr->theta_i) * prered + actred);
215           tau_min = PetscMin(tau_1, tau_2);
216           tau_max = PetscMax(tau_1, tau_2);
217 
218           if (PetscAbsScalar(kappa - 1.0) <= tr->mu1_i) {
219             /*  Great agreement */
220             max_radius = PetscMax(max_radius, tao->trust);
221 
222             if (tau_max < 1.0) {
223               tau = tr->gamma3_i;
224             }
225             else if (tau_max > tr->gamma4_i) {
226               tau = tr->gamma4_i;
227             }
228             else {
229               tau = tau_max;
230             }
231           }
232           else if (PetscAbsScalar(kappa - 1.0) <= tr->mu2_i) {
233             /*  Good agreement */
234             max_radius = PetscMax(max_radius, tao->trust);
235 
236             if (tau_max < tr->gamma2_i) {
237               tau = tr->gamma2_i;
238             }
239             else if (tau_max > tr->gamma3_i) {
240               tau = tr->gamma3_i;
241             }
242             else {
243               tau = tau_max;
244             }
245           }
246           else {
247             /*  Not good agreement */
248             if (tau_min > 1.0) {
249               tau = tr->gamma2_i;
250             }
251             else if (tau_max < tr->gamma1_i) {
252               tau = tr->gamma1_i;
253             }
254             else if ((tau_min < tr->gamma1_i) && (tau_max >= 1.0)) {
255               tau = tr->gamma1_i;
256             }
257             else if ((tau_1 >= tr->gamma1_i) && (tau_1 < 1.0) &&
258                      ((tau_2 < tr->gamma1_i) || (tau_2 >= 1.0))) {
259               tau = tau_1;
260             }
261             else if ((tau_2 >= tr->gamma1_i) && (tau_2 < 1.0) &&
262                      ((tau_1 < tr->gamma1_i) || (tau_2 >= 1.0))) {
263               tau = tau_2;
264             }
265             else {
266               tau = tau_max;
267             }
268           }
269         }
270         tao->trust = tau * tao->trust;
271       }
272 
273       if (fmin < f) {
274         f = fmin;
275         ierr = VecAXPY(tao->solution, sigma, tao->gradient);CHKERRQ(ierr);
276         ierr = TaoComputeGradient(tao,tao->solution, tao->gradient);CHKERRQ(ierr);
277 
278         ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
279 
280         if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
281         needH = 1;
282 
283         ierr = TaoMonitor(tao, tao->niter, f, gnorm, 0.0, 1.0, &reason);CHKERRQ(ierr);
284         if (reason != TAO_CONTINUE_ITERATING) {
285           PetscFunctionReturn(0);
286         }
287       }
288     }
289     tao->trust = PetscMax(tao->trust, max_radius);
290 
291     /*  Modify the radius if it is too large or small */
292     tao->trust = PetscMax(tao->trust, tr->min_radius);
293     tao->trust = PetscMin(tao->trust, tr->max_radius);
294     break;
295 
296   default:
297     /*  Norm of the first direction will initialize radius */
298     tao->trust = 0.0;
299     break;
300   }
301 
302   /* Set initial scaling for the BFGS preconditioner
303      This step is done after computing the initial trust-region radius
304      since the function value may have decreased */
305   if (NTR_PC_BFGS == tr->pc_type) {
306     if (f != 0.0) {
307       delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
308     }
309     else {
310       delta = 2.0 / (gnorm*gnorm);
311     }
312     ierr = MatLMVMSetDelta(tr->M,delta);CHKERRQ(ierr);
313   }
314 
315   /* Have not converged; continue with Newton method */
316   while (reason == TAO_CONTINUE_ITERATING) {
317     ++tao->niter;
318     tao->ksp_its=0;
319     /* Compute the Hessian */
320     if (needH) {
321       ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
322       needH = 0;
323     }
324 
325     if (NTR_PC_BFGS == tr->pc_type) {
326       if (BFGS_SCALE_AHESS == tr->bfgs_scale_type) {
327         /* Obtain diagonal for the bfgs preconditioner */
328         ierr = MatGetDiagonal(tao->hessian, tr->Diag);CHKERRQ(ierr);
329         ierr = VecAbs(tr->Diag);CHKERRQ(ierr);
330         ierr = VecReciprocal(tr->Diag);CHKERRQ(ierr);
331         ierr = MatLMVMSetScale(tr->M,tr->Diag);CHKERRQ(ierr);
332       }
333 
334       /* Update the limited memory preconditioner */
335       ierr = MatLMVMUpdate(tr->M, tao->solution, tao->gradient);CHKERRQ(ierr);
336       ++bfgsUpdates;
337     }
338 
339     while (reason == TAO_CONTINUE_ITERATING) {
340       ierr = KSPSetOperators(tao->ksp, tao->hessian, tao->hessian_pre);CHKERRQ(ierr);
341 
342       /* Solve the trust region subproblem */
343       ierr = KSPCGSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr);
344       ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr);
345       ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr);
346       tao->ksp_its+=its;
347       tao->ksp_tot_its+=its;
348       ierr = KSPCGGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr);
349 
350       if (0.0 == tao->trust) {
351         /* Radius was uninitialized; use the norm of the direction */
352         if (norm_d > 0.0) {
353           tao->trust = norm_d;
354 
355           /* Modify the radius if it is too large or small */
356           tao->trust = PetscMax(tao->trust, tr->min_radius);
357           tao->trust = PetscMin(tao->trust, tr->max_radius);
358         }
359         else {
360           /* The direction was bad; set radius to default value and re-solve
361              the trust-region subproblem to get a direction */
362           tao->trust = tao->trust0;
363 
364           /* Modify the radius if it is too large or small */
365           tao->trust = PetscMax(tao->trust, tr->min_radius);
366           tao->trust = PetscMin(tao->trust, tr->max_radius);
367 
368           ierr = KSPCGSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr);
369           ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr);
370           ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr);
371           tao->ksp_its+=its;
372           tao->ksp_tot_its+=its;
373           ierr = KSPCGGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr);
374 
375           if (norm_d == 0.0) SETERRQ(PETSC_COMM_SELF,1, "Initial direction zero");
376         }
377       }
378       ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr);
379       ierr = KSPGetConvergedReason(tao->ksp, &ksp_reason);CHKERRQ(ierr);
380       if ((KSP_DIVERGED_INDEFINITE_PC == ksp_reason) &&
381           (NTR_PC_BFGS == tr->pc_type) && (bfgsUpdates > 1)) {
382         /* Preconditioner is numerically indefinite; reset the
383            approximate if using BFGS preconditioning. */
384 
385         if (f != 0.0) {
386           delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
387         }
388         else {
389           delta = 2.0 / (gnorm*gnorm);
390         }
391         ierr = MatLMVMSetDelta(tr->M, delta);CHKERRQ(ierr);
392         ierr = MatLMVMReset(tr->M);CHKERRQ(ierr);
393         ierr = MatLMVMUpdate(tr->M, tao->solution, tao->gradient);CHKERRQ(ierr);
394         bfgsUpdates = 1;
395       }
396 
397       if (NTR_UPDATE_REDUCTION == tr->update_type) {
398         /* Get predicted reduction */
399         ierr = KSPCGGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr);
400         if (prered >= 0.0) {
401           /* The predicted reduction has the wrong sign.  This cannot
402              happen in infinite precision arithmetic.  Step should
403              be rejected! */
404           tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d);
405         }
406         else {
407           /* Compute trial step and function value */
408           ierr = VecCopy(tao->solution,tr->W);CHKERRQ(ierr);
409           ierr = VecAXPY(tr->W, 1.0, tao->stepdirection);CHKERRQ(ierr);
410           ierr = TaoComputeObjective(tao, tr->W, &ftrial);CHKERRQ(ierr);
411 
412           if (PetscIsInfOrNanReal(ftrial)) {
413             tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d);
414           } else {
415             /* Compute and actual reduction */
416             actred = f - ftrial;
417             prered = -prered;
418             if ((PetscAbsScalar(actred) <= tr->epsilon) &&
419                 (PetscAbsScalar(prered) <= tr->epsilon)) {
420               kappa = 1.0;
421             }
422             else {
423               kappa = actred / prered;
424             }
425 
426             /* Accept or reject the step and update radius */
427             if (kappa < tr->eta1) {
428               /* Reject the step */
429               tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d);
430             }
431             else {
432               /* Accept the step */
433               if (kappa < tr->eta2) {
434                 /* Marginal bad step */
435                 tao->trust = tr->alpha2 * PetscMin(tao->trust, norm_d);
436               }
437               else if (kappa < tr->eta3) {
438                 /* Reasonable step */
439                 tao->trust = tr->alpha3 * tao->trust;
440               }
441               else if (kappa < tr->eta4) {
442                 /* Good step */
443                 tao->trust = PetscMax(tr->alpha4 * norm_d, tao->trust);
444               }
445               else {
446                 /* Very good step */
447                 tao->trust = PetscMax(tr->alpha5 * norm_d, tao->trust);
448               }
449               break;
450             }
451           }
452         }
453       }
454       else {
455         /* Get predicted reduction */
456         ierr = KSPCGGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr);
457         if (prered >= 0.0) {
458           /* The predicted reduction has the wrong sign.  This cannot
459              happen in infinite precision arithmetic.  Step should
460              be rejected! */
461           tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
462         }
463         else {
464           ierr = VecCopy(tao->solution, tr->W);CHKERRQ(ierr);
465           ierr = VecAXPY(tr->W, 1.0, tao->stepdirection);CHKERRQ(ierr);
466           ierr = TaoComputeObjective(tao, tr->W, &ftrial);CHKERRQ(ierr);
467           if (PetscIsInfOrNanReal(ftrial)) {
468             tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
469           }
470           else {
471             ierr = VecDot(tao->gradient, tao->stepdirection, &beta);CHKERRQ(ierr);
472             actred = f - ftrial;
473             prered = -prered;
474             if ((PetscAbsScalar(actred) <= tr->epsilon) &&
475                 (PetscAbsScalar(prered) <= tr->epsilon)) {
476               kappa = 1.0;
477             }
478             else {
479               kappa = actred / prered;
480             }
481 
482             tau_1 = tr->theta * beta / (tr->theta * beta - (1.0 - tr->theta) * prered + actred);
483             tau_2 = tr->theta * beta / (tr->theta * beta + (1.0 + tr->theta) * prered - actred);
484             tau_min = PetscMin(tau_1, tau_2);
485             tau_max = PetscMax(tau_1, tau_2);
486 
487             if (kappa >= 1.0 - tr->mu1) {
488               /* Great agreement; accept step and update radius */
489               if (tau_max < 1.0) {
490                 tao->trust = PetscMax(tao->trust, tr->gamma3 * norm_d);
491               }
492               else if (tau_max > tr->gamma4) {
493                 tao->trust = PetscMax(tao->trust, tr->gamma4 * norm_d);
494               }
495               else {
496                 tao->trust = PetscMax(tao->trust, tau_max * norm_d);
497               }
498               break;
499             }
500             else if (kappa >= 1.0 - tr->mu2) {
501               /* Good agreement */
502 
503               if (tau_max < tr->gamma2) {
504                 tao->trust = tr->gamma2 * PetscMin(tao->trust, norm_d);
505               }
506               else if (tau_max > tr->gamma3) {
507                 tao->trust = PetscMax(tao->trust, tr->gamma3 * norm_d);
508               }
509               else if (tau_max < 1.0) {
510                 tao->trust = tau_max * PetscMin(tao->trust, norm_d);
511               }
512               else {
513                 tao->trust = PetscMax(tao->trust, tau_max * norm_d);
514               }
515               break;
516             }
517             else {
518               /* Not good agreement */
519               if (tau_min > 1.0) {
520                 tao->trust = tr->gamma2 * PetscMin(tao->trust, norm_d);
521               }
522               else if (tau_max < tr->gamma1) {
523                 tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
524               }
525               else if ((tau_min < tr->gamma1) && (tau_max >= 1.0)) {
526                 tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
527               }
528               else if ((tau_1 >= tr->gamma1) && (tau_1 < 1.0) &&
529                        ((tau_2 < tr->gamma1) || (tau_2 >= 1.0))) {
530                 tao->trust = tau_1 * PetscMin(tao->trust, norm_d);
531               }
532               else if ((tau_2 >= tr->gamma1) && (tau_2 < 1.0) &&
533                        ((tau_1 < tr->gamma1) || (tau_2 >= 1.0))) {
534                 tao->trust = tau_2 * PetscMin(tao->trust, norm_d);
535               }
536               else {
537                 tao->trust = tau_max * PetscMin(tao->trust, norm_d);
538               }
539             }
540           }
541         }
542       }
543 
544       /* The step computed was not good and the radius was decreased.
545          Monitor the radius to terminate. */
546       ierr = TaoMonitor(tao, tao->niter, f, gnorm, 0.0, tao->trust, &reason);CHKERRQ(ierr);
547     }
548 
549     /* The radius may have been increased; modify if it is too large */
550     tao->trust = PetscMin(tao->trust, tr->max_radius);
551 
552     if (reason == TAO_CONTINUE_ITERATING) {
553       ierr = VecCopy(tr->W, tao->solution);CHKERRQ(ierr);
554       f = ftrial;
555       ierr = TaoComputeGradient(tao, tao->solution, tao->gradient);CHKERRQ(ierr);
556       ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
557       if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
558       needH = 1;
559       ierr = TaoMonitor(tao, tao->niter, f, gnorm, 0.0, tao->trust, &reason);CHKERRQ(ierr);
560     }
561   }
562   PetscFunctionReturn(0);
563 }
564 
565 /*------------------------------------------------------------*/
566 #undef __FUNCT__
567 #define __FUNCT__ "TaoSetUp_NTR"
568 static PetscErrorCode TaoSetUp_NTR(Tao tao)
569 {
570   TAO_NTR *tr = (TAO_NTR *)tao->data;
571   PetscErrorCode ierr;
572 
573   PetscFunctionBegin;
574   if (!tao->gradient) {ierr = VecDuplicate(tao->solution, &tao->gradient);CHKERRQ(ierr);}
575   if (!tao->stepdirection) {ierr = VecDuplicate(tao->solution, &tao->stepdirection);CHKERRQ(ierr);}
576   if (!tr->W) {ierr = VecDuplicate(tao->solution, &tr->W);CHKERRQ(ierr);}
577 
578   tr->Diag = 0;
579   tr->M = 0;
580   PetscFunctionReturn(0);
581 }
582 
583 /*------------------------------------------------------------*/
584 #undef __FUNCT__
585 #define __FUNCT__ "TaoDestroy_NTR"
586 static PetscErrorCode TaoDestroy_NTR(Tao tao)
587 {
588   TAO_NTR        *tr = (TAO_NTR *)tao->data;
589   PetscErrorCode ierr;
590 
591   PetscFunctionBegin;
592   if (tao->setupcalled) {
593     ierr = VecDestroy(&tr->W);CHKERRQ(ierr);
594   }
595   ierr = MatDestroy(&tr->M);CHKERRQ(ierr);
596   ierr = VecDestroy(&tr->Diag);CHKERRQ(ierr);
597   ierr = PetscFree(tao->data);CHKERRQ(ierr);
598   PetscFunctionReturn(0);
599 }
600 
601 /*------------------------------------------------------------*/
602 #undef __FUNCT__
603 #define __FUNCT__ "TaoSetFromOptions_NTR"
604 static PetscErrorCode TaoSetFromOptions_NTR(PetscOptionItems *PetscOptionsObject,Tao tao)
605 {
606   TAO_NTR        *tr = (TAO_NTR *)tao->data;
607   PetscErrorCode ierr;
608 
609   PetscFunctionBegin;
610   ierr = PetscOptionsHead(PetscOptionsObject,"Newton trust region method for unconstrained optimization");CHKERRQ(ierr);
611   ierr = PetscOptionsEList("-tao_ntr_pc_type", "pc type", "", NTR_PC, NTR_PC_TYPES, NTR_PC[tr->pc_type], &tr->pc_type,NULL);CHKERRQ(ierr);
612   ierr = PetscOptionsEList("-tao_ntr_bfgs_scale_type", "bfgs scale type", "", BFGS_SCALE, BFGS_SCALE_TYPES, BFGS_SCALE[tr->bfgs_scale_type], &tr->bfgs_scale_type,NULL);CHKERRQ(ierr);
613   ierr = PetscOptionsEList("-tao_ntr_init_type", "tao->trust initialization type", "", NTR_INIT, NTR_INIT_TYPES, NTR_INIT[tr->init_type], &tr->init_type,NULL);CHKERRQ(ierr);
614   ierr = PetscOptionsEList("-tao_ntr_update_type", "radius update type", "", NTR_UPDATE, NTR_UPDATE_TYPES, NTR_UPDATE[tr->update_type], &tr->update_type,NULL);CHKERRQ(ierr);
615   ierr = PetscOptionsReal("-tao_ntr_eta1", "step is unsuccessful if actual reduction < eta1 * predicted reduction", "", tr->eta1, &tr->eta1,NULL);CHKERRQ(ierr);
616   ierr = PetscOptionsReal("-tao_ntr_eta2", "", "", tr->eta2, &tr->eta2,NULL);CHKERRQ(ierr);
617   ierr = PetscOptionsReal("-tao_ntr_eta3", "", "", tr->eta3, &tr->eta3,NULL);CHKERRQ(ierr);
618   ierr = PetscOptionsReal("-tao_ntr_eta4", "", "", tr->eta4, &tr->eta4,NULL);CHKERRQ(ierr);
619   ierr = PetscOptionsReal("-tao_ntr_alpha1", "", "", tr->alpha1, &tr->alpha1,NULL);CHKERRQ(ierr);
620   ierr = PetscOptionsReal("-tao_ntr_alpha2", "", "", tr->alpha2, &tr->alpha2,NULL);CHKERRQ(ierr);
621   ierr = PetscOptionsReal("-tao_ntr_alpha3", "", "", tr->alpha3, &tr->alpha3,NULL);CHKERRQ(ierr);
622   ierr = PetscOptionsReal("-tao_ntr_alpha4", "", "", tr->alpha4, &tr->alpha4,NULL);CHKERRQ(ierr);
623   ierr = PetscOptionsReal("-tao_ntr_alpha5", "", "", tr->alpha5, &tr->alpha5,NULL);CHKERRQ(ierr);
624   ierr = PetscOptionsReal("-tao_ntr_mu1", "", "", tr->mu1, &tr->mu1,NULL);CHKERRQ(ierr);
625   ierr = PetscOptionsReal("-tao_ntr_mu2", "", "", tr->mu2, &tr->mu2,NULL);CHKERRQ(ierr);
626   ierr = PetscOptionsReal("-tao_ntr_gamma1", "", "", tr->gamma1, &tr->gamma1,NULL);CHKERRQ(ierr);
627   ierr = PetscOptionsReal("-tao_ntr_gamma2", "", "", tr->gamma2, &tr->gamma2,NULL);CHKERRQ(ierr);
628   ierr = PetscOptionsReal("-tao_ntr_gamma3", "", "", tr->gamma3, &tr->gamma3,NULL);CHKERRQ(ierr);
629   ierr = PetscOptionsReal("-tao_ntr_gamma4", "", "", tr->gamma4, &tr->gamma4,NULL);CHKERRQ(ierr);
630   ierr = PetscOptionsReal("-tao_ntr_theta", "", "", tr->theta, &tr->theta,NULL);CHKERRQ(ierr);
631   ierr = PetscOptionsReal("-tao_ntr_mu1_i", "", "", tr->mu1_i, &tr->mu1_i,NULL);CHKERRQ(ierr);
632   ierr = PetscOptionsReal("-tao_ntr_mu2_i", "", "", tr->mu2_i, &tr->mu2_i,NULL);CHKERRQ(ierr);
633   ierr = PetscOptionsReal("-tao_ntr_gamma1_i", "", "", tr->gamma1_i, &tr->gamma1_i,NULL);CHKERRQ(ierr);
634   ierr = PetscOptionsReal("-tao_ntr_gamma2_i", "", "", tr->gamma2_i, &tr->gamma2_i,NULL);CHKERRQ(ierr);
635   ierr = PetscOptionsReal("-tao_ntr_gamma3_i", "", "", tr->gamma3_i, &tr->gamma3_i,NULL);CHKERRQ(ierr);
636   ierr = PetscOptionsReal("-tao_ntr_gamma4_i", "", "", tr->gamma4_i, &tr->gamma4_i,NULL);CHKERRQ(ierr);
637   ierr = PetscOptionsReal("-tao_ntr_theta_i", "", "", tr->theta_i, &tr->theta_i,NULL);CHKERRQ(ierr);
638   ierr = PetscOptionsReal("-tao_ntr_min_radius", "lower bound on initial trust-region radius", "", tr->min_radius, &tr->min_radius,NULL);CHKERRQ(ierr);
639   ierr = PetscOptionsReal("-tao_ntr_max_radius", "upper bound on trust-region radius", "", tr->max_radius, &tr->max_radius,NULL);CHKERRQ(ierr);
640   ierr = PetscOptionsReal("-tao_ntr_epsilon", "tolerance used when computing actual and predicted reduction", "", tr->epsilon, &tr->epsilon,NULL);CHKERRQ(ierr);
641   ierr = PetscOptionsTail();CHKERRQ(ierr);
642   ierr = KSPSetFromOptions(tao->ksp);CHKERRQ(ierr);
643   PetscFunctionReturn(0);
644 }
645 
646 /*------------------------------------------------------------*/
647 #undef __FUNCT__
648 #define __FUNCT__ "TaoView_NTR"
649 static PetscErrorCode TaoView_NTR(Tao tao, PetscViewer viewer)
650 {
651   TAO_NTR        *tr = (TAO_NTR *)tao->data;
652   PetscErrorCode ierr;
653   PetscInt       nrejects;
654   PetscBool      isascii;
655 
656   PetscFunctionBegin;
657   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
658   if (isascii) {
659     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
660     if (NTR_PC_BFGS == tr->pc_type && tr->M) {
661       ierr = MatLMVMGetRejects(tr->M, &nrejects);CHKERRQ(ierr);
662       ierr = PetscViewerASCIIPrintf(viewer, "Rejected matrix updates: %D\n", nrejects);CHKERRQ(ierr);
663     }
664     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
665   }
666   PetscFunctionReturn(0);
667 }
668 
669 /*------------------------------------------------------------*/
670 /*MC
671   TAONTR - Newton's method with trust region for unconstrained minimization.
672   At each iteration, the Newton trust region method solves the system.
673   NTR expects a KSP solver with a trust region radius.
674             min_d  .5 dT Hk d + gkT d,  s.t.   ||d|| < Delta_k
675 
676   Options Database Keys:
677 + -tao_ntr_pc_type - "none","ahess","bfgs","petsc"
678 . -tao_ntr_bfgs_scale_type - type of scaling with bfgs pc, "ahess" or "bfgs"
679 . -tao_ntr_init_type - "constant","direction","interpolation"
680 . -tao_ntr_update_type - "reduction","interpolation"
681 . -tao_ntr_min_radius - lower bound on trust region radius
682 . -tao_ntr_max_radius - upper bound on trust region radius
683 . -tao_ntr_epsilon - tolerance for accepting actual / predicted reduction
684 . -tao_ntr_mu1_i - mu1 interpolation init factor
685 . -tao_ntr_mu2_i - mu2 interpolation init factor
686 . -tao_ntr_gamma1_i - gamma1 interpolation init factor
687 . -tao_ntr_gamma2_i - gamma2 interpolation init factor
688 . -tao_ntr_gamma3_i - gamma3 interpolation init factor
689 . -tao_ntr_gamma4_i - gamma4 interpolation init factor
690 . -tao_ntr_theta_i - thetha1 interpolation init factor
691 . -tao_ntr_eta1 - eta1 reduction update factor
692 . -tao_ntr_eta2 - eta2 reduction update factor
693 . -tao_ntr_eta3 - eta3 reduction update factor
694 . -tao_ntr_eta4 - eta4 reduction update factor
695 . -tao_ntr_alpha1 - alpha1 reduction update factor
696 . -tao_ntr_alpha2 - alpha2 reduction update factor
697 . -tao_ntr_alpha3 - alpha3 reduction update factor
698 . -tao_ntr_alpha4 - alpha4 reduction update factor
699 . -tao_ntr_alpha4 - alpha4 reduction update factor
700 . -tao_ntr_mu1 - mu1 interpolation update
701 . -tao_ntr_mu2 - mu2 interpolation update
702 . -tao_ntr_gamma1 - gamma1 interpolcation update
703 . -tao_ntr_gamma2 - gamma2 interpolcation update
704 . -tao_ntr_gamma3 - gamma3 interpolcation update
705 . -tao_ntr_gamma4 - gamma4 interpolation update
706 - -tao_ntr_theta - theta interpolation update
707 
708   Level: beginner
709 M*/
710 
711 #undef __FUNCT__
712 #define __FUNCT__ "TaoCreate_NTR"
713 PETSC_EXTERN PetscErrorCode TaoCreate_NTR(Tao tao)
714 {
715   TAO_NTR *tr;
716   PetscErrorCode ierr;
717 
718   PetscFunctionBegin;
719 
720   ierr = PetscNewLog(tao,&tr);CHKERRQ(ierr);
721 
722   tao->ops->setup = TaoSetUp_NTR;
723   tao->ops->solve = TaoSolve_NTR;
724   tao->ops->view = TaoView_NTR;
725   tao->ops->setfromoptions = TaoSetFromOptions_NTR;
726   tao->ops->destroy = TaoDestroy_NTR;
727 
728   /* Override default settings (unless already changed) */
729   if (!tao->max_it_changed) tao->max_it = 50;
730   if (!tao->trust0_changed) tao->trust0 = 100.0;
731   tao->data = (void*)tr;
732 
733   /*  Standard trust region update parameters */
734   tr->eta1 = 1.0e-4;
735   tr->eta2 = 0.25;
736   tr->eta3 = 0.50;
737   tr->eta4 = 0.90;
738 
739   tr->alpha1 = 0.25;
740   tr->alpha2 = 0.50;
741   tr->alpha3 = 1.00;
742   tr->alpha4 = 2.00;
743   tr->alpha5 = 4.00;
744 
745   /*  Interpolation trust region update parameters */
746   tr->mu1 = 0.10;
747   tr->mu2 = 0.50;
748 
749   tr->gamma1 = 0.25;
750   tr->gamma2 = 0.50;
751   tr->gamma3 = 2.00;
752   tr->gamma4 = 4.00;
753 
754   tr->theta = 0.05;
755 
756   /*  Interpolation parameters for initialization */
757   tr->mu1_i = 0.35;
758   tr->mu2_i = 0.50;
759 
760   tr->gamma1_i = 0.0625;
761   tr->gamma2_i = 0.50;
762   tr->gamma3_i = 2.00;
763   tr->gamma4_i = 5.00;
764 
765   tr->theta_i = 0.25;
766 
767   tr->min_radius = 1.0e-10;
768   tr->max_radius = 1.0e10;
769   tr->epsilon    = 1.0e-6;
770 
771   tr->pc_type         = NTR_PC_BFGS;
772   tr->bfgs_scale_type = BFGS_SCALE_AHESS;
773   tr->init_type       = NTR_INIT_INTERPOLATION;
774   tr->update_type     = NTR_UPDATE_REDUCTION;
775 
776   /* Set linear solver to default for trust region */
777   ierr = KSPCreate(((PetscObject)tao)->comm,&tao->ksp);CHKERRQ(ierr);
778   ierr = KSPSetOptionsPrefix(tao->ksp,tao->hdr.prefix);CHKERRQ(ierr);
779   ierr = KSPSetType(tao->ksp,KSPCGSTCG);CHKERRQ(ierr);
780   PetscFunctionReturn(0);
781 }
782 
783