xref: /petsc/src/tao/unconstrained/impls/ntr/ntr.c (revision bcd4bb4a4158aa96f212e9537e87b40407faf83e)
1 #include <../src/tao/unconstrained/impls/ntr/ntrimpl.h>
2 
3 #include <petscksp.h>
4 
5 #define NTR_INIT_CONSTANT      0
6 #define NTR_INIT_DIRECTION     1
7 #define NTR_INIT_INTERPOLATION 2
8 #define NTR_INIT_TYPES         3
9 
10 #define NTR_UPDATE_REDUCTION     0
11 #define NTR_UPDATE_INTERPOLATION 1
12 #define NTR_UPDATE_TYPES         2
13 
14 static const char *NTR_INIT[64] = {"constant", "direction", "interpolation"};
15 
16 static const char *NTR_UPDATE[64] = {"reduction", "interpolation"};
17 
18 /*
19    TaoSolve_NTR - Implements Newton's Method with a trust region approach
20    for solving unconstrained minimization problems.
21 
22    The basic algorithm is taken from MINPACK-2 (dstrn).
23 
24    TaoSolve_NTR computes a local minimizer of a twice differentiable function
25    f by applying a trust region variant of Newton's method.  At each stage
26    of the algorithm, we use the prconditioned conjugate gradient method to
27    determine an approximate minimizer of the quadratic equation
28 
29         q(s) = <s, Hs + g>
30 
31    subject to the trust region constraint
32 
33         || s ||_M <= radius,
34 
35    where radius is the trust region radius and M is a symmetric positive
36    definite matrix (the preconditioner).  Here g is the gradient and H
37    is the Hessian matrix.
38 
39    Note:  TaoSolve_NTR MUST use the iterative solver KSPNASH, KSPSTCG,
40           or KSPGLTR.  Thus, we set KSPNASH, KSPSTCG, or KSPGLTR in this
41           routine regardless of what the user may have previously specified.
42 */
43 static PetscErrorCode TaoSolve_NTR(Tao tao)
44 {
45   TAO_NTR           *tr = (TAO_NTR *)tao->data;
46   KSPType            ksp_type;
47   PetscBool          is_nash, is_stcg, is_gltr, is_bfgs, is_jacobi, is_symmetric, sym_set;
48   KSPConvergedReason ksp_reason;
49   PC                 pc;
50   PetscReal          fmin, ftrial, prered, actred, kappa, sigma, beta;
51   PetscReal          tau, tau_1, tau_2, tau_max, tau_min, max_radius;
52   PetscReal          f, gnorm;
53 
54   PetscReal norm_d;
55   PetscInt  needH;
56 
57   PetscInt i_max = 5;
58   PetscInt j_max = 1;
59   PetscInt i, j, N, n, its;
60 
61   PetscFunctionBegin;
62   if (tao->XL || tao->XU || tao->ops->computebounds) PetscCall(PetscInfo(tao, "WARNING: Variable bounds have been set but will be ignored by ntr algorithm\n"));
63 
64   PetscCall(KSPGetType(tao->ksp, &ksp_type));
65   PetscCall(PetscStrcmp(ksp_type, KSPNASH, &is_nash));
66   PetscCall(PetscStrcmp(ksp_type, KSPSTCG, &is_stcg));
67   PetscCall(PetscStrcmp(ksp_type, KSPGLTR, &is_gltr));
68   PetscCheck(is_nash || is_stcg || is_gltr, PetscObjectComm((PetscObject)tao), PETSC_ERR_SUP, "TAO_NTR requires nash, stcg, or gltr for the KSP");
69 
70   /* Initialize the radius and modify if it is too large or small */
71   tao->trust = tao->trust0;
72   tao->trust = PetscMax(tao->trust, tr->min_radius);
73   tao->trust = PetscMin(tao->trust, tr->max_radius);
74 
75   /* Allocate the vectors needed for the BFGS approximation */
76   PetscCall(KSPGetPC(tao->ksp, &pc));
77   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCLMVM, &is_bfgs));
78   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCJACOBI, &is_jacobi));
79   if (is_bfgs) {
80     tr->bfgs_pre = pc;
81     PetscCall(PCLMVMGetMatLMVM(tr->bfgs_pre, &tr->M));
82     PetscCall(VecGetLocalSize(tao->solution, &n));
83     PetscCall(VecGetSize(tao->solution, &N));
84     PetscCall(MatSetSizes(tr->M, n, n, N, N));
85     PetscCall(MatLMVMAllocate(tr->M, tao->solution, tao->gradient));
86     PetscCall(MatIsSymmetricKnown(tr->M, &sym_set, &is_symmetric));
87     PetscCheck(sym_set && is_symmetric, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "LMVM matrix in the LMVM preconditioner must be symmetric.");
88   } else if (is_jacobi) PetscCall(PCJacobiSetUseAbs(pc, PETSC_TRUE));
89 
90   /* Check convergence criteria */
91   PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient));
92   PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &gnorm));
93   PetscCheck(!PetscIsInfOrNanReal(f) && !PetscIsInfOrNanReal(gnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated infinity or NaN");
94   needH = 1;
95 
96   tao->reason = TAO_CONTINUE_ITERATING;
97   PetscCall(TaoLogConvergenceHistory(tao, f, gnorm, 0.0, tao->ksp_its));
98   PetscCall(TaoMonitor(tao, tao->niter, f, gnorm, 0.0, 1.0));
99   PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
100   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS);
101 
102   /*  Initialize trust-region radius */
103   switch (tr->init_type) {
104   case NTR_INIT_CONSTANT:
105     /*  Use the initial radius specified */
106     break;
107 
108   case NTR_INIT_INTERPOLATION:
109     /*  Use the initial radius specified */
110     max_radius = 0.0;
111 
112     for (j = 0; j < j_max; ++j) {
113       fmin  = f;
114       sigma = 0.0;
115 
116       if (needH) {
117         PetscCall(TaoComputeHessian(tao, tao->solution, tao->hessian, tao->hessian_pre));
118         needH = 0;
119       }
120 
121       for (i = 0; i < i_max; ++i) {
122         PetscCall(VecCopy(tao->solution, tr->W));
123         PetscCall(VecAXPY(tr->W, -tao->trust / gnorm, tao->gradient));
124         PetscCall(TaoComputeObjective(tao, tr->W, &ftrial));
125 
126         if (PetscIsInfOrNanReal(ftrial)) {
127           tau = tr->gamma1_i;
128         } else {
129           if (ftrial < fmin) {
130             fmin  = ftrial;
131             sigma = -tao->trust / gnorm;
132           }
133 
134           PetscCall(MatMult(tao->hessian, tao->gradient, tao->stepdirection));
135           PetscCall(VecDot(tao->gradient, tao->stepdirection, &prered));
136 
137           prered = tao->trust * (gnorm - 0.5 * tao->trust * prered / (gnorm * gnorm));
138           actred = f - ftrial;
139           if ((PetscAbsScalar(actred) <= tr->epsilon) && (PetscAbsScalar(prered) <= tr->epsilon)) {
140             kappa = 1.0;
141           } else {
142             kappa = actred / prered;
143           }
144 
145           tau_1   = tr->theta_i * gnorm * tao->trust / (tr->theta_i * gnorm * tao->trust + (1.0 - tr->theta_i) * prered - actred);
146           tau_2   = tr->theta_i * gnorm * tao->trust / (tr->theta_i * gnorm * tao->trust - (1.0 + tr->theta_i) * prered + actred);
147           tau_min = PetscMin(tau_1, tau_2);
148           tau_max = PetscMax(tau_1, tau_2);
149 
150           if (PetscAbsScalar(kappa - (PetscReal)1.0) <= tr->mu1_i) {
151             /*  Great agreement */
152             max_radius = PetscMax(max_radius, tao->trust);
153 
154             if (tau_max < 1.0) {
155               tau = tr->gamma3_i;
156             } else if (tau_max > tr->gamma4_i) {
157               tau = tr->gamma4_i;
158             } else {
159               tau = tau_max;
160             }
161           } else if (PetscAbsScalar(kappa - (PetscReal)1.0) <= tr->mu2_i) {
162             /*  Good agreement */
163             max_radius = PetscMax(max_radius, tao->trust);
164 
165             if (tau_max < tr->gamma2_i) {
166               tau = tr->gamma2_i;
167             } else if (tau_max > tr->gamma3_i) {
168               tau = tr->gamma3_i;
169             } else {
170               tau = tau_max;
171             }
172           } else {
173             /*  Not good agreement */
174             if (tau_min > 1.0) {
175               tau = tr->gamma2_i;
176             } else if (tau_max < tr->gamma1_i) {
177               tau = tr->gamma1_i;
178             } else if ((tau_min < tr->gamma1_i) && (tau_max >= 1.0)) {
179               tau = tr->gamma1_i;
180             } else if ((tau_1 >= tr->gamma1_i) && (tau_1 < 1.0) && ((tau_2 < tr->gamma1_i) || (tau_2 >= 1.0))) {
181               tau = tau_1;
182             } else if ((tau_2 >= tr->gamma1_i) && (tau_2 < 1.0) && ((tau_1 < tr->gamma1_i) || (tau_2 >= 1.0))) {
183               tau = tau_2;
184             } else {
185               tau = tau_max;
186             }
187           }
188         }
189         tao->trust = tau * tao->trust;
190       }
191 
192       if (fmin < f) {
193         f = fmin;
194         PetscCall(VecAXPY(tao->solution, sigma, tao->gradient));
195         PetscCall(TaoComputeGradient(tao, tao->solution, tao->gradient));
196 
197         PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &gnorm));
198         PetscCheck(!PetscIsInfOrNanReal(f) && !PetscIsInfOrNanReal(gnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated infinity or NaN");
199         needH = 1;
200 
201         PetscCall(TaoLogConvergenceHistory(tao, f, gnorm, 0.0, tao->ksp_its));
202         PetscCall(TaoMonitor(tao, tao->niter, f, gnorm, 0.0, 1.0));
203         PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
204         if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS);
205       }
206     }
207     tao->trust = PetscMax(tao->trust, max_radius);
208 
209     /*  Modify the radius if it is too large or small */
210     tao->trust = PetscMax(tao->trust, tr->min_radius);
211     tao->trust = PetscMin(tao->trust, tr->max_radius);
212     break;
213 
214   default:
215     /*  Norm of the first direction will initialize radius */
216     tao->trust = 0.0;
217     break;
218   }
219 
220   /* Have not converged; continue with Newton method */
221   while (tao->reason == TAO_CONTINUE_ITERATING) {
222     /* Call general purpose update function */
223     if (tao->ops->update) {
224       PetscUseTypeMethod(tao, update, tao->niter, tao->user_update);
225       PetscCall(TaoComputeObjective(tao, tao->solution, &f));
226     }
227     ++tao->niter;
228     tao->ksp_its = 0;
229     /* Compute the Hessian */
230     if (needH) {
231       PetscCall(TaoComputeHessian(tao, tao->solution, tao->hessian, tao->hessian_pre));
232       needH = 0;
233     }
234 
235     if (tr->bfgs_pre) {
236       /* Update the limited memory preconditioner */
237       PetscCall(MatLMVMUpdate(tr->M, tao->solution, tao->gradient));
238     }
239 
240     while (tao->reason == TAO_CONTINUE_ITERATING) {
241       PetscCall(KSPSetOperators(tao->ksp, tao->hessian, tao->hessian_pre));
242 
243       /* Solve the trust region subproblem */
244       PetscCall(KSPCGSetRadius(tao->ksp, tao->trust));
245       PetscCall(KSPSolve(tao->ksp, tao->gradient, tao->stepdirection));
246       PetscCall(KSPGetIterationNumber(tao->ksp, &its));
247       tao->ksp_its += its;
248       tao->ksp_tot_its += its;
249       PetscCall(KSPCGGetNormD(tao->ksp, &norm_d));
250 
251       if (0.0 == tao->trust) {
252         /* Radius was uninitialized; use the norm of the direction */
253         if (norm_d > 0.0) {
254           tao->trust = norm_d;
255 
256           /* Modify the radius if it is too large or small */
257           tao->trust = PetscMax(tao->trust, tr->min_radius);
258           tao->trust = PetscMin(tao->trust, tr->max_radius);
259         } else {
260           /* The direction was bad; set radius to default value and re-solve
261              the trust-region subproblem to get a direction */
262           tao->trust = tao->trust0;
263 
264           /* Modify the radius if it is too large or small */
265           tao->trust = PetscMax(tao->trust, tr->min_radius);
266           tao->trust = PetscMin(tao->trust, tr->max_radius);
267 
268           PetscCall(KSPCGSetRadius(tao->ksp, tao->trust));
269           PetscCall(KSPSolve(tao->ksp, tao->gradient, tao->stepdirection));
270           PetscCall(KSPGetIterationNumber(tao->ksp, &its));
271           tao->ksp_its += its;
272           tao->ksp_tot_its += its;
273           PetscCall(KSPCGGetNormD(tao->ksp, &norm_d));
274 
275           PetscCheck(norm_d != 0.0, PetscObjectComm((PetscObject)tao), PETSC_ERR_PLIB, "Initial direction zero");
276         }
277       }
278       PetscCall(VecScale(tao->stepdirection, -1.0));
279       PetscCall(KSPGetConvergedReason(tao->ksp, &ksp_reason));
280       if ((KSP_DIVERGED_INDEFINITE_PC == ksp_reason) && (tr->bfgs_pre)) {
281         /* Preconditioner is numerically indefinite; reset the
282            approximate if using BFGS preconditioning. */
283         PetscCall(MatLMVMReset(tr->M, PETSC_FALSE));
284         PetscCall(MatLMVMUpdate(tr->M, tao->solution, tao->gradient));
285       }
286 
287       if (NTR_UPDATE_REDUCTION == tr->update_type) {
288         /* Get predicted reduction */
289         PetscCall(KSPCGGetObjFcn(tao->ksp, &prered));
290         if (prered >= 0.0) {
291           /* The predicted reduction has the wrong sign.  This cannot
292              happen in infinite precision arithmetic.  Step should
293              be rejected! */
294           tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d);
295         } else {
296           /* Compute trial step and function value */
297           PetscCall(VecCopy(tao->solution, tr->W));
298           PetscCall(VecAXPY(tr->W, 1.0, tao->stepdirection));
299           PetscCall(TaoComputeObjective(tao, tr->W, &ftrial));
300 
301           if (PetscIsInfOrNanReal(ftrial)) {
302             tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d);
303           } else {
304             /* Compute and actual reduction */
305             actred = f - ftrial;
306             prered = -prered;
307             if ((PetscAbsScalar(actred) <= tr->epsilon) && (PetscAbsScalar(prered) <= tr->epsilon)) {
308               kappa = 1.0;
309             } else {
310               kappa = actred / prered;
311             }
312 
313             /* Accept or reject the step and update radius */
314             if (kappa < tr->eta1) {
315               /* Reject the step */
316               tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d);
317             } else {
318               /* Accept the step */
319               if (kappa < tr->eta2) {
320                 /* Marginal bad step */
321                 tao->trust = tr->alpha2 * PetscMin(tao->trust, norm_d);
322               } else if (kappa < tr->eta3) {
323                 /* Reasonable step */
324                 tao->trust = tr->alpha3 * tao->trust;
325               } else if (kappa < tr->eta4) {
326                 /* Good step */
327                 tao->trust = PetscMax(tr->alpha4 * norm_d, tao->trust);
328               } else {
329                 /* Very good step */
330                 tao->trust = PetscMax(tr->alpha5 * norm_d, tao->trust);
331               }
332               break;
333             }
334           }
335         }
336       } else {
337         /* Get predicted reduction */
338         PetscCall(KSPCGGetObjFcn(tao->ksp, &prered));
339         if (prered >= 0.0) {
340           /* The predicted reduction has the wrong sign.  This cannot
341              happen in infinite precision arithmetic.  Step should
342              be rejected! */
343           tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
344         } else {
345           PetscCall(VecCopy(tao->solution, tr->W));
346           PetscCall(VecAXPY(tr->W, 1.0, tao->stepdirection));
347           PetscCall(TaoComputeObjective(tao, tr->W, &ftrial));
348           if (PetscIsInfOrNanReal(ftrial)) {
349             tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
350           } else {
351             PetscCall(VecDot(tao->gradient, tao->stepdirection, &beta));
352             actred = f - ftrial;
353             prered = -prered;
354             if ((PetscAbsScalar(actred) <= tr->epsilon) && (PetscAbsScalar(prered) <= tr->epsilon)) {
355               kappa = 1.0;
356             } else {
357               kappa = actred / prered;
358             }
359 
360             tau_1   = tr->theta * beta / (tr->theta * beta - (1.0 - tr->theta) * prered + actred);
361             tau_2   = tr->theta * beta / (tr->theta * beta + (1.0 + tr->theta) * prered - actred);
362             tau_min = PetscMin(tau_1, tau_2);
363             tau_max = PetscMax(tau_1, tau_2);
364 
365             if (kappa >= 1.0 - tr->mu1) {
366               /* Great agreement; accept step and update radius */
367               if (tau_max < 1.0) {
368                 tao->trust = PetscMax(tao->trust, tr->gamma3 * norm_d);
369               } else if (tau_max > tr->gamma4) {
370                 tao->trust = PetscMax(tao->trust, tr->gamma4 * norm_d);
371               } else {
372                 tao->trust = PetscMax(tao->trust, tau_max * norm_d);
373               }
374               break;
375             } else if (kappa >= 1.0 - tr->mu2) {
376               /* Good agreement */
377 
378               if (tau_max < tr->gamma2) {
379                 tao->trust = tr->gamma2 * PetscMin(tao->trust, norm_d);
380               } else if (tau_max > tr->gamma3) {
381                 tao->trust = PetscMax(tao->trust, tr->gamma3 * norm_d);
382               } else if (tau_max < 1.0) {
383                 tao->trust = tau_max * PetscMin(tao->trust, norm_d);
384               } else {
385                 tao->trust = PetscMax(tao->trust, tau_max * norm_d);
386               }
387               break;
388             } else {
389               /* Not good agreement */
390               if (tau_min > 1.0) {
391                 tao->trust = tr->gamma2 * PetscMin(tao->trust, norm_d);
392               } else if (tau_max < tr->gamma1) {
393                 tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
394               } else if ((tau_min < tr->gamma1) && (tau_max >= 1.0)) {
395                 tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d);
396               } else if ((tau_1 >= tr->gamma1) && (tau_1 < 1.0) && ((tau_2 < tr->gamma1) || (tau_2 >= 1.0))) {
397                 tao->trust = tau_1 * PetscMin(tao->trust, norm_d);
398               } else if ((tau_2 >= tr->gamma1) && (tau_2 < 1.0) && ((tau_1 < tr->gamma1) || (tau_2 >= 1.0))) {
399                 tao->trust = tau_2 * PetscMin(tao->trust, norm_d);
400               } else {
401                 tao->trust = tau_max * PetscMin(tao->trust, norm_d);
402               }
403             }
404           }
405         }
406       }
407 
408       /* The step computed was not good and the radius was decreased.
409          Monitor the radius to terminate. */
410       PetscCall(TaoLogConvergenceHistory(tao, f, gnorm, 0.0, tao->ksp_its));
411       PetscCall(TaoMonitor(tao, tao->niter, f, gnorm, 0.0, tao->trust));
412       PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
413     }
414 
415     /* The radius may have been increased; modify if it is too large */
416     tao->trust = PetscMin(tao->trust, tr->max_radius);
417 
418     if (tao->reason == TAO_CONTINUE_ITERATING) {
419       PetscCall(VecCopy(tr->W, tao->solution));
420       f = ftrial;
421       PetscCall(TaoComputeGradient(tao, tao->solution, tao->gradient));
422       PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &gnorm));
423       PetscCheck(!PetscIsInfOrNanReal(f) && !PetscIsInfOrNanReal(gnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated infinity or NaN");
424       needH = 1;
425       PetscCall(TaoLogConvergenceHistory(tao, f, gnorm, 0.0, tao->ksp_its));
426       PetscCall(TaoMonitor(tao, tao->niter, f, gnorm, 0.0, tao->trust));
427       PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
428     }
429   }
430   PetscFunctionReturn(PETSC_SUCCESS);
431 }
432 
433 /*------------------------------------------------------------*/
434 static PetscErrorCode TaoSetUp_NTR(Tao tao)
435 {
436   TAO_NTR *tr = (TAO_NTR *)tao->data;
437 
438   PetscFunctionBegin;
439   if (!tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient));
440   if (!tao->stepdirection) PetscCall(VecDuplicate(tao->solution, &tao->stepdirection));
441   if (!tr->W) PetscCall(VecDuplicate(tao->solution, &tr->W));
442 
443   tr->bfgs_pre = NULL;
444   tr->M        = NULL;
445   PetscFunctionReturn(PETSC_SUCCESS);
446 }
447 
448 /*------------------------------------------------------------*/
449 static PetscErrorCode TaoDestroy_NTR(Tao tao)
450 {
451   TAO_NTR *tr = (TAO_NTR *)tao->data;
452 
453   PetscFunctionBegin;
454   if (tao->setupcalled) PetscCall(VecDestroy(&tr->W));
455   PetscCall(KSPDestroy(&tao->ksp));
456   PetscCall(PetscFree(tao->data));
457   PetscFunctionReturn(PETSC_SUCCESS);
458 }
459 
460 /*------------------------------------------------------------*/
461 static PetscErrorCode TaoSetFromOptions_NTR(Tao tao, PetscOptionItems PetscOptionsObject)
462 {
463   TAO_NTR *tr = (TAO_NTR *)tao->data;
464 
465   PetscFunctionBegin;
466   PetscOptionsHeadBegin(PetscOptionsObject, "Newton trust region method for unconstrained optimization");
467   PetscCall(PetscOptionsEList("-tao_ntr_init_type", "tao->trust initialization type", "", NTR_INIT, NTR_INIT_TYPES, NTR_INIT[tr->init_type], &tr->init_type, NULL));
468   PetscCall(PetscOptionsEList("-tao_ntr_update_type", "radius update type", "", NTR_UPDATE, NTR_UPDATE_TYPES, NTR_UPDATE[tr->update_type], &tr->update_type, NULL));
469   PetscCall(PetscOptionsReal("-tao_ntr_eta1", "step is unsuccessful if actual reduction < eta1 * predicted reduction", "", tr->eta1, &tr->eta1, NULL));
470   PetscCall(PetscOptionsReal("-tao_ntr_eta2", "", "", tr->eta2, &tr->eta2, NULL));
471   PetscCall(PetscOptionsReal("-tao_ntr_eta3", "", "", tr->eta3, &tr->eta3, NULL));
472   PetscCall(PetscOptionsReal("-tao_ntr_eta4", "", "", tr->eta4, &tr->eta4, NULL));
473   PetscCall(PetscOptionsReal("-tao_ntr_alpha1", "", "", tr->alpha1, &tr->alpha1, NULL));
474   PetscCall(PetscOptionsReal("-tao_ntr_alpha2", "", "", tr->alpha2, &tr->alpha2, NULL));
475   PetscCall(PetscOptionsReal("-tao_ntr_alpha3", "", "", tr->alpha3, &tr->alpha3, NULL));
476   PetscCall(PetscOptionsReal("-tao_ntr_alpha4", "", "", tr->alpha4, &tr->alpha4, NULL));
477   PetscCall(PetscOptionsReal("-tao_ntr_alpha5", "", "", tr->alpha5, &tr->alpha5, NULL));
478   PetscCall(PetscOptionsReal("-tao_ntr_mu1", "", "", tr->mu1, &tr->mu1, NULL));
479   PetscCall(PetscOptionsReal("-tao_ntr_mu2", "", "", tr->mu2, &tr->mu2, NULL));
480   PetscCall(PetscOptionsReal("-tao_ntr_gamma1", "", "", tr->gamma1, &tr->gamma1, NULL));
481   PetscCall(PetscOptionsReal("-tao_ntr_gamma2", "", "", tr->gamma2, &tr->gamma2, NULL));
482   PetscCall(PetscOptionsReal("-tao_ntr_gamma3", "", "", tr->gamma3, &tr->gamma3, NULL));
483   PetscCall(PetscOptionsReal("-tao_ntr_gamma4", "", "", tr->gamma4, &tr->gamma4, NULL));
484   PetscCall(PetscOptionsReal("-tao_ntr_theta", "", "", tr->theta, &tr->theta, NULL));
485   PetscCall(PetscOptionsReal("-tao_ntr_mu1_i", "", "", tr->mu1_i, &tr->mu1_i, NULL));
486   PetscCall(PetscOptionsReal("-tao_ntr_mu2_i", "", "", tr->mu2_i, &tr->mu2_i, NULL));
487   PetscCall(PetscOptionsReal("-tao_ntr_gamma1_i", "", "", tr->gamma1_i, &tr->gamma1_i, NULL));
488   PetscCall(PetscOptionsReal("-tao_ntr_gamma2_i", "", "", tr->gamma2_i, &tr->gamma2_i, NULL));
489   PetscCall(PetscOptionsReal("-tao_ntr_gamma3_i", "", "", tr->gamma3_i, &tr->gamma3_i, NULL));
490   PetscCall(PetscOptionsReal("-tao_ntr_gamma4_i", "", "", tr->gamma4_i, &tr->gamma4_i, NULL));
491   PetscCall(PetscOptionsReal("-tao_ntr_theta_i", "", "", tr->theta_i, &tr->theta_i, NULL));
492   PetscCall(PetscOptionsReal("-tao_ntr_min_radius", "lower bound on initial trust-region radius", "", tr->min_radius, &tr->min_radius, NULL));
493   PetscCall(PetscOptionsReal("-tao_ntr_max_radius", "upper bound on trust-region radius", "", tr->max_radius, &tr->max_radius, NULL));
494   PetscCall(PetscOptionsReal("-tao_ntr_epsilon", "tolerance used when computing actual and predicted reduction", "", tr->epsilon, &tr->epsilon, NULL));
495   PetscOptionsHeadEnd();
496   PetscCall(KSPSetFromOptions(tao->ksp));
497   PetscFunctionReturn(PETSC_SUCCESS);
498 }
499 
500 /*------------------------------------------------------------*/
501 /*MC
502   TAONTR - Newton's method with trust region for unconstrained minimization.
503   At each iteration, the Newton trust region method solves the system.
504   NTR expects a KSP solver with a trust region radius.
505             min_d  .5 dT Hk d + gkT d,  s.t.   ||d|| < Delta_k
506 
507   Options Database Keys:
508 + -tao_ntr_init_type - "constant","direction","interpolation"
509 . -tao_ntr_update_type - "reduction","interpolation"
510 . -tao_ntr_min_radius - lower bound on trust region radius
511 . -tao_ntr_max_radius - upper bound on trust region radius
512 . -tao_ntr_epsilon - tolerance for accepting actual / predicted reduction
513 . -tao_ntr_mu1_i - mu1 interpolation init factor
514 . -tao_ntr_mu2_i - mu2 interpolation init factor
515 . -tao_ntr_gamma1_i - gamma1 interpolation init factor
516 . -tao_ntr_gamma2_i - gamma2 interpolation init factor
517 . -tao_ntr_gamma3_i - gamma3 interpolation init factor
518 . -tao_ntr_gamma4_i - gamma4 interpolation init factor
519 . -tao_ntr_theta_i - theta1 interpolation init factor
520 . -tao_ntr_eta1 - eta1 reduction update factor
521 . -tao_ntr_eta2 - eta2 reduction update factor
522 . -tao_ntr_eta3 - eta3 reduction update factor
523 . -tao_ntr_eta4 - eta4 reduction update factor
524 . -tao_ntr_alpha1 - alpha1 reduction update factor
525 . -tao_ntr_alpha2 - alpha2 reduction update factor
526 . -tao_ntr_alpha3 - alpha3 reduction update factor
527 . -tao_ntr_alpha4 - alpha4 reduction update factor
528 . -tao_ntr_alpha4 - alpha4 reduction update factor
529 . -tao_ntr_mu1 - mu1 interpolation update
530 . -tao_ntr_mu2 - mu2 interpolation update
531 . -tao_ntr_gamma1 - gamma1 interpolcation update
532 . -tao_ntr_gamma2 - gamma2 interpolcation update
533 . -tao_ntr_gamma3 - gamma3 interpolcation update
534 . -tao_ntr_gamma4 - gamma4 interpolation update
535 - -tao_ntr_theta - theta interpolation update
536 
537   Level: beginner
538 M*/
539 
540 PETSC_EXTERN PetscErrorCode TaoCreate_NTR(Tao tao)
541 {
542   TAO_NTR *tr;
543 
544   PetscFunctionBegin;
545   PetscCall(PetscNew(&tr));
546 
547   tao->ops->setup          = TaoSetUp_NTR;
548   tao->ops->solve          = TaoSolve_NTR;
549   tao->ops->setfromoptions = TaoSetFromOptions_NTR;
550   tao->ops->destroy        = TaoDestroy_NTR;
551 
552   /* Override default settings (unless already changed) */
553   PetscCall(TaoParametersInitialize(tao));
554   PetscObjectParameterSetDefault(tao, max_it, 50);
555   PetscObjectParameterSetDefault(tao, trust0, 100.0);
556   tao->data = (void *)tr;
557 
558   /*  Standard trust region update parameters */
559   tr->eta1 = 1.0e-4;
560   tr->eta2 = 0.25;
561   tr->eta3 = 0.50;
562   tr->eta4 = 0.90;
563 
564   tr->alpha1 = 0.25;
565   tr->alpha2 = 0.50;
566   tr->alpha3 = 1.00;
567   tr->alpha4 = 2.00;
568   tr->alpha5 = 4.00;
569 
570   /*  Interpolation trust region update parameters */
571   tr->mu1 = 0.10;
572   tr->mu2 = 0.50;
573 
574   tr->gamma1 = 0.25;
575   tr->gamma2 = 0.50;
576   tr->gamma3 = 2.00;
577   tr->gamma4 = 4.00;
578 
579   tr->theta = 0.05;
580 
581   /*  Interpolation parameters for initialization */
582   tr->mu1_i = 0.35;
583   tr->mu2_i = 0.50;
584 
585   tr->gamma1_i = 0.0625;
586   tr->gamma2_i = 0.50;
587   tr->gamma3_i = 2.00;
588   tr->gamma4_i = 5.00;
589 
590   tr->theta_i = 0.25;
591 
592   tr->min_radius = 1.0e-10;
593   tr->max_radius = 1.0e10;
594   tr->epsilon    = 1.0e-6;
595 
596   tr->init_type   = NTR_INIT_INTERPOLATION;
597   tr->update_type = NTR_UPDATE_REDUCTION;
598 
599   /* Set linear solver to default for trust region */
600   PetscCall(KSPCreate(((PetscObject)tao)->comm, &tao->ksp));
601   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->ksp, (PetscObject)tao, 1));
602   PetscCall(KSPSetOptionsPrefix(tao->ksp, tao->hdr.prefix));
603   PetscCall(KSPAppendOptionsPrefix(tao->ksp, "tao_ntr_"));
604   PetscCall(KSPSetType(tao->ksp, KSPSTCG));
605   PetscFunctionReturn(PETSC_SUCCESS);
606 }
607