Actual source code: nls.c

petsc-dev 2014-02-02
Report Typos and Errors
  1: #include <petsctaolinesearch.h>
  2: #include <../src/tao/matrix/lmvmmat.h>
  3: #include <../src/tao/unconstrained/impls/nls/nls.h>

  5: #include <petscksp.h>
  6: #include <petscpc.h>
  7: #include <petsc-private/kspimpl.h>
  8: #include <petsc-private/pcimpl.h>

 10: #define NLS_KSP_CG      0
 11: #define NLS_KSP_NASH    1
 12: #define NLS_KSP_STCG    2
 13: #define NLS_KSP_GLTR    3
 14: #define NLS_KSP_PETSC   4
 15: #define NLS_KSP_TYPES   5

 17: #define NLS_PC_NONE     0
 18: #define NLS_PC_AHESS    1
 19: #define NLS_PC_BFGS     2
 20: #define NLS_PC_PETSC    3
 21: #define NLS_PC_TYPES    4

 23: #define BFGS_SCALE_AHESS        0
 24: #define BFGS_SCALE_PHESS        1
 25: #define BFGS_SCALE_BFGS         2
 26: #define BFGS_SCALE_TYPES        3

 28: #define NLS_INIT_CONSTANT         0
 29: #define NLS_INIT_DIRECTION        1
 30: #define NLS_INIT_INTERPOLATION    2
 31: #define NLS_INIT_TYPES            3

 33: #define NLS_UPDATE_STEP           0
 34: #define NLS_UPDATE_REDUCTION      1
 35: #define NLS_UPDATE_INTERPOLATION  2
 36: #define NLS_UPDATE_TYPES          3

 38: static const char *NLS_KSP[64] = {"cg", "nash", "stcg", "gltr", "petsc"};

 40: static const char *NLS_PC[64] = {"none", "ahess", "bfgs", "petsc"};

 42: static const char *BFGS_SCALE[64] = {"ahess", "phess", "bfgs"};

 44: static const char *NLS_INIT[64] = {"constant", "direction", "interpolation"};

 46: static const char *NLS_UPDATE[64] = {"step", "reduction", "interpolation"};

 48: static PetscErrorCode MatLMVMSolveShell(PC pc, Vec b, Vec x);
 49: /* Routine for BFGS preconditioner


 52:  Implements Newton's Method with a line search approach for solving
 53:  unconstrained minimization problems.  A More'-Thuente line search
 54:  is used to guarantee that the bfgs preconditioner remains positive
 55:  definite.

 57:  The method can shift the Hessian matrix.  The shifting procedure is
 58:  adapted from the PATH algorithm for solving complementarity
 59:  problems.

 61:  The linear system solve should be done with a conjugate gradient
 62:  method, although any method can be used. */

 64: #define NLS_NEWTON              0
 65: #define NLS_BFGS                1
 66: #define NLS_SCALED_GRADIENT     2
 67: #define NLS_GRADIENT            3

 71: static PetscErrorCode TaoSolve_NLS(Tao tao)
 72: {
 73:   PetscErrorCode                 ierr;
 74:   TAO_NLS                        *nlsP = (TAO_NLS *)tao->data;
 75:   PC                             pc;
 76:   KSPConvergedReason             ksp_reason;
 77:   TaoLineSearchTerminationReason ls_reason;
 78:   TaoTerminationReason     reason;

 80:   PetscReal                      fmin, ftrial, f_full, prered, actred, kappa, sigma;
 81:   PetscReal                      tau, tau_1, tau_2, tau_max, tau_min, max_radius;
 82:   PetscReal                      f, fold, gdx, gnorm, pert;
 83:   PetscReal                      step = 1.0;
 84:   PetscReal                      delta;
 85:   PetscReal                      norm_d = 0.0, e_min;

 87:   MatStructure                   matflag;

 89:   PetscInt                       stepType;
 90:   PetscInt                       iter = 0;
 91:   PetscInt                       bfgsUpdates = 0;
 92:   PetscInt                       n,N,kspits;
 93:   PetscInt                       needH;

 95:   PetscInt                       i_max = 5;
 96:   PetscInt                       j_max = 1;
 97:   PetscInt                       i, j;

100:   if (tao->XL || tao->XU || tao->ops->computebounds) {
101:     PetscPrintf(((PetscObject)tao)->comm,"WARNING: Variable bounds have been set but will be ignored by nls algorithm\n");
102:   }

104:   /* Initialized variables */
105:   pert = nlsP->sval;

107:   nlsP->ksp_atol = 0;
108:   nlsP->ksp_rtol = 0;
109:   nlsP->ksp_dtol = 0;
110:   nlsP->ksp_ctol = 0;
111:   nlsP->ksp_negc = 0;
112:   nlsP->ksp_iter = 0;
113:   nlsP->ksp_othr = 0;

115:   /* Modify the linear solver to a trust region method if desired */
116:   switch(nlsP->ksp_type) {
117:   case NLS_KSP_CG:
118:     KSPSetType(tao->ksp, KSPCG);
119:     KSPSetFromOptions(tao->ksp);
120:     break;

122:   case NLS_KSP_NASH:
123:     KSPSetType(tao->ksp, KSPNASH);
124:     KSPSetFromOptions(tao->ksp);
125:     break;

127:   case NLS_KSP_STCG:
128:     KSPSetType(tao->ksp, KSPSTCG);
129:     KSPSetFromOptions(tao->ksp);
130:     break;

132:   case NLS_KSP_GLTR:
133:     KSPSetType(tao->ksp, KSPGLTR);
134:     KSPSetFromOptions(tao->ksp);
135:     break;

137:   default:
138:     /* Use the method set by the ksp_type */
139:     break;
140:   }

142:   /* Initialize trust-region radius when using nash, stcg, or gltr
143:    Will be reset during the first iteration */
144:   if (NLS_KSP_NASH == nlsP->ksp_type) {
145:     KSPNASHSetRadius(tao->ksp,nlsP->max_radius);
146:   } else if (NLS_KSP_STCG == nlsP->ksp_type) {
147:     KSPSTCGSetRadius(tao->ksp,nlsP->max_radius);
148:   } else if (NLS_KSP_GLTR == nlsP->ksp_type) {
149:     KSPGLTRSetRadius(tao->ksp,nlsP->max_radius);
150:   }

152:   if (NLS_KSP_NASH == nlsP->ksp_type || NLS_KSP_STCG == nlsP->ksp_type || NLS_KSP_GLTR == nlsP->ksp_type) {
153:     tao->trust = tao->trust0;

155:     if (tao->trust < 0.0) SETERRQ(PETSC_COMM_SELF,1, "Initial radius negative");

157:     /* Modify the radius if it is too large or small */
158:     tao->trust = PetscMax(tao->trust, nlsP->min_radius);
159:     tao->trust = PetscMin(tao->trust, nlsP->max_radius);
160:   }

162:   /* Get vectors we will need */
163:   if (NLS_PC_BFGS == nlsP->pc_type && !nlsP->M) {
164:     VecGetLocalSize(tao->solution,&n);
165:     VecGetSize(tao->solution,&N);
166:     MatCreateLMVM(((PetscObject)tao)->comm,n,N,&nlsP->M);
167:     MatLMVMAllocateVectors(nlsP->M,tao->solution);
168:   }

170:   /* Check convergence criteria */
171:   TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient);
172:   VecNorm(tao->gradient,NORM_2,&gnorm);
173:   if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
174:   needH = 1;

176:   TaoMonitor(tao, iter, f, gnorm, 0.0, 1.0, &reason);
177:   if (reason != TAO_CONTINUE_ITERATING) return(0);

179:   /* create vectors for the limited memory preconditioner */
180:   if ((NLS_PC_BFGS == nlsP->pc_type) && (BFGS_SCALE_BFGS != nlsP->bfgs_scale_type)) {
181:     if (!nlsP->Diag) {
182:       VecDuplicate(tao->solution,&nlsP->Diag);
183:     }
184:   }

186:   /* Modify the preconditioner to use the bfgs approximation */
187:   KSPGetPC(tao->ksp, &pc);
188:   switch(nlsP->pc_type) {
189:   case NLS_PC_NONE:
190:     PCSetType(pc, PCNONE);
191:     if (pc->ops->setfromoptions) {
192:       (*pc->ops->setfromoptions)(pc);
193:     }
194:     break;

196:   case NLS_PC_AHESS:
197:     PCSetType(pc, PCJACOBI);
198:     if (pc->ops->setfromoptions) {
199:       (*pc->ops->setfromoptions)(pc);
200:     }
201:     PCJacobiSetUseAbs(pc);
202:     break;

204:   case NLS_PC_BFGS:
205:     PCSetType(pc, PCSHELL);
206:     if (pc->ops->setfromoptions) {
207:       (*pc->ops->setfromoptions)(pc);
208:     }
209:     PCShellSetName(pc, "bfgs");
210:     PCShellSetContext(pc, nlsP->M);
211:     PCShellSetApply(pc, MatLMVMSolveShell);
212:     break;

214:   default:
215:     /* Use the pc method set by pc_type */
216:     break;
217:   }

219:   /* Initialize trust-region radius.  The initialization is only performed
220:      when we are using Nash, Steihaug-Toint or the Generalized Lanczos method. */
221:   if (NLS_KSP_NASH == nlsP->ksp_type || NLS_KSP_STCG == nlsP->ksp_type || NLS_KSP_GLTR == nlsP->ksp_type) {
222:     switch(nlsP->init_type) {
223:     case NLS_INIT_CONSTANT:
224:       /* Use the initial radius specified */
225:       break;

227:     case NLS_INIT_INTERPOLATION:
228:       /* Use the initial radius specified */
229:       max_radius = 0.0;

231:       for (j = 0; j < j_max; ++j) {
232:         fmin = f;
233:         sigma = 0.0;

235:         if (needH) {
236:           TaoComputeHessian(tao, tao->solution, &tao->hessian, &tao->hessian_pre, &matflag);
237:           needH = 0;
238:         }

240:         for (i = 0; i < i_max; ++i) {
241:           VecCopy(tao->solution,nlsP->W);
242:           VecAXPY(nlsP->W,-tao->trust/gnorm,tao->gradient);
243:           TaoComputeObjective(tao, nlsP->W, &ftrial);
244:           if (PetscIsInfOrNanReal(ftrial)) {
245:             tau = nlsP->gamma1_i;
246:           } else {
247:             if (ftrial < fmin) {
248:               fmin = ftrial;
249:               sigma = -tao->trust / gnorm;
250:             }

252:             MatMult(tao->hessian, tao->gradient, nlsP->D);
253:             VecDot(tao->gradient, nlsP->D, &prered);

255:             prered = tao->trust * (gnorm - 0.5 * tao->trust * prered / (gnorm * gnorm));
256:             actred = f - ftrial;
257:             if ((PetscAbsScalar(actred) <= nlsP->epsilon) && (PetscAbsScalar(prered) <= nlsP->epsilon)) {
258:               kappa = 1.0;
259:             } else {
260:               kappa = actred / prered;
261:             }

263:             tau_1 = nlsP->theta_i * gnorm * tao->trust / (nlsP->theta_i * gnorm * tao->trust + (1.0 - nlsP->theta_i) * prered - actred);
264:             tau_2 = nlsP->theta_i * gnorm * tao->trust / (nlsP->theta_i * gnorm * tao->trust - (1.0 + nlsP->theta_i) * prered + actred);
265:             tau_min = PetscMin(tau_1, tau_2);
266:             tau_max = PetscMax(tau_1, tau_2);

268:             if (PetscAbsScalar(kappa - 1.0) <= nlsP->mu1_i) {
269:               /* Great agreement */
270:               max_radius = PetscMax(max_radius, tao->trust);

272:               if (tau_max < 1.0) {
273:                 tau = nlsP->gamma3_i;
274:               } else if (tau_max > nlsP->gamma4_i) {
275:                 tau = nlsP->gamma4_i;
276:               } else if (tau_1 >= 1.0 && tau_1 <= nlsP->gamma4_i && tau_2 < 1.0) {
277:                 tau = tau_1;
278:               } else if (tau_2 >= 1.0 && tau_2 <= nlsP->gamma4_i && tau_1 < 1.0) {
279:                 tau = tau_2;
280:               } else {
281:                 tau = tau_max;
282:               }
283:             } else if (PetscAbsScalar(kappa - 1.0) <= nlsP->mu2_i) {
284:               /* Good agreement */
285:               max_radius = PetscMax(max_radius, tao->trust);

287:               if (tau_max < nlsP->gamma2_i) {
288:                 tau = nlsP->gamma2_i;
289:               } else if (tau_max > nlsP->gamma3_i) {
290:                 tau = nlsP->gamma3_i;
291:               } else {
292:                 tau = tau_max;
293:               }
294:             } else {
295:               /* Not good agreement */
296:               if (tau_min > 1.0) {
297:                 tau = nlsP->gamma2_i;
298:               } else if (tau_max < nlsP->gamma1_i) {
299:                 tau = nlsP->gamma1_i;
300:               } else if ((tau_min < nlsP->gamma1_i) && (tau_max >= 1.0)) {
301:                 tau = nlsP->gamma1_i;
302:               } else if ((tau_1 >= nlsP->gamma1_i) && (tau_1 < 1.0) && ((tau_2 < nlsP->gamma1_i) || (tau_2 >= 1.0))) {
303:                 tau = tau_1;
304:               } else if ((tau_2 >= nlsP->gamma1_i) && (tau_2 < 1.0) && ((tau_1 < nlsP->gamma1_i) || (tau_2 >= 1.0))) {
305:                 tau = tau_2;
306:               } else {
307:                 tau = tau_max;
308:               }
309:             }
310:           }
311:           tao->trust = tau * tao->trust;
312:         }

314:         if (fmin < f) {
315:           f = fmin;
316:           VecAXPY(tao->solution,sigma,tao->gradient);
317:           TaoComputeGradient(tao,tao->solution,tao->gradient);

319:           VecNorm(tao->gradient,NORM_2,&gnorm);
320:           if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute gradient generated Inf or NaN");
321:           needH = 1;

323:           TaoMonitor(tao, iter, f, gnorm, 0.0, 1.0, &reason);
324:           if (reason != TAO_CONTINUE_ITERATING) return(0);
325:         }
326:       }
327:       tao->trust = PetscMax(tao->trust, max_radius);

329:       /* Modify the radius if it is too large or small */
330:       tao->trust = PetscMax(tao->trust, nlsP->min_radius);
331:       tao->trust = PetscMin(tao->trust, nlsP->max_radius);
332:       break;

334:     default:
335:       /* Norm of the first direction will initialize radius */
336:       tao->trust = 0.0;
337:       break;
338:     }
339:   }

341:   /* Set initial scaling for the BFGS preconditioner
342:      This step is done after computing the initial trust-region radius
343:      since the function value may have decreased */
344:   if (NLS_PC_BFGS == nlsP->pc_type) {
345:     if (f != 0.0) {
346:       delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
347:     } else {
348:       delta = 2.0 / (gnorm*gnorm);
349:     }
350:     MatLMVMSetDelta(nlsP->M,delta);
351:   }

353:   /* Set counter for gradient/reset steps*/
354:   nlsP->newt = 0;
355:   nlsP->bfgs = 0;
356:   nlsP->sgrad = 0;
357:   nlsP->grad = 0;

359:   /* Have not converged; continue with Newton method */
360:   while (reason == TAO_CONTINUE_ITERATING) {
361:     ++iter;

363:     /* Compute the Hessian */
364:     if (needH) {
365:       TaoComputeHessian(tao, tao->solution, &tao->hessian, &tao->hessian_pre, &matflag);
366:       needH = 0;
367:     }

369:     if ((NLS_PC_BFGS == nlsP->pc_type) && (BFGS_SCALE_AHESS == nlsP->bfgs_scale_type)) {
370:       /* Obtain diagonal for the bfgs preconditioner  */
371:       MatGetDiagonal(tao->hessian, nlsP->Diag);
372:       VecAbs(nlsP->Diag);
373:       VecReciprocal(nlsP->Diag);
374:       MatLMVMSetScale(nlsP->M,nlsP->Diag);
375:     }

377:     /* Shift the Hessian matrix */
378:     if (pert > 0) {
379:       MatShift(tao->hessian, pert);
380:       if (tao->hessian != tao->hessian_pre) {
381:         MatShift(tao->hessian_pre, pert);
382:       }
383:     }

385:     if (NLS_PC_BFGS == nlsP->pc_type) {
386:       if (BFGS_SCALE_PHESS == nlsP->bfgs_scale_type) {
387:         /* Obtain diagonal for the bfgs preconditioner  */
388:         MatGetDiagonal(tao->hessian, nlsP->Diag);
389:         VecAbs(nlsP->Diag);
390:         VecReciprocal(nlsP->Diag);
391:         MatLMVMSetScale(nlsP->M,nlsP->Diag);
392:       }
393:       /* Update the limited memory preconditioner */
394:       MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);
395:       ++bfgsUpdates;
396:     }

398:     /* Solve the Newton system of equations */
399:     KSPSetOperators(tao->ksp,tao->hessian,tao->hessian_pre,matflag);
400:     if (NLS_KSP_NASH == nlsP->ksp_type || NLS_KSP_STCG == nlsP->ksp_type ||  NLS_KSP_GLTR == nlsP->ksp_type) {

402:       if (NLS_KSP_NASH == nlsP->ksp_type) {
403:         KSPNASHSetRadius(tao->ksp,nlsP->max_radius);
404:       } else if (NLS_KSP_STCG == nlsP->ksp_type) {
405:          KSPSTCGSetRadius(tao->ksp,nlsP->max_radius);
406:       } else if (NLS_KSP_GLTR == nlsP->ksp_type) {
407:         KSPGLTRSetRadius(tao->ksp,nlsP->max_radius);
408:       }

410:       KSPSolve(tao->ksp, tao->gradient, nlsP->D);
411:       KSPGetIterationNumber(tao->ksp,&kspits);
412:       tao->ksp_its+=kspits;

414:       if (NLS_KSP_NASH == nlsP->ksp_type) {
415:         KSPNASHGetNormD(tao->ksp,&norm_d);
416:       } else if (NLS_KSP_STCG == nlsP->ksp_type) {
417:          KSPSTCGGetNormD(tao->ksp,&norm_d);
418:       } else if (NLS_KSP_GLTR == nlsP->ksp_type) {
419:         KSPGLTRGetNormD(tao->ksp,&norm_d);
420:       }

422:       if (0.0 == tao->trust) {
423:         /* Radius was uninitialized; use the norm of the direction */
424:         if (norm_d > 0.0) {
425:           tao->trust = norm_d;

427:           /* Modify the radius if it is too large or small */
428:           tao->trust = PetscMax(tao->trust, nlsP->min_radius);
429:           tao->trust = PetscMin(tao->trust, nlsP->max_radius);
430:         } else {
431:           /* The direction was bad; set radius to default value and re-solve
432:              the trust-region subproblem to get a direction */
433:           tao->trust = tao->trust0;

435:           /* Modify the radius if it is too large or small */
436:           tao->trust = PetscMax(tao->trust, nlsP->min_radius);
437:           tao->trust = PetscMin(tao->trust, nlsP->max_radius);

439:           if (NLS_KSP_NASH == nlsP->ksp_type) {
440:             KSPNASHSetRadius(tao->ksp,nlsP->max_radius);
441:           } else if (NLS_KSP_STCG == nlsP->ksp_type) {
442:             KSPSTCGSetRadius(tao->ksp,nlsP->max_radius);
443:           } else if (NLS_KSP_GLTR == nlsP->ksp_type) {
444:             KSPGLTRSetRadius(tao->ksp,nlsP->max_radius);
445:           }

447:           KSPSolve(tao->ksp, tao->gradient, nlsP->D);
448:           KSPGetIterationNumber(tao->ksp,&kspits);
449:           tao->ksp_its+=kspits;
450:           if (NLS_KSP_NASH == nlsP->ksp_type) {
451:             KSPNASHGetNormD(tao->ksp,&norm_d);
452:           } else if (NLS_KSP_STCG == nlsP->ksp_type) {
453:             KSPSTCGGetNormD(tao->ksp,&norm_d);
454:           } else if (NLS_KSP_GLTR == nlsP->ksp_type) {
455:             KSPGLTRGetNormD(tao->ksp,&norm_d);
456:           }

458:           if (norm_d == 0.0) SETERRQ(PETSC_COMM_SELF,1, "Initial direction zero");
459:         }
460:       }
461:     } else {
462:       KSPSolve(tao->ksp, tao->gradient, nlsP->D);
463:       KSPGetIterationNumber(tao->ksp, &kspits);
464:       tao->ksp_its += kspits;
465:     }
466:     VecScale(nlsP->D, -1.0);
467:     KSPGetConvergedReason(tao->ksp, &ksp_reason);
468:     if ((KSP_DIVERGED_INDEFINITE_PC == ksp_reason) &&  (NLS_PC_BFGS == nlsP->pc_type) && (bfgsUpdates > 1)) {
469:       /* Preconditioner is numerically indefinite; reset the
470:          approximate if using BFGS preconditioning. */

472:       if (f != 0.0) {
473:         delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
474:       } else {
475:         delta = 2.0 / (gnorm*gnorm);
476:       }
477:       MatLMVMSetDelta(nlsP->M,delta);
478:       MatLMVMReset(nlsP->M);
479:       MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);
480:       bfgsUpdates = 1;
481:     }

483:     if (KSP_CONVERGED_ATOL == ksp_reason) {
484:       ++nlsP->ksp_atol;
485:     } else if (KSP_CONVERGED_RTOL == ksp_reason) {
486:       ++nlsP->ksp_rtol;
487:     } else if (KSP_CONVERGED_CG_CONSTRAINED == ksp_reason) {
488:       ++nlsP->ksp_ctol;
489:     } else if (KSP_CONVERGED_CG_NEG_CURVE == ksp_reason) {
490:       ++nlsP->ksp_negc;
491:     } else if (KSP_DIVERGED_DTOL == ksp_reason) {
492:       ++nlsP->ksp_dtol;
493:     } else if (KSP_DIVERGED_ITS == ksp_reason) {
494:       ++nlsP->ksp_iter;
495:     } else {
496:       ++nlsP->ksp_othr;
497:     }

499:     /* Check for success (descent direction) */
500:     VecDot(nlsP->D, tao->gradient, &gdx);
501:     if ((gdx >= 0.0) || PetscIsInfOrNanReal(gdx)) {
502:       /* Newton step is not descent or direction produced Inf or NaN
503:          Update the perturbation for next time */
504:       if (pert <= 0.0) {
505:         /* Initialize the perturbation */
506:         pert = PetscMin(nlsP->imax, PetscMax(nlsP->imin, nlsP->imfac * gnorm));
507:         if (NLS_KSP_GLTR == nlsP->ksp_type) {
508:           KSPGLTRGetMinEig(tao->ksp,&e_min);
509:           pert = PetscMax(pert, -e_min);
510:         }
511:       } else {
512:         /* Increase the perturbation */
513:         pert = PetscMin(nlsP->pmax, PetscMax(nlsP->pgfac * pert, nlsP->pmgfac * gnorm));
514:       }

516:       if (NLS_PC_BFGS != nlsP->pc_type) {
517:         /* We don't have the bfgs matrix around and updated
518:            Must use gradient direction in this case */
519:         VecCopy(tao->gradient, nlsP->D);
520:         VecScale(nlsP->D, -1.0);
521:         ++nlsP->grad;
522:         stepType = NLS_GRADIENT;
523:       } else {
524:         /* Attempt to use the BFGS direction */
525:         MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);
526:         VecScale(nlsP->D, -1.0);

528:         /* Check for success (descent direction) */
529:         VecDot(tao->gradient, nlsP->D, &gdx);
530:         if ((gdx >= 0) || PetscIsInfOrNanReal(gdx)) {
531:           /* BFGS direction is not descent or direction produced not a number
532:              We can assert bfgsUpdates > 1 in this case because
533:              the first solve produces the scaled gradient direction,
534:              which is guaranteed to be descent */

536:           /* Use steepest descent direction (scaled) */

538:           if (f != 0.0) {
539:             delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
540:           } else {
541:             delta = 2.0 / (gnorm*gnorm);
542:           }
543:           MatLMVMSetDelta(nlsP->M, delta);
544:           MatLMVMReset(nlsP->M);
545:           MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);
546:           MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);
547:           VecScale(nlsP->D, -1.0);

549:           bfgsUpdates = 1;
550:           ++nlsP->sgrad;
551:           stepType = NLS_SCALED_GRADIENT;
552:         } else {
553:           if (1 == bfgsUpdates) {
554:             /* The first BFGS direction is always the scaled gradient */
555:             ++nlsP->sgrad;
556:             stepType = NLS_SCALED_GRADIENT;
557:           } else {
558:             ++nlsP->bfgs;
559:             stepType = NLS_BFGS;
560:           }
561:         }
562:       }
563:     } else {
564:       /* Computed Newton step is descent */
565:       switch (ksp_reason) {
566:       case KSP_DIVERGED_NANORINF:
567:       case KSP_DIVERGED_BREAKDOWN:
568:       case KSP_DIVERGED_INDEFINITE_MAT:
569:       case KSP_DIVERGED_INDEFINITE_PC:
570:       case KSP_CONVERGED_CG_NEG_CURVE:
571:         /* Matrix or preconditioner is indefinite; increase perturbation */
572:         if (pert <= 0.0) {
573:           /* Initialize the perturbation */
574:           pert = PetscMin(nlsP->imax, PetscMax(nlsP->imin, nlsP->imfac * gnorm));
575:           if (NLS_KSP_GLTR == nlsP->ksp_type) {
576:             KSPGLTRGetMinEig(tao->ksp, &e_min);
577:             pert = PetscMax(pert, -e_min);
578:           }
579:         } else {
580:           /* Increase the perturbation */
581:           pert = PetscMin(nlsP->pmax, PetscMax(nlsP->pgfac * pert, nlsP->pmgfac * gnorm));
582:         }
583:         break;

585:       default:
586:         /* Newton step computation is good; decrease perturbation */
587:         pert = PetscMin(nlsP->psfac * pert, nlsP->pmsfac * gnorm);
588:         if (pert < nlsP->pmin) {
589:           pert = 0.0;
590:         }
591:         break;
592:       }

594:       ++nlsP->newt;
595:       stepType = NLS_NEWTON;
596:     }

598:     /* Perform the linesearch */
599:     fold = f;
600:     VecCopy(tao->solution, nlsP->Xold);
601:     VecCopy(tao->gradient, nlsP->Gold);

603:     TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, nlsP->D, &step, &ls_reason);
604:     TaoAddLineSearchCounts(tao);

606:     while (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER && stepType != NLS_GRADIENT) {      /* Linesearch failed */
607:       f = fold;
608:       VecCopy(nlsP->Xold, tao->solution);
609:       VecCopy(nlsP->Gold, tao->gradient);

611:       switch(stepType) {
612:       case NLS_NEWTON:
613:         /* Failed to obtain acceptable iterate with Newton 1step
614:            Update the perturbation for next time */
615:         if (pert <= 0.0) {
616:           /* Initialize the perturbation */
617:           pert = PetscMin(nlsP->imax, PetscMax(nlsP->imin, nlsP->imfac * gnorm));
618:           if (NLS_KSP_GLTR == nlsP->ksp_type) {
619:             KSPGLTRGetMinEig(tao->ksp,&e_min);
620:             pert = PetscMax(pert, -e_min);
621:           }
622:         } else {
623:           /* Increase the perturbation */
624:           pert = PetscMin(nlsP->pmax, PetscMax(nlsP->pgfac * pert, nlsP->pmgfac * gnorm));
625:         }

627:         if (NLS_PC_BFGS != nlsP->pc_type) {
628:           /* We don't have the bfgs matrix around and being updated
629:              Must use gradient direction in this case */
630:           VecCopy(tao->gradient, nlsP->D);
631:           ++nlsP->grad;
632:           stepType = NLS_GRADIENT;
633:         } else {
634:           /* Attempt to use the BFGS direction */
635:           MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);
636:           /* Check for success (descent direction) */
637:           VecDot(tao->solution, nlsP->D, &gdx);
638:           if ((gdx <= 0) || PetscIsInfOrNanReal(gdx)) {
639:             /* BFGS direction is not descent or direction produced not a number
640:                We can assert bfgsUpdates > 1 in this case
641:                Use steepest descent direction (scaled) */

643:             if (f != 0.0) {
644:               delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
645:             } else {
646:               delta = 2.0 / (gnorm*gnorm);
647:             }
648:             MatLMVMSetDelta(nlsP->M, delta);
649:             MatLMVMReset(nlsP->M);
650:             MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);
651:             MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);

653:             bfgsUpdates = 1;
654:             ++nlsP->sgrad;
655:             stepType = NLS_SCALED_GRADIENT;
656:           } else {
657:             if (1 == bfgsUpdates) {
658:               /* The first BFGS direction is always the scaled gradient */
659:               ++nlsP->sgrad;
660:               stepType = NLS_SCALED_GRADIENT;
661:             } else {
662:               ++nlsP->bfgs;
663:               stepType = NLS_BFGS;
664:             }
665:           }
666:         }
667:         break;

669:       case NLS_BFGS:
670:         /* Can only enter if pc_type == NLS_PC_BFGS
671:            Failed to obtain acceptable iterate with BFGS step
672:            Attempt to use the scaled gradient direction */

674:         if (f != 0.0) {
675:           delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm);
676:         } else {
677:           delta = 2.0 / (gnorm*gnorm);
678:         }
679:         MatLMVMSetDelta(nlsP->M, delta);
680:         MatLMVMReset(nlsP->M);
681:         MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);
682:         MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);

684:         bfgsUpdates = 1;
685:         ++nlsP->sgrad;
686:         stepType = NLS_SCALED_GRADIENT;
687:         break;

689:       case NLS_SCALED_GRADIENT:
690:         /* Can only enter if pc_type == NLS_PC_BFGS
691:            The scaled gradient step did not produce a new iterate;
692:            attemp to use the gradient direction.
693:            Need to make sure we are not using a different diagonal scaling */

695:         MatLMVMSetScale(nlsP->M,0);
696:         MatLMVMSetDelta(nlsP->M,1.0);
697:         MatLMVMReset(nlsP->M);
698:         MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);
699:         MatLMVMSolve(nlsP->M, tao->gradient, nlsP->D);

701:         bfgsUpdates = 1;
702:         ++nlsP->grad;
703:         stepType = NLS_GRADIENT;
704:         break;
705:       }
706:       VecScale(nlsP->D, -1.0);

708:       TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, nlsP->D, &step, &ls_reason);
709:       TaoLineSearchGetFullStepObjective(tao->linesearch, &f_full);
710:       TaoAddLineSearchCounts(tao);
711:     }

713:     if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) {
714:       /* Failed to find an improving point */
715:       f = fold;
716:       VecCopy(nlsP->Xold, tao->solution);
717:       VecCopy(nlsP->Gold, tao->gradient);
718:       step = 0.0;
719:       reason = TAO_DIVERGED_LS_FAILURE;
720:       tao->reason = TAO_DIVERGED_LS_FAILURE;
721:       break;
722:     }

724:     /* Update trust region radius */
725:     if (NLS_KSP_NASH == nlsP->ksp_type || NLS_KSP_STCG == nlsP->ksp_type || NLS_KSP_GLTR == nlsP->ksp_type) {
726:       switch(nlsP->update_type) {
727:       case NLS_UPDATE_STEP:
728:         if (stepType == NLS_NEWTON) {
729:           if (step < nlsP->nu1) {
730:             /* Very bad step taken; reduce radius */
731:             tao->trust = nlsP->omega1 * PetscMin(norm_d, tao->trust);
732:           } else if (step < nlsP->nu2) {
733:             /* Reasonably bad step taken; reduce radius */
734:             tao->trust = nlsP->omega2 * PetscMin(norm_d, tao->trust);
735:           } else if (step < nlsP->nu3) {
736:             /*  Reasonable step was taken; leave radius alone */
737:             if (nlsP->omega3 < 1.0) {
738:               tao->trust = nlsP->omega3 * PetscMin(norm_d, tao->trust);
739:             } else if (nlsP->omega3 > 1.0) {
740:               tao->trust = PetscMax(nlsP->omega3 * norm_d, tao->trust);
741:             }
742:           } else if (step < nlsP->nu4) {
743:             /*  Full step taken; increase the radius */
744:             tao->trust = PetscMax(nlsP->omega4 * norm_d, tao->trust);
745:           } else {
746:             /*  More than full step taken; increase the radius */
747:             tao->trust = PetscMax(nlsP->omega5 * norm_d, tao->trust);
748:           }
749:         } else {
750:           /*  Newton step was not good; reduce the radius */
751:           tao->trust = nlsP->omega1 * PetscMin(norm_d, tao->trust);
752:         }
753:         break;

755:       case NLS_UPDATE_REDUCTION:
756:         if (stepType == NLS_NEWTON) {
757:           /*  Get predicted reduction */

759:           if (NLS_KSP_STCG == nlsP->ksp_type) {
760:             KSPSTCGGetObjFcn(tao->ksp,&prered);
761:           } else if (NLS_KSP_NASH == nlsP->ksp_type)  {
762:             KSPNASHGetObjFcn(tao->ksp,&prered);
763:           } else {
764:             KSPGLTRGetObjFcn(tao->ksp,&prered);
765:           }

767:           if (prered >= 0.0) {
768:             /*  The predicted reduction has the wrong sign.  This cannot */
769:             /*  happen in infinite precision arithmetic.  Step should */
770:             /*  be rejected! */
771:             tao->trust = nlsP->alpha1 * PetscMin(tao->trust, norm_d);
772:           } else {
773:             if (PetscIsInfOrNanReal(f_full)) {
774:               tao->trust = nlsP->alpha1 * PetscMin(tao->trust, norm_d);
775:             } else {
776:               /*  Compute and actual reduction */
777:               actred = fold - f_full;
778:               prered = -prered;
779:               if ((PetscAbsScalar(actred) <= nlsP->epsilon) &&
780:                   (PetscAbsScalar(prered) <= nlsP->epsilon)) {
781:                 kappa = 1.0;
782:               } else {
783:                 kappa = actred / prered;
784:               }

786:               /*  Accept of reject the step and update radius */
787:               if (kappa < nlsP->eta1) {
788:                 /*  Very bad step */
789:                 tao->trust = nlsP->alpha1 * PetscMin(tao->trust, norm_d);
790:               } else if (kappa < nlsP->eta2) {
791:                 /*  Marginal bad step */
792:                 tao->trust = nlsP->alpha2 * PetscMin(tao->trust, norm_d);
793:               } else if (kappa < nlsP->eta3) {
794:                 /*  Reasonable step */
795:                 if (nlsP->alpha3 < 1.0) {
796:                   tao->trust = nlsP->alpha3 * PetscMin(norm_d, tao->trust);
797:                 } else if (nlsP->alpha3 > 1.0) {
798:                   tao->trust = PetscMax(nlsP->alpha3 * norm_d, tao->trust);
799:                 }
800:               } else if (kappa < nlsP->eta4) {
801:                 /*  Good step */
802:                 tao->trust = PetscMax(nlsP->alpha4 * norm_d, tao->trust);
803:               } else {
804:                 /*  Very good step */
805:                 tao->trust = PetscMax(nlsP->alpha5 * norm_d, tao->trust);
806:               }
807:             }
808:           }
809:         } else {
810:           /*  Newton step was not good; reduce the radius */
811:           tao->trust = nlsP->alpha1 * PetscMin(norm_d, tao->trust);
812:         }
813:         break;

815:       default:
816:         if (stepType == NLS_NEWTON) {

818:           if (NLS_KSP_STCG == nlsP->ksp_type) {
819:               KSPSTCGGetObjFcn(tao->ksp,&prered);
820:           } else if (NLS_KSP_NASH == nlsP->ksp_type)  {
821:               KSPNASHGetObjFcn(tao->ksp,&prered);
822:           } else {
823:               KSPGLTRGetObjFcn(tao->ksp,&prered);
824:           }
825:           if (prered >= 0.0) {
826:             /*  The predicted reduction has the wrong sign.  This cannot */
827:             /*  happen in infinite precision arithmetic.  Step should */
828:             /*  be rejected! */
829:             tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
830:           } else {
831:             if (PetscIsInfOrNanReal(f_full)) {
832:               tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
833:             } else {
834:               actred = fold - f_full;
835:               prered = -prered;
836:               if ((PetscAbsScalar(actred) <= nlsP->epsilon) && (PetscAbsScalar(prered) <= nlsP->epsilon)) {
837:                 kappa = 1.0;
838:               } else {
839:                 kappa = actred / prered;
840:               }

842:               tau_1 = nlsP->theta * gdx / (nlsP->theta * gdx - (1.0 - nlsP->theta) * prered + actred);
843:               tau_2 = nlsP->theta * gdx / (nlsP->theta * gdx + (1.0 + nlsP->theta) * prered - actred);
844:               tau_min = PetscMin(tau_1, tau_2);
845:               tau_max = PetscMax(tau_1, tau_2);

847:               if (kappa >= 1.0 - nlsP->mu1) {
848:                 /*  Great agreement */
849:                 if (tau_max < 1.0) {
850:                   tao->trust = PetscMax(tao->trust, nlsP->gamma3 * norm_d);
851:                 } else if (tau_max > nlsP->gamma4) {
852:                   tao->trust = PetscMax(tao->trust, nlsP->gamma4 * norm_d);
853:                 } else {
854:                   tao->trust = PetscMax(tao->trust, tau_max * norm_d);
855:                 }
856:               } else if (kappa >= 1.0 - nlsP->mu2) {
857:                 /*  Good agreement */

859:                 if (tau_max < nlsP->gamma2) {
860:                   tao->trust = nlsP->gamma2 * PetscMin(tao->trust, norm_d);
861:                 } else if (tau_max > nlsP->gamma3) {
862:                   tao->trust = PetscMax(tao->trust, nlsP->gamma3 * norm_d);
863:                 } else if (tau_max < 1.0) {
864:                   tao->trust = tau_max * PetscMin(tao->trust, norm_d);
865:                 } else {
866:                   tao->trust = PetscMax(tao->trust, tau_max * norm_d);
867:                 }
868:               } else {
869:                 /*  Not good agreement */
870:                 if (tau_min > 1.0) {
871:                   tao->trust = nlsP->gamma2 * PetscMin(tao->trust, norm_d);
872:                 } else if (tau_max < nlsP->gamma1) {
873:                   tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
874:                 } else if ((tau_min < nlsP->gamma1) && (tau_max >= 1.0)) {
875:                   tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
876:                 } else if ((tau_1 >= nlsP->gamma1) && (tau_1 < 1.0) && ((tau_2 < nlsP->gamma1) || (tau_2 >= 1.0))) {
877:                   tao->trust = tau_1 * PetscMin(tao->trust, norm_d);
878:                 } else if ((tau_2 >= nlsP->gamma1) && (tau_2 < 1.0) && ((tau_1 < nlsP->gamma1) || (tau_2 >= 1.0))) {
879:                   tao->trust = tau_2 * PetscMin(tao->trust, norm_d);
880:                 } else {
881:                   tao->trust = tau_max * PetscMin(tao->trust, norm_d);
882:                 }
883:               }
884:             }
885:           }
886:         } else {
887:           /*  Newton step was not good; reduce the radius */
888:           tao->trust = nlsP->gamma1 * PetscMin(norm_d, tao->trust);
889:         }
890:         break;
891:       }

893:       /*  The radius may have been increased; modify if it is too large */
894:       tao->trust = PetscMin(tao->trust, nlsP->max_radius);
895:     }

897:     /*  Check for termination */
898:     VecNorm(tao->gradient, NORM_2, &gnorm);
899:     if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
900:     needH = 1;
901:     TaoMonitor(tao, iter, f, gnorm, 0.0, step, &reason);
902:   }
903:   return(0);
904: }

906: /* ---------------------------------------------------------- */
909: static PetscErrorCode TaoSetUp_NLS(Tao tao)
910: {
911:   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;

915:   if (!tao->gradient) {VecDuplicate(tao->solution,&tao->gradient);}
916:   if (!tao->stepdirection) {VecDuplicate(tao->solution,&tao->stepdirection);}
917:   if (!nlsP->W) {VecDuplicate(tao->solution,&nlsP->W);}
918:   if (!nlsP->D) {VecDuplicate(tao->solution,&nlsP->D);}
919:   if (!nlsP->Xold) {VecDuplicate(tao->solution,&nlsP->Xold);}
920:   if (!nlsP->Gold) {VecDuplicate(tao->solution,&nlsP->Gold);}
921:   nlsP->Diag = 0;
922:   nlsP->M = 0;
923:   return(0);
924: }

926: /*------------------------------------------------------------*/
929: static PetscErrorCode TaoDestroy_NLS(Tao tao)
930: {
931:   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;

935:   if (tao->setupcalled) {
936:     VecDestroy(&nlsP->D);
937:     VecDestroy(&nlsP->W);
938:     VecDestroy(&nlsP->Xold);
939:     VecDestroy(&nlsP->Gold);
940:   }
941:   VecDestroy(&nlsP->Diag);
942:   MatDestroy(&nlsP->M);
943:   PetscFree(tao->data);
944:   return(0);
945: }

947: /*------------------------------------------------------------*/
950: static PetscErrorCode TaoSetFromOptions_NLS(Tao tao)
951: {
952:   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;

956:   PetscOptionsHead("Newton line search method for unconstrained optimization");
957:   PetscOptionsEList("-tao_nls_ksp_type", "ksp type", "", NLS_KSP, NLS_KSP_TYPES, NLS_KSP[nlsP->ksp_type], &nlsP->ksp_type, 0);
958:   PetscOptionsEList("-tao_nls_pc_type", "pc type", "", NLS_PC, NLS_PC_TYPES, NLS_PC[nlsP->pc_type], &nlsP->pc_type, 0);
959:   PetscOptionsEList("-tao_nls_bfgs_scale_type", "bfgs scale type", "", BFGS_SCALE, BFGS_SCALE_TYPES, BFGS_SCALE[nlsP->bfgs_scale_type], &nlsP->bfgs_scale_type, 0);
960:   PetscOptionsEList("-tao_nls_init_type", "radius initialization type", "", NLS_INIT, NLS_INIT_TYPES, NLS_INIT[nlsP->init_type], &nlsP->init_type, 0);
961:   PetscOptionsEList("-tao_nls_update_type", "radius update type", "", NLS_UPDATE, NLS_UPDATE_TYPES, NLS_UPDATE[nlsP->update_type], &nlsP->update_type, 0);
962:  PetscOptionsReal("-tao_nls_sval", "perturbation starting value", "", nlsP->sval, &nlsP->sval, 0);
963:   PetscOptionsReal("-tao_nls_imin", "minimum initial perturbation", "", nlsP->imin, &nlsP->imin, 0);
964:   PetscOptionsReal("-tao_nls_imax", "maximum initial perturbation", "", nlsP->imax, &nlsP->imax, 0);
965:   PetscOptionsReal("-tao_nls_imfac", "initial merit factor", "", nlsP->imfac, &nlsP->imfac, 0);
966:   PetscOptionsReal("-tao_nls_pmin", "minimum perturbation", "", nlsP->pmin, &nlsP->pmin, 0);
967:   PetscOptionsReal("-tao_nls_pmax", "maximum perturbation", "", nlsP->pmax, &nlsP->pmax, 0);
968:   PetscOptionsReal("-tao_nls_pgfac", "growth factor", "", nlsP->pgfac, &nlsP->pgfac, 0);
969:   PetscOptionsReal("-tao_nls_psfac", "shrink factor", "", nlsP->psfac, &nlsP->psfac, 0);
970:   PetscOptionsReal("-tao_nls_pmgfac", "merit growth factor", "", nlsP->pmgfac, &nlsP->pmgfac, 0);
971:   PetscOptionsReal("-tao_nls_pmsfac", "merit shrink factor", "", nlsP->pmsfac, &nlsP->pmsfac, 0);
972:   PetscOptionsReal("-tao_nls_eta1", "poor steplength; reduce radius", "", nlsP->eta1, &nlsP->eta1, 0);
973:   PetscOptionsReal("-tao_nls_eta2", "reasonable steplength; leave radius alone", "", nlsP->eta2, &nlsP->eta2, 0);
974:   PetscOptionsReal("-tao_nls_eta3", "good steplength; increase radius", "", nlsP->eta3, &nlsP->eta3, 0);
975:   PetscOptionsReal("-tao_nls_eta4", "excellent steplength; greatly increase radius", "", nlsP->eta4, &nlsP->eta4, 0);
976:   PetscOptionsReal("-tao_nls_alpha1", "", "", nlsP->alpha1, &nlsP->alpha1, 0);
977:   PetscOptionsReal("-tao_nls_alpha2", "", "", nlsP->alpha2, &nlsP->alpha2, 0);
978:   PetscOptionsReal("-tao_nls_alpha3", "", "", nlsP->alpha3, &nlsP->alpha3, 0);
979:   PetscOptionsReal("-tao_nls_alpha4", "", "", nlsP->alpha4, &nlsP->alpha4, 0);
980:   PetscOptionsReal("-tao_nls_alpha5", "", "", nlsP->alpha5, &nlsP->alpha5, 0);
981:   PetscOptionsReal("-tao_nls_nu1", "poor steplength; reduce radius", "", nlsP->nu1, &nlsP->nu1, 0);
982:   PetscOptionsReal("-tao_nls_nu2", "reasonable steplength; leave radius alone", "", nlsP->nu2, &nlsP->nu2, 0);
983:   PetscOptionsReal("-tao_nls_nu3", "good steplength; increase radius", "", nlsP->nu3, &nlsP->nu3, 0);
984:   PetscOptionsReal("-tao_nls_nu4", "excellent steplength; greatly increase radius", "", nlsP->nu4, &nlsP->nu4, 0);
985:   PetscOptionsReal("-tao_nls_omega1", "", "", nlsP->omega1, &nlsP->omega1, 0);
986:   PetscOptionsReal("-tao_nls_omega2", "", "", nlsP->omega2, &nlsP->omega2, 0);
987:   PetscOptionsReal("-tao_nls_omega3", "", "", nlsP->omega3, &nlsP->omega3, 0);
988:   PetscOptionsReal("-tao_nls_omega4", "", "", nlsP->omega4, &nlsP->omega4, 0);
989:   PetscOptionsReal("-tao_nls_omega5", "", "", nlsP->omega5, &nlsP->omega5, 0);
990:   PetscOptionsReal("-tao_nls_mu1_i", "", "", nlsP->mu1_i, &nlsP->mu1_i, 0);
991:   PetscOptionsReal("-tao_nls_mu2_i", "", "", nlsP->mu2_i, &nlsP->mu2_i, 0);
992:   PetscOptionsReal("-tao_nls_gamma1_i", "", "", nlsP->gamma1_i, &nlsP->gamma1_i, 0);
993:   PetscOptionsReal("-tao_nls_gamma2_i", "", "", nlsP->gamma2_i, &nlsP->gamma2_i, 0);
994:   PetscOptionsReal("-tao_nls_gamma3_i", "", "", nlsP->gamma3_i, &nlsP->gamma3_i, 0);
995:   PetscOptionsReal("-tao_nls_gamma4_i", "", "", nlsP->gamma4_i, &nlsP->gamma4_i, 0);
996:   PetscOptionsReal("-tao_nls_theta_i", "", "", nlsP->theta_i, &nlsP->theta_i, 0);
997:   PetscOptionsReal("-tao_nls_mu1", "", "", nlsP->mu1, &nlsP->mu1, 0);
998:   PetscOptionsReal("-tao_nls_mu2", "", "", nlsP->mu2, &nlsP->mu2, 0);
999:   PetscOptionsReal("-tao_nls_gamma1", "", "", nlsP->gamma1, &nlsP->gamma1, 0);
1000:   PetscOptionsReal("-tao_nls_gamma2", "", "", nlsP->gamma2, &nlsP->gamma2, 0);
1001:   PetscOptionsReal("-tao_nls_gamma3", "", "", nlsP->gamma3, &nlsP->gamma3, 0);
1002:   PetscOptionsReal("-tao_nls_gamma4", "", "", nlsP->gamma4, &nlsP->gamma4, 0);
1003:   PetscOptionsReal("-tao_nls_theta", "", "", nlsP->theta, &nlsP->theta, 0);
1004:   PetscOptionsReal("-tao_nls_min_radius", "lower bound on initial radius", "", nlsP->min_radius, &nlsP->min_radius, 0);
1005:   PetscOptionsReal("-tao_nls_max_radius", "upper bound on radius", "", nlsP->max_radius, &nlsP->max_radius, 0);
1006:   PetscOptionsReal("-tao_nls_epsilon", "tolerance used when computing actual and predicted reduction", "", nlsP->epsilon, &nlsP->epsilon, 0);
1007:   PetscOptionsTail();
1008:   TaoLineSearchSetFromOptions(tao->linesearch);
1009:   KSPSetFromOptions(tao->ksp);
1010:   return(0);
1011: }


1014: /*------------------------------------------------------------*/
1017: static PetscErrorCode TaoView_NLS(Tao tao, PetscViewer viewer)
1018: {
1019:   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;
1020:   PetscInt       nrejects;
1021:   PetscBool      isascii;

1025:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
1026:   if (isascii) {
1027:     PetscViewerASCIIPushTab(viewer);
1028:     if (NLS_PC_BFGS == nlsP->pc_type && nlsP->M) {
1029:       MatLMVMGetRejects(nlsP->M,&nrejects);
1030:       PetscViewerASCIIPrintf(viewer, "Rejected matrix updates: %D\n",nrejects);
1031:     }
1032:     PetscViewerASCIIPrintf(viewer, "Newton steps: %D\n", nlsP->newt);
1033:     PetscViewerASCIIPrintf(viewer, "BFGS steps: %D\n", nlsP->bfgs);
1034:     PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %D\n", nlsP->sgrad);
1035:     PetscViewerASCIIPrintf(viewer, "Gradient steps: %D\n", nlsP->grad);

1037:     PetscViewerASCIIPrintf(viewer, "nls ksp atol: %D\n", nlsP->ksp_atol);
1038:     PetscViewerASCIIPrintf(viewer, "nls ksp rtol: %D\n", nlsP->ksp_rtol);
1039:     PetscViewerASCIIPrintf(viewer, "nls ksp ctol: %D\n", nlsP->ksp_ctol);
1040:     PetscViewerASCIIPrintf(viewer, "nls ksp negc: %D\n", nlsP->ksp_negc);
1041:     PetscViewerASCIIPrintf(viewer, "nls ksp dtol: %D\n", nlsP->ksp_dtol);
1042:     PetscViewerASCIIPrintf(viewer, "nls ksp iter: %D\n", nlsP->ksp_iter);
1043:     PetscViewerASCIIPrintf(viewer, "nls ksp othr: %D\n", nlsP->ksp_othr);
1044:     PetscViewerASCIIPopTab(viewer);
1045:   }
1046:   return(0);
1047: }

1049: /* ---------------------------------------------------------- */
1050: EXTERN_C_BEGIN
1053: PetscErrorCode TaoCreate_NLS(Tao tao)
1054: {
1055:   TAO_NLS        *nlsP;
1056:   const char     *morethuente_type = TAOLINESEARCH_MT;

1060:   PetscNewLog(tao,&nlsP);

1062:   tao->ops->setup = TaoSetUp_NLS;
1063:   tao->ops->solve = TaoSolve_NLS;
1064:   tao->ops->view = TaoView_NLS;
1065:   tao->ops->setfromoptions = TaoSetFromOptions_NLS;
1066:   tao->ops->destroy = TaoDestroy_NLS;

1068:   tao->max_it = 50;
1069: #if defined(PETSC_USE_REAL_SINGLE)
1070:   tao->fatol = 1e-5;
1071:   tao->frtol = 1e-5;
1072: #else
1073:   tao->fatol = 1e-10;
1074:   tao->frtol = 1e-10;
1075: #endif
1076:   tao->data = (void*)nlsP;
1077:   tao->trust0 = 100.0;

1079:   nlsP->sval   = 0.0;
1080:   nlsP->imin   = 1.0e-4;
1081:   nlsP->imax   = 1.0e+2;
1082:   nlsP->imfac  = 1.0e-1;

1084:   nlsP->pmin   = 1.0e-12;
1085:   nlsP->pmax   = 1.0e+2;
1086:   nlsP->pgfac  = 1.0e+1;
1087:   nlsP->psfac  = 4.0e-1;
1088:   nlsP->pmgfac = 1.0e-1;
1089:   nlsP->pmsfac = 1.0e-1;

1091:   /*  Default values for trust-region radius update based on steplength */
1092:   nlsP->nu1 = 0.25;
1093:   nlsP->nu2 = 0.50;
1094:   nlsP->nu3 = 1.00;
1095:   nlsP->nu4 = 1.25;

1097:   nlsP->omega1 = 0.25;
1098:   nlsP->omega2 = 0.50;
1099:   nlsP->omega3 = 1.00;
1100:   nlsP->omega4 = 2.00;
1101:   nlsP->omega5 = 4.00;

1103:   /*  Default values for trust-region radius update based on reduction */
1104:   nlsP->eta1 = 1.0e-4;
1105:   nlsP->eta2 = 0.25;
1106:   nlsP->eta3 = 0.50;
1107:   nlsP->eta4 = 0.90;

1109:   nlsP->alpha1 = 0.25;
1110:   nlsP->alpha2 = 0.50;
1111:   nlsP->alpha3 = 1.00;
1112:   nlsP->alpha4 = 2.00;
1113:   nlsP->alpha5 = 4.00;

1115:   /*  Default values for trust-region radius update based on interpolation */
1116:   nlsP->mu1 = 0.10;
1117:   nlsP->mu2 = 0.50;

1119:   nlsP->gamma1 = 0.25;
1120:   nlsP->gamma2 = 0.50;
1121:   nlsP->gamma3 = 2.00;
1122:   nlsP->gamma4 = 4.00;

1124:   nlsP->theta = 0.05;

1126:   /*  Default values for trust region initialization based on interpolation */
1127:   nlsP->mu1_i = 0.35;
1128:   nlsP->mu2_i = 0.50;

1130:   nlsP->gamma1_i = 0.0625;
1131:   nlsP->gamma2_i = 0.5;
1132:   nlsP->gamma3_i = 2.0;
1133:   nlsP->gamma4_i = 5.0;

1135:   nlsP->theta_i = 0.25;

1137:   /*  Remaining parameters */
1138:   nlsP->min_radius = 1.0e-10;
1139:   nlsP->max_radius = 1.0e10;
1140:   nlsP->epsilon = 1.0e-6;

1142:   nlsP->ksp_type        = NLS_KSP_STCG;
1143:   nlsP->pc_type         = NLS_PC_BFGS;
1144:   nlsP->bfgs_scale_type = BFGS_SCALE_PHESS;
1145:   nlsP->init_type       = NLS_INIT_INTERPOLATION;
1146:   nlsP->update_type     = NLS_UPDATE_STEP;

1148:   TaoLineSearchCreate(((PetscObject)tao)->comm,&tao->linesearch);
1149:   TaoLineSearchSetType(tao->linesearch,morethuente_type);
1150:   TaoLineSearchUseTaoRoutines(tao->linesearch,tao);

1152:   /*  Set linear solver to default for symmetric matrices */
1153:   KSPCreate(((PetscObject)tao)->comm,&tao->ksp);
1154:   return(0);
1155: }
1156: EXTERN_C_END

1160: static PetscErrorCode MatLMVMSolveShell(PC pc, Vec b, Vec x)
1161: {
1163:   Mat            M;

1169:   PCShellGetContext(pc,(void**)&M);
1170:   MatLMVMSolve(M, b, x);
1171:   return(0);
1172: }