xref: /petsc/src/tao/bound/impls/bnk/bnls.c (revision eb9107154965f6d42900b472f8cc894abc73f56d)
1*eb910715SAlp Dener #include <../src/tao/bound/impls/bnk/bnk.h>
2*eb910715SAlp Dener #include <petscksp.h>
3*eb910715SAlp Dener 
4*eb910715SAlp Dener /*
5*eb910715SAlp Dener  Implements Newton's Method with a line search approach for solving
6*eb910715SAlp Dener  unconstrained minimization problems.  A More'-Thuente line search
7*eb910715SAlp Dener  is used to guarantee that the bfgs preconditioner remains positive
8*eb910715SAlp Dener  definite.
9*eb910715SAlp Dener 
10*eb910715SAlp Dener  The method can shift the Hessian matrix.  The shifting procedure is
11*eb910715SAlp Dener  adapted from the PATH algorithm for solving complementarity
12*eb910715SAlp Dener  problems.
13*eb910715SAlp Dener 
14*eb910715SAlp Dener  The linear system solve should be done with a conjugate gradient
15*eb910715SAlp Dener  method, although any method can be used.
16*eb910715SAlp Dener */
17*eb910715SAlp Dener 
18*eb910715SAlp Dener static PetscErrorCode TaoSolve_BNLS(Tao tao)
19*eb910715SAlp Dener {
20*eb910715SAlp Dener   PetscErrorCode               ierr;
21*eb910715SAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
22*eb910715SAlp Dener   TaoLineSearchConvergedReason ls_reason;
23*eb910715SAlp Dener 
24*eb910715SAlp Dener   PetscReal                    prered, actred, kappa;
25*eb910715SAlp Dener   PetscReal                    tau_1, tau_2, tau_max, tau_min;
26*eb910715SAlp Dener   PetscReal                    f_full, fold, gdx;
27*eb910715SAlp Dener   PetscReal                    step = 1.0;
28*eb910715SAlp Dener   PetscReal                    delta;
29*eb910715SAlp Dener   PetscReal                    norm_d = 0.0, e_min;
30*eb910715SAlp Dener 
31*eb910715SAlp Dener   PetscInt                     stepType;
32*eb910715SAlp Dener   PetscInt                     bfgsUpdates = 0;
33*eb910715SAlp Dener   PetscInt                     needH = 1;
34*eb910715SAlp Dener 
35*eb910715SAlp Dener   PetscFunctionBegin;
36*eb910715SAlp Dener   if (tao->XL || tao->XU || tao->ops->computebounds) {
37*eb910715SAlp Dener     ierr = PetscPrintf(((PetscObject)tao)->comm,"WARNING: Variable bounds have been set but will be ignored by nls algorithm\n");CHKERRQ(ierr);
38*eb910715SAlp Dener   }
39*eb910715SAlp Dener 
40*eb910715SAlp Dener   /* Check convergence criteria */
41*eb910715SAlp Dener   ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &bnk->f, tao->gradient);CHKERRQ(ierr);
42*eb910715SAlp Dener   ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr);
43*eb910715SAlp Dener   if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
44*eb910715SAlp Dener 
45*eb910715SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
46*eb910715SAlp Dener   ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
47*eb910715SAlp Dener   ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,step);CHKERRQ(ierr);
48*eb910715SAlp Dener   ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
49*eb910715SAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
50*eb910715SAlp Dener 
51*eb910715SAlp Dener   /* Initialize the preconditioner and trust radius */
52*eb910715SAlp Dener   ierr = TaoBNKInitialize(tao);CHKERRQ(ierr);
53*eb910715SAlp Dener 
54*eb910715SAlp Dener   /* Have not converged; continue with Newton method */
55*eb910715SAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
56*eb910715SAlp Dener     ++tao->niter;
57*eb910715SAlp Dener     tao->ksp_its=0;
58*eb910715SAlp Dener 
59*eb910715SAlp Dener     /* Use the common BNK kernel to compute the step */
60*eb910715SAlp Dener     ierr = TaoBNKComputeStep(tao, &stepType);CHKERRQ(ierr);
61*eb910715SAlp Dener 
62*eb910715SAlp Dener     /* Perform the linesearch */
63*eb910715SAlp Dener     fold = bnk->f;
64*eb910715SAlp Dener     ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
65*eb910715SAlp Dener     ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr);
66*eb910715SAlp Dener 
67*eb910715SAlp Dener     ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &bnk->f, tao->gradient, bnk->D, &step, &ls_reason);CHKERRQ(ierr);
68*eb910715SAlp Dener     ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
69*eb910715SAlp Dener 
70*eb910715SAlp Dener     while (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER && stepType != BNK_GRADIENT) {
71*eb910715SAlp Dener       /* Linesearch failed, revert solution */
72*eb910715SAlp Dener       bnk->f = fold;
73*eb910715SAlp Dener       ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
74*eb910715SAlp Dener       ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr);
75*eb910715SAlp Dener 
76*eb910715SAlp Dener       switch(stepType) {
77*eb910715SAlp Dener       case BNK_NEWTON:
78*eb910715SAlp Dener         /* Failed to obtain acceptable iterate with Newton 1step
79*eb910715SAlp Dener            Update the perturbation for next time */
80*eb910715SAlp Dener         if (bnk->pert <= 0.0) {
81*eb910715SAlp Dener           /* Initialize the perturbation */
82*eb910715SAlp Dener           bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
83*eb910715SAlp Dener           if (bnk->is_gltr) {
84*eb910715SAlp Dener             ierr = KSPCGGLTRGetMinEig(tao->ksp,&e_min);CHKERRQ(ierr);
85*eb910715SAlp Dener             bnk->pert = PetscMax(bnk->pert, -e_min);
86*eb910715SAlp Dener           }
87*eb910715SAlp Dener         } else {
88*eb910715SAlp Dener           /* Increase the perturbation */
89*eb910715SAlp Dener           bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
90*eb910715SAlp Dener         }
91*eb910715SAlp Dener 
92*eb910715SAlp Dener         if (BNK_PC_BFGS != bnk->pc_type) {
93*eb910715SAlp Dener           /* We don't have the bfgs matrix around and being updated
94*eb910715SAlp Dener              Must use gradient direction in this case */
95*eb910715SAlp Dener           ierr = VecCopy(tao->gradient, bnk->D);CHKERRQ(ierr);
96*eb910715SAlp Dener           ++bnk->grad;
97*eb910715SAlp Dener           stepType = BNK_GRADIENT;
98*eb910715SAlp Dener         } else {
99*eb910715SAlp Dener           /* Attempt to use the BFGS direction */
100*eb910715SAlp Dener           ierr = MatLMVMSolve(bnk->M, tao->gradient, bnk->D);CHKERRQ(ierr);
101*eb910715SAlp Dener           /* Check for success (descent direction) */
102*eb910715SAlp Dener           ierr = VecDot(tao->solution, bnk->D, &gdx);CHKERRQ(ierr);
103*eb910715SAlp Dener           if ((gdx <= 0) || PetscIsInfOrNanReal(gdx)) {
104*eb910715SAlp Dener             /* BFGS direction is not descent or direction produced not a number
105*eb910715SAlp Dener                We can assert bfgsUpdates > 1 in this case
106*eb910715SAlp Dener                Use steepest descent direction (scaled) */
107*eb910715SAlp Dener 
108*eb910715SAlp Dener             if (bnk->f != 0.0) {
109*eb910715SAlp Dener               delta = 2.0 * PetscAbsScalar(bnk->f) / (bnk->gnorm*bnk->gnorm);
110*eb910715SAlp Dener             } else {
111*eb910715SAlp Dener               delta = 2.0 / (bnk->gnorm*bnk->gnorm);
112*eb910715SAlp Dener             }
113*eb910715SAlp Dener             ierr = MatLMVMSetDelta(bnk->M, delta);CHKERRQ(ierr);
114*eb910715SAlp Dener             ierr = MatLMVMReset(bnk->M);CHKERRQ(ierr);
115*eb910715SAlp Dener             ierr = MatLMVMUpdate(bnk->M, tao->solution, tao->gradient);CHKERRQ(ierr);
116*eb910715SAlp Dener             ierr = MatLMVMSolve(bnk->M, tao->gradient, bnk->D);CHKERRQ(ierr);
117*eb910715SAlp Dener 
118*eb910715SAlp Dener             bfgsUpdates = 1;
119*eb910715SAlp Dener             ++bnk->sgrad;
120*eb910715SAlp Dener             stepType = BNK_SCALED_GRADIENT;
121*eb910715SAlp Dener           } else {
122*eb910715SAlp Dener             ierr = MatLMVMGetUpdates(bnk->M, &bfgsUpdates);CHKERRQ(ierr);
123*eb910715SAlp Dener             if (1 == bfgsUpdates) {
124*eb910715SAlp Dener               /* The first BFGS direction is always the scaled gradient */
125*eb910715SAlp Dener               ++bnk->sgrad;
126*eb910715SAlp Dener               stepType = BNK_SCALED_GRADIENT;
127*eb910715SAlp Dener             } else {
128*eb910715SAlp Dener               ++bnk->bfgs;
129*eb910715SAlp Dener               stepType = BNK_BFGS;
130*eb910715SAlp Dener             }
131*eb910715SAlp Dener           }
132*eb910715SAlp Dener         }
133*eb910715SAlp Dener         break;
134*eb910715SAlp Dener 
135*eb910715SAlp Dener       case BNK_BFGS:
136*eb910715SAlp Dener         /* Can only enter if pc_type == BNK_PC_BFGS
137*eb910715SAlp Dener            Failed to obtain acceptable iterate with BFGS step
138*eb910715SAlp Dener            Attempt to use the scaled gradient direction */
139*eb910715SAlp Dener 
140*eb910715SAlp Dener         if (bnk->f != 0.0) {
141*eb910715SAlp Dener           delta = 2.0 * PetscAbsScalar(bnk->f) / (bnk->gnorm*bnk->gnorm);
142*eb910715SAlp Dener         } else {
143*eb910715SAlp Dener           delta = 2.0 / (bnk->gnorm*bnk->gnorm);
144*eb910715SAlp Dener         }
145*eb910715SAlp Dener         ierr = MatLMVMSetDelta(bnk->M, delta);CHKERRQ(ierr);
146*eb910715SAlp Dener         ierr = MatLMVMReset(bnk->M);CHKERRQ(ierr);
147*eb910715SAlp Dener         ierr = MatLMVMUpdate(bnk->M, tao->solution, tao->gradient);CHKERRQ(ierr);
148*eb910715SAlp Dener         ierr = MatLMVMSolve(bnk->M, tao->gradient, bnk->D);CHKERRQ(ierr);
149*eb910715SAlp Dener 
150*eb910715SAlp Dener         bfgsUpdates = 1;
151*eb910715SAlp Dener         ++bnk->sgrad;
152*eb910715SAlp Dener         stepType = BNK_SCALED_GRADIENT;
153*eb910715SAlp Dener         break;
154*eb910715SAlp Dener 
155*eb910715SAlp Dener       case BNK_SCALED_GRADIENT:
156*eb910715SAlp Dener         /* Can only enter if pc_type == BNK_PC_BFGS
157*eb910715SAlp Dener            The scaled gradient step did not produce a new iterate;
158*eb910715SAlp Dener            attemp to use the gradient direction.
159*eb910715SAlp Dener            Need to make sure we are not using a different diagonal scaling */
160*eb910715SAlp Dener 
161*eb910715SAlp Dener         ierr = MatLMVMSetScale(bnk->M,0);CHKERRQ(ierr);
162*eb910715SAlp Dener         ierr = MatLMVMSetDelta(bnk->M,1.0);CHKERRQ(ierr);
163*eb910715SAlp Dener         ierr = MatLMVMReset(bnk->M);CHKERRQ(ierr);
164*eb910715SAlp Dener         ierr = MatLMVMUpdate(bnk->M, tao->solution, tao->gradient);CHKERRQ(ierr);
165*eb910715SAlp Dener         ierr = MatLMVMSolve(bnk->M, tao->gradient, bnk->D);CHKERRQ(ierr);
166*eb910715SAlp Dener 
167*eb910715SAlp Dener         bfgsUpdates = 1;
168*eb910715SAlp Dener         ++bnk->grad;
169*eb910715SAlp Dener         stepType = BNK_GRADIENT;
170*eb910715SAlp Dener         break;
171*eb910715SAlp Dener       }
172*eb910715SAlp Dener       ierr = VecScale(bnk->D, -1.0);CHKERRQ(ierr);
173*eb910715SAlp Dener 
174*eb910715SAlp Dener       ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &bnk->f, tao->gradient, bnk->D, &step, &ls_reason);CHKERRQ(ierr);
175*eb910715SAlp Dener       ierr = TaoLineSearchGetFullStepObjective(tao->linesearch, &f_full);CHKERRQ(ierr);
176*eb910715SAlp Dener       ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
177*eb910715SAlp Dener     }
178*eb910715SAlp Dener 
179*eb910715SAlp Dener     if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) {
180*eb910715SAlp Dener       /* Failed to find an improving point */
181*eb910715SAlp Dener       bnk->f = fold;
182*eb910715SAlp Dener       ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
183*eb910715SAlp Dener       ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr);
184*eb910715SAlp Dener       step = 0.0;
185*eb910715SAlp Dener       tao->reason = TAO_DIVERGED_LS_FAILURE;
186*eb910715SAlp Dener       break;
187*eb910715SAlp Dener     }
188*eb910715SAlp Dener 
189*eb910715SAlp Dener     /* Update trust region radius */
190*eb910715SAlp Dener     if (bnk->is_nash || bnk->is_stcg || bnk->is_gltr) {
191*eb910715SAlp Dener       switch(bnk->update_type) {
192*eb910715SAlp Dener       case BNK_UPDATE_STEP:
193*eb910715SAlp Dener         if (stepType == BNK_NEWTON) {
194*eb910715SAlp Dener           if (step < bnk->nu1) {
195*eb910715SAlp Dener             /* Very bad step taken; reduce radius */
196*eb910715SAlp Dener             tao->trust = bnk->omega1 * PetscMin(norm_d, tao->trust);
197*eb910715SAlp Dener           } else if (step < bnk->nu2) {
198*eb910715SAlp Dener             /* Reasonably bad step taken; reduce radius */
199*eb910715SAlp Dener             tao->trust = bnk->omega2 * PetscMin(norm_d, tao->trust);
200*eb910715SAlp Dener           } else if (step < bnk->nu3) {
201*eb910715SAlp Dener             /*  Reasonable step was taken; leave radius alone */
202*eb910715SAlp Dener             if (bnk->omega3 < 1.0) {
203*eb910715SAlp Dener               tao->trust = bnk->omega3 * PetscMin(norm_d, tao->trust);
204*eb910715SAlp Dener             } else if (bnk->omega3 > 1.0) {
205*eb910715SAlp Dener               tao->trust = PetscMax(bnk->omega3 * norm_d, tao->trust);
206*eb910715SAlp Dener             }
207*eb910715SAlp Dener           } else if (step < bnk->nu4) {
208*eb910715SAlp Dener             /*  Full step taken; increase the radius */
209*eb910715SAlp Dener             tao->trust = PetscMax(bnk->omega4 * norm_d, tao->trust);
210*eb910715SAlp Dener           } else {
211*eb910715SAlp Dener             /*  More than full step taken; increase the radius */
212*eb910715SAlp Dener             tao->trust = PetscMax(bnk->omega5 * norm_d, tao->trust);
213*eb910715SAlp Dener           }
214*eb910715SAlp Dener         } else {
215*eb910715SAlp Dener           /*  Newton step was not good; reduce the radius */
216*eb910715SAlp Dener           tao->trust = bnk->omega1 * PetscMin(norm_d, tao->trust);
217*eb910715SAlp Dener         }
218*eb910715SAlp Dener         break;
219*eb910715SAlp Dener 
220*eb910715SAlp Dener       case BNK_UPDATE_REDUCTION:
221*eb910715SAlp Dener         if (stepType == BNK_NEWTON) {
222*eb910715SAlp Dener           /*  Get predicted reduction */
223*eb910715SAlp Dener           ierr = KSPCGGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr);
224*eb910715SAlp Dener           if (prered >= 0.0) {
225*eb910715SAlp Dener             /*  The predicted reduction has the wrong sign.  This cannot */
226*eb910715SAlp Dener             /*  happen in infinite precision arithmetic.  Step should */
227*eb910715SAlp Dener             /*  be rejected! */
228*eb910715SAlp Dener             tao->trust = bnk->alpha1 * PetscMin(tao->trust, norm_d);
229*eb910715SAlp Dener           } else {
230*eb910715SAlp Dener             if (PetscIsInfOrNanReal(f_full)) {
231*eb910715SAlp Dener               tao->trust = bnk->alpha1 * PetscMin(tao->trust, norm_d);
232*eb910715SAlp Dener             } else {
233*eb910715SAlp Dener               /*  Compute and actual reduction */
234*eb910715SAlp Dener               actred = fold - f_full;
235*eb910715SAlp Dener               prered = -prered;
236*eb910715SAlp Dener               if ((PetscAbsScalar(actred) <= bnk->epsilon) &&
237*eb910715SAlp Dener                   (PetscAbsScalar(prered) <= bnk->epsilon)) {
238*eb910715SAlp Dener                 kappa = 1.0;
239*eb910715SAlp Dener               } else {
240*eb910715SAlp Dener                 kappa = actred / prered;
241*eb910715SAlp Dener               }
242*eb910715SAlp Dener 
243*eb910715SAlp Dener               /*  Accept of reject the step and update radius */
244*eb910715SAlp Dener               if (kappa < bnk->eta1) {
245*eb910715SAlp Dener                 /*  Very bad step */
246*eb910715SAlp Dener                 tao->trust = bnk->alpha1 * PetscMin(tao->trust, norm_d);
247*eb910715SAlp Dener               } else if (kappa < bnk->eta2) {
248*eb910715SAlp Dener                 /*  Marginal bad step */
249*eb910715SAlp Dener                 tao->trust = bnk->alpha2 * PetscMin(tao->trust, norm_d);
250*eb910715SAlp Dener               } else if (kappa < bnk->eta3) {
251*eb910715SAlp Dener                 /*  Reasonable step */
252*eb910715SAlp Dener                 if (bnk->alpha3 < 1.0) {
253*eb910715SAlp Dener                   tao->trust = bnk->alpha3 * PetscMin(norm_d, tao->trust);
254*eb910715SAlp Dener                 } else if (bnk->alpha3 > 1.0) {
255*eb910715SAlp Dener                   tao->trust = PetscMax(bnk->alpha3 * norm_d, tao->trust);
256*eb910715SAlp Dener                 }
257*eb910715SAlp Dener               } else if (kappa < bnk->eta4) {
258*eb910715SAlp Dener                 /*  Good step */
259*eb910715SAlp Dener                 tao->trust = PetscMax(bnk->alpha4 * norm_d, tao->trust);
260*eb910715SAlp Dener               } else {
261*eb910715SAlp Dener                 /*  Very good step */
262*eb910715SAlp Dener                 tao->trust = PetscMax(bnk->alpha5 * norm_d, tao->trust);
263*eb910715SAlp Dener               }
264*eb910715SAlp Dener             }
265*eb910715SAlp Dener           }
266*eb910715SAlp Dener         } else {
267*eb910715SAlp Dener           /*  Newton step was not good; reduce the radius */
268*eb910715SAlp Dener           tao->trust = bnk->alpha1 * PetscMin(norm_d, tao->trust);
269*eb910715SAlp Dener         }
270*eb910715SAlp Dener         break;
271*eb910715SAlp Dener 
272*eb910715SAlp Dener       default:
273*eb910715SAlp Dener         if (stepType == BNK_NEWTON) {
274*eb910715SAlp Dener           ierr = KSPCGGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr);
275*eb910715SAlp Dener           if (prered >= 0.0) {
276*eb910715SAlp Dener             /*  The predicted reduction has the wrong sign.  This cannot */
277*eb910715SAlp Dener             /*  happen in infinite precision arithmetic.  Step should */
278*eb910715SAlp Dener             /*  be rejected! */
279*eb910715SAlp Dener             tao->trust = bnk->gamma1 * PetscMin(tao->trust, norm_d);
280*eb910715SAlp Dener           } else {
281*eb910715SAlp Dener             if (PetscIsInfOrNanReal(f_full)) {
282*eb910715SAlp Dener               tao->trust = bnk->gamma1 * PetscMin(tao->trust, norm_d);
283*eb910715SAlp Dener             } else {
284*eb910715SAlp Dener               actred = fold - f_full;
285*eb910715SAlp Dener               prered = -prered;
286*eb910715SAlp Dener               if ((PetscAbsScalar(actred) <= bnk->epsilon) && (PetscAbsScalar(prered) <= bnk->epsilon)) {
287*eb910715SAlp Dener                 kappa = 1.0;
288*eb910715SAlp Dener               } else {
289*eb910715SAlp Dener                 kappa = actred / prered;
290*eb910715SAlp Dener               }
291*eb910715SAlp Dener 
292*eb910715SAlp Dener               tau_1 = bnk->theta * gdx / (bnk->theta * gdx - (1.0 - bnk->theta) * prered + actred);
293*eb910715SAlp Dener               tau_2 = bnk->theta * gdx / (bnk->theta * gdx + (1.0 + bnk->theta) * prered - actred);
294*eb910715SAlp Dener               tau_min = PetscMin(tau_1, tau_2);
295*eb910715SAlp Dener               tau_max = PetscMax(tau_1, tau_2);
296*eb910715SAlp Dener 
297*eb910715SAlp Dener               if (kappa >= 1.0 - bnk->mu1) {
298*eb910715SAlp Dener                 /*  Great agreement */
299*eb910715SAlp Dener                 if (tau_max < 1.0) {
300*eb910715SAlp Dener                   tao->trust = PetscMax(tao->trust, bnk->gamma3 * norm_d);
301*eb910715SAlp Dener                 } else if (tau_max > bnk->gamma4) {
302*eb910715SAlp Dener                   tao->trust = PetscMax(tao->trust, bnk->gamma4 * norm_d);
303*eb910715SAlp Dener                 } else {
304*eb910715SAlp Dener                   tao->trust = PetscMax(tao->trust, tau_max * norm_d);
305*eb910715SAlp Dener                 }
306*eb910715SAlp Dener               } else if (kappa >= 1.0 - bnk->mu2) {
307*eb910715SAlp Dener                 /*  Good agreement */
308*eb910715SAlp Dener 
309*eb910715SAlp Dener                 if (tau_max < bnk->gamma2) {
310*eb910715SAlp Dener                   tao->trust = bnk->gamma2 * PetscMin(tao->trust, norm_d);
311*eb910715SAlp Dener                 } else if (tau_max > bnk->gamma3) {
312*eb910715SAlp Dener                   tao->trust = PetscMax(tao->trust, bnk->gamma3 * norm_d);
313*eb910715SAlp Dener                 } else if (tau_max < 1.0) {
314*eb910715SAlp Dener                   tao->trust = tau_max * PetscMin(tao->trust, norm_d);
315*eb910715SAlp Dener                 } else {
316*eb910715SAlp Dener                   tao->trust = PetscMax(tao->trust, tau_max * norm_d);
317*eb910715SAlp Dener                 }
318*eb910715SAlp Dener               } else {
319*eb910715SAlp Dener                 /*  Not good agreement */
320*eb910715SAlp Dener                 if (tau_min > 1.0) {
321*eb910715SAlp Dener                   tao->trust = bnk->gamma2 * PetscMin(tao->trust, norm_d);
322*eb910715SAlp Dener                 } else if (tau_max < bnk->gamma1) {
323*eb910715SAlp Dener                   tao->trust = bnk->gamma1 * PetscMin(tao->trust, norm_d);
324*eb910715SAlp Dener                 } else if ((tau_min < bnk->gamma1) && (tau_max >= 1.0)) {
325*eb910715SAlp Dener                   tao->trust = bnk->gamma1 * PetscMin(tao->trust, norm_d);
326*eb910715SAlp Dener                 } else if ((tau_1 >= bnk->gamma1) && (tau_1 < 1.0) && ((tau_2 < bnk->gamma1) || (tau_2 >= 1.0))) {
327*eb910715SAlp Dener                   tao->trust = tau_1 * PetscMin(tao->trust, norm_d);
328*eb910715SAlp Dener                 } else if ((tau_2 >= bnk->gamma1) && (tau_2 < 1.0) && ((tau_1 < bnk->gamma1) || (tau_2 >= 1.0))) {
329*eb910715SAlp Dener                   tao->trust = tau_2 * PetscMin(tao->trust, norm_d);
330*eb910715SAlp Dener                 } else {
331*eb910715SAlp Dener                   tao->trust = tau_max * PetscMin(tao->trust, norm_d);
332*eb910715SAlp Dener                 }
333*eb910715SAlp Dener               }
334*eb910715SAlp Dener             }
335*eb910715SAlp Dener           }
336*eb910715SAlp Dener         } else {
337*eb910715SAlp Dener           /*  Newton step was not good; reduce the radius */
338*eb910715SAlp Dener           tao->trust = bnk->gamma1 * PetscMin(norm_d, tao->trust);
339*eb910715SAlp Dener         }
340*eb910715SAlp Dener         break;
341*eb910715SAlp Dener       }
342*eb910715SAlp Dener 
343*eb910715SAlp Dener       /*  The radius may have been increased; modify if it is too large */
344*eb910715SAlp Dener       tao->trust = PetscMin(tao->trust, bnk->max_radius);
345*eb910715SAlp Dener     }
346*eb910715SAlp Dener 
347*eb910715SAlp Dener     /*  Check for termination */
348*eb910715SAlp Dener     ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr);
349*eb910715SAlp Dener     if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
350*eb910715SAlp Dener     needH = 1;
351*eb910715SAlp Dener     ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
352*eb910715SAlp Dener     ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,step);CHKERRQ(ierr);
353*eb910715SAlp Dener     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
354*eb910715SAlp Dener   }
355*eb910715SAlp Dener   PetscFunctionReturn(0);
356*eb910715SAlp Dener }
357*eb910715SAlp Dener 
358*eb910715SAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNLS(Tao tao)
359*eb910715SAlp Dener {
360*eb910715SAlp Dener   PetscErrorCode ierr;
361*eb910715SAlp Dener 
362*eb910715SAlp Dener   PetscFunctionBegin;
363*eb910715SAlp Dener   ierr = TaoCreate_BNK(tao);CHKERRQ(ierr);
364*eb910715SAlp Dener   tao->ops->solve=TaoSolve_BNLS;
365*eb910715SAlp Dener   PetscFunctionReturn(0);
366*eb910715SAlp Dener }