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