Date: 2022-03-04T17:39:49+00:00

Actual source code: nls.c

      1: #include <petsctaolinesearch.h>
      2: #include <../src/tao/unconstrained/impls/nls/nlsimpl.h>

      4: #include <petscksp.h>

      6: #define NLS_INIT_CONSTANT         0
      7: #define NLS_INIT_DIRECTION        1
      8: #define NLS_INIT_INTERPOLATION    2
      9: #define NLS_INIT_TYPES            3

     11: #define NLS_UPDATE_STEP           0
     12: #define NLS_UPDATE_REDUCTION      1
     13: #define NLS_UPDATE_INTERPOLATION  2
     14: #define NLS_UPDATE_TYPES          3

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

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

     20: /*
     21:  Implements Newton's Method with a line search approach for solving
     22:  unconstrained minimization problems.  A More'-Thuente line search
     23:  is used to guarantee that the bfgs preconditioner remains positive
     24:  definite.

     26:  The method can shift the Hessian matrix.  The shifting procedure is
     27:  adapted from the PATH algorithm for solving complementarity
     28:  problems.

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

     34: #define NLS_NEWTON              0
     35: #define NLS_BFGS                1
     36: #define NLS_GRADIENT            2

     38: static PetscErrorCode TaoSolve_NLS(Tao tao)
     39: {
     40:   PetscErrorCode               ierr;
     41:   TAO_NLS                      *nlsP = (TAO_NLS *)tao->data;
     42:   KSPType                      ksp_type;
     43:   PetscBool                    is_nash,is_stcg,is_gltr,is_bfgs,is_jacobi,is_symmetric,sym_set;
     44:   KSPConvergedReason           ksp_reason;
     45:   PC                           pc;
     46:   TaoLineSearchConvergedReason ls_reason;

     48:   PetscReal                    fmin, ftrial, f_full, prered, actred, kappa, sigma;
     49:   PetscReal                    tau, tau_1, tau_2, tau_max, tau_min, max_radius;
     50:   PetscReal                    f, fold, gdx, gnorm, pert;
     51:   PetscReal                    step = 1.0;
     52:   PetscReal                    norm_d = 0.0, e_min;

     54:   PetscInt                     stepType;
     55:   PetscInt                     bfgsUpdates = 0;
     56:   PetscInt                     n,N,kspits;
     57:   PetscInt                     needH = 1;

     59:   PetscInt                     i_max = 5;
     60:   PetscInt                     j_max = 1;
     61:   PetscInt                     i, j;

     64:   if (tao->XL || tao->XU || tao->ops->computebounds) {
     65:     PetscInfo(tao,"WARNING: Variable bounds have been set but will be ignored by nls algorithm\n");
     66:   }

     68:   /* Initialized variables */
     69:   pert = nlsP->sval;

     71:   /* Number of times ksp stopped because of these reasons */
     72:   nlsP->ksp_atol = 0;
     73:   nlsP->ksp_rtol = 0;
     74:   nlsP->ksp_dtol = 0;
     75:   nlsP->ksp_ctol = 0;
     76:   nlsP->ksp_negc = 0;
     77:   nlsP->ksp_iter = 0;
     78:   nlsP->ksp_othr = 0;

     80:   /* Initialize trust-region radius when using nash, stcg, or gltr
     81:      Command automatically ignored for other methods
     82:      Will be reset during the first iteration
     83:   */
     84:   KSPGetType(tao->ksp,&ksp_type);
     85:   PetscStrcmp(ksp_type,KSPNASH,&is_nash);
     86:   PetscStrcmp(ksp_type,KSPSTCG,&is_stcg);
     87:   PetscStrcmp(ksp_type,KSPGLTR,&is_gltr);

     89:   KSPCGSetRadius(tao->ksp,nlsP->max_radius);

     91:   if (is_nash || is_stcg || is_gltr) {
     92:     if (tao->trust0 < 0.0) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ARG_OUTOFRANGE,"Initial radius negative");
     93:     tao->trust = tao->trust0;
     94:     tao->trust = PetscMax(tao->trust, nlsP->min_radius);
     95:     tao->trust = PetscMin(tao->trust, nlsP->max_radius);
     96:   }

     98:   /* Check convergence criteria */
     99:   TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient);
    100:   TaoGradientNorm(tao, tao->gradient,NORM_2,&gnorm);
    101:   if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN");

    103:   tao->reason = TAO_CONTINUE_ITERATING;
    104:   TaoLogConvergenceHistory(tao,f,gnorm,0.0,tao->ksp_its);
    105:   TaoMonitor(tao,tao->niter,f,gnorm,0.0,step);
    106:   (*tao->ops->convergencetest)(tao,tao->cnvP);
    107:   if (tao->reason != TAO_CONTINUE_ITERATING) return(0);

    109:   /* Allocate the vectors needed for the BFGS approximation */
    110:   KSPGetPC(tao->ksp, &pc);
    111:   PetscObjectTypeCompare((PetscObject)pc, PCLMVM, &is_bfgs);
    112:   PetscObjectTypeCompare((PetscObject)pc, PCJACOBI, &is_jacobi);
    113:   if (is_bfgs) {
    114:     nlsP->bfgs_pre = pc;
    115:     PCLMVMGetMatLMVM(nlsP->bfgs_pre, &nlsP->M);
    116:     VecGetLocalSize(tao->solution, &n);
    117:     VecGetSize(tao->solution, &N);
    118:     MatSetSizes(nlsP->M, n, n, N, N);
    119:     MatLMVMAllocate(nlsP->M, tao->solution, tao->gradient);
    120:     MatIsSymmetricKnown(nlsP->M, &sym_set, &is_symmetric);
    121:     if (!sym_set || !is_symmetric) SETERRQ(PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "LMVM matrix in the LMVM preconditioner must be symmetric.");
    122:   } else if (is_jacobi) {
    123:     PCJacobiSetUseAbs(pc,PETSC_TRUE);
    124:   }

    126:   /* Initialize trust-region radius.  The initialization is only performed
    127:      when we are using Nash, Steihaug-Toint or the Generalized Lanczos method. */
    128:   if (is_nash || is_stcg || is_gltr) {
    129:     switch (nlsP->init_type) {
    130:     case NLS_INIT_CONSTANT:
    131:       /* Use the initial radius specified */
    132:       break;

    134:     case NLS_INIT_INTERPOLATION:
    135:       /* Use the initial radius specified */
    136:       max_radius = 0.0;

    138:       for (j = 0; j < j_max; ++j) {
    139:         fmin = f;
    140:         sigma = 0.0;

    142:         if (needH) {
    143:           TaoComputeHessian(tao, tao->solution,tao->hessian,tao->hessian_pre);
    144:           needH = 0;
    145:         }

    147:         for (i = 0; i < i_max; ++i) {
    148:           VecCopy(tao->solution,nlsP->W);
    149:           VecAXPY(nlsP->W,-tao->trust/gnorm,tao->gradient);
    150:           TaoComputeObjective(tao, nlsP->W, &ftrial);
    151:           if (PetscIsInfOrNanReal(ftrial)) {
    152:             tau = nlsP->gamma1_i;
    153:           } else {
    154:             if (ftrial < fmin) {
    155:               fmin = ftrial;
    156:               sigma = -tao->trust / gnorm;
    157:             }

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

    162:             prered = tao->trust * (gnorm - 0.5 * tao->trust * prered / (gnorm * gnorm));
    163:             actred = f - ftrial;
    164:             if ((PetscAbsScalar(actred) <= nlsP->epsilon) && (PetscAbsScalar(prered) <= nlsP->epsilon)) {
    165:               kappa = 1.0;
    166:             } else {
    167:               kappa = actred / prered;
    168:             }

    170:             tau_1 = nlsP->theta_i * gnorm * tao->trust / (nlsP->theta_i * gnorm * tao->trust + (1.0 - nlsP->theta_i) * prered - actred);
    171:             tau_2 = nlsP->theta_i * gnorm * tao->trust / (nlsP->theta_i * gnorm * tao->trust - (1.0 + nlsP->theta_i) * prered + actred);
    172:             tau_min = PetscMin(tau_1, tau_2);
    173:             tau_max = PetscMax(tau_1, tau_2);

    175:             if (PetscAbsScalar(kappa - (PetscReal)1.0) <= nlsP->mu1_i) {
    176:               /* Great agreement */
    177:               max_radius = PetscMax(max_radius, tao->trust);

    179:               if (tau_max < 1.0) {
    180:                 tau = nlsP->gamma3_i;
    181:               } else if (tau_max > nlsP->gamma4_i) {
    182:                 tau = nlsP->gamma4_i;
    183:               } else if (tau_1 >= 1.0 && tau_1 <= nlsP->gamma4_i && tau_2 < 1.0) {
    184:                 tau = tau_1;
    185:               } else if (tau_2 >= 1.0 && tau_2 <= nlsP->gamma4_i && tau_1 < 1.0) {
    186:                 tau = tau_2;
    187:               } else {
    188:                 tau = tau_max;
    189:               }
    190:             } else if (PetscAbsScalar(kappa - (PetscReal)1.0) <= nlsP->mu2_i) {
    191:               /* Good agreement */
    192:               max_radius = PetscMax(max_radius, tao->trust);

    194:               if (tau_max < nlsP->gamma2_i) {
    195:                 tau = nlsP->gamma2_i;
    196:               } else if (tau_max > nlsP->gamma3_i) {
    197:                 tau = nlsP->gamma3_i;
    198:               } else {
    199:                 tau = tau_max;
    200:               }
    201:             } else {
    202:               /* Not good agreement */
    203:               if (tau_min > 1.0) {
    204:                 tau = nlsP->gamma2_i;
    205:               } else if (tau_max < nlsP->gamma1_i) {
    206:                 tau = nlsP->gamma1_i;
    207:               } else if ((tau_min < nlsP->gamma1_i) && (tau_max >= 1.0)) {
    208:                 tau = nlsP->gamma1_i;
    209:               } else if ((tau_1 >= nlsP->gamma1_i) && (tau_1 < 1.0) && ((tau_2 < nlsP->gamma1_i) || (tau_2 >= 1.0))) {
    210:                 tau = tau_1;
    211:               } else if ((tau_2 >= nlsP->gamma1_i) && (tau_2 < 1.0) && ((tau_1 < nlsP->gamma1_i) || (tau_2 >= 1.0))) {
    212:                 tau = tau_2;
    213:               } else {
    214:                 tau = tau_max;
    215:               }
    216:             }
    217:           }
    218:           tao->trust = tau * tao->trust;
    219:         }

    221:         if (fmin < f) {
    222:           f = fmin;
    223:           VecAXPY(tao->solution,sigma,tao->gradient);
    224:           TaoComputeGradient(tao,tao->solution,tao->gradient);

    226:           TaoGradientNorm(tao, tao->gradient,NORM_2,&gnorm);
    227:           if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute gradient generated Inf or NaN");
    228:           needH = 1;

    230:           TaoLogConvergenceHistory(tao,f,gnorm,0.0,tao->ksp_its);
    231:           TaoMonitor(tao,tao->niter,f,gnorm,0.0,step);
    232:           (*tao->ops->convergencetest)(tao,tao->cnvP);
    233:           if (tao->reason != TAO_CONTINUE_ITERATING) return(0);
    234:         }
    235:       }
    236:       tao->trust = PetscMax(tao->trust, max_radius);

    238:       /* Modify the radius if it is too large or small */
    239:       tao->trust = PetscMax(tao->trust, nlsP->min_radius);
    240:       tao->trust = PetscMin(tao->trust, nlsP->max_radius);
    241:       break;

    243:     default:
    244:       /* Norm of the first direction will initialize radius */
    245:       tao->trust = 0.0;
    246:       break;
    247:     }
    248:   }

    250:   /* Set counter for gradient/reset steps*/
    251:   nlsP->newt = 0;
    252:   nlsP->bfgs = 0;
    253:   nlsP->grad = 0;

    255:   /* Have not converged; continue with Newton method */
    256:   while (tao->reason == TAO_CONTINUE_ITERATING) {
    257:     /* Call general purpose update function */
    258:     if (tao->ops->update) {
    259:       (*tao->ops->update)(tao, tao->niter, tao->user_update);
    260:     }
    261:     ++tao->niter;
    262:     tao->ksp_its=0;

    264:     /* Compute the Hessian */
    265:     if (needH) {
    266:       TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);
    267:     }

    269:     /* Shift the Hessian matrix */
    270:     if (pert > 0) {
    271:       MatShift(tao->hessian, pert);
    272:       if (tao->hessian != tao->hessian_pre) {
    273:         MatShift(tao->hessian_pre, pert);
    274:       }
    275:     }

    277:     if (nlsP->bfgs_pre) {
    278:       MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);
    279:       ++bfgsUpdates;
    280:     }

    282:     /* Solve the Newton system of equations */
    283:     KSPSetOperators(tao->ksp,tao->hessian,tao->hessian_pre);
    284:     if (is_nash || is_stcg || is_gltr) {
    285:       KSPCGSetRadius(tao->ksp,nlsP->max_radius);
    286:       KSPSolve(tao->ksp, tao->gradient, nlsP->D);
    287:       KSPGetIterationNumber(tao->ksp,&kspits);
    288:       tao->ksp_its+=kspits;
    289:       tao->ksp_tot_its+=kspits;
    290:       KSPCGGetNormD(tao->ksp,&norm_d);

    292:       if (0.0 == tao->trust) {
    293:         /* Radius was uninitialized; use the norm of the direction */
    294:         if (norm_d > 0.0) {
    295:           tao->trust = norm_d;

    297:           /* Modify the radius if it is too large or small */
    298:           tao->trust = PetscMax(tao->trust, nlsP->min_radius);
    299:           tao->trust = PetscMin(tao->trust, nlsP->max_radius);
    300:         } else {
    301:           /* The direction was bad; set radius to default value and re-solve
    302:              the trust-region subproblem to get a direction */
    303:           tao->trust = tao->trust0;

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

    309:           KSPCGSetRadius(tao->ksp,nlsP->max_radius);
    310:           KSPSolve(tao->ksp, tao->gradient, nlsP->D);
    311:           KSPGetIterationNumber(tao->ksp,&kspits);
    312:           tao->ksp_its+=kspits;
    313:           tao->ksp_tot_its+=kspits;
    314:           KSPCGGetNormD(tao->ksp,&norm_d);

    316:           if (norm_d == 0.0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB, "Initial direction zero");
    317:         }
    318:       }
    319:     } else {
    320:       KSPSolve(tao->ksp, tao->gradient, nlsP->D);
    321:       KSPGetIterationNumber(tao->ksp, &kspits);
    322:       tao->ksp_its += kspits;
    323:       tao->ksp_tot_its+=kspits;
    324:     }
    325:     VecScale(nlsP->D, -1.0);
    326:     KSPGetConvergedReason(tao->ksp, &ksp_reason);
    327:     if ((KSP_DIVERGED_INDEFINITE_PC == ksp_reason) &&  (nlsP->bfgs_pre)) {
    328:       /* Preconditioner is numerically indefinite; reset the
    329:          approximate if using BFGS preconditioning. */
    330:       MatLMVMReset(nlsP->M, PETSC_FALSE);
    331:       MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);
    332:       bfgsUpdates = 1;
    333:     }

    335:     if (KSP_CONVERGED_ATOL == ksp_reason) {
    336:       ++nlsP->ksp_atol;
    337:     } else if (KSP_CONVERGED_RTOL == ksp_reason) {
    338:       ++nlsP->ksp_rtol;
    339:     } else if (KSP_CONVERGED_CG_CONSTRAINED == ksp_reason) {
    340:       ++nlsP->ksp_ctol;
    341:     } else if (KSP_CONVERGED_CG_NEG_CURVE == ksp_reason) {
    342:       ++nlsP->ksp_negc;
    343:     } else if (KSP_DIVERGED_DTOL == ksp_reason) {
    344:       ++nlsP->ksp_dtol;
    345:     } else if (KSP_DIVERGED_ITS == ksp_reason) {
    346:       ++nlsP->ksp_iter;
    347:     } else {
    348:       ++nlsP->ksp_othr;
    349:     }

    351:     /* Check for success (descent direction) */
    352:     VecDot(nlsP->D, tao->gradient, &gdx);
    353:     if ((gdx >= 0.0) || PetscIsInfOrNanReal(gdx)) {
    354:       /* Newton step is not descent or direction produced Inf or NaN
    355:          Update the perturbation for next time */
    356:       if (pert <= 0.0) {
    357:         /* Initialize the perturbation */
    358:         pert = PetscMin(nlsP->imax, PetscMax(nlsP->imin, nlsP->imfac * gnorm));
    359:         if (is_gltr) {
    360:           KSPGLTRGetMinEig(tao->ksp,&e_min);
    361:           pert = PetscMax(pert, -e_min);
    362:         }
    363:       } else {
    364:         /* Increase the perturbation */
    365:         pert = PetscMin(nlsP->pmax, PetscMax(nlsP->pgfac * pert, nlsP->pmgfac * gnorm));
    366:       }

    368:       if (!nlsP->bfgs_pre) {
    369:         /* We don't have the bfgs matrix around and updated
    370:            Must use gradient direction in this case */
    371:         VecCopy(tao->gradient, nlsP->D);
    372:         VecScale(nlsP->D, -1.0);
    373:         ++nlsP->grad;
    374:         stepType = NLS_GRADIENT;
    375:       } else {
    376:         /* Attempt to use the BFGS direction */
    377:         MatSolve(nlsP->M, tao->gradient, nlsP->D);
    378:         VecScale(nlsP->D, -1.0);

    380:         /* Check for success (descent direction) */
    381:         VecDot(tao->gradient, nlsP->D, &gdx);
    382:         if ((gdx >= 0) || PetscIsInfOrNanReal(gdx)) {
    383:           /* BFGS direction is not descent or direction produced not a number
    384:              We can assert bfgsUpdates > 1 in this case because
    385:              the first solve produces the scaled gradient direction,
    386:              which is guaranteed to be descent */

    388:           /* Use steepest descent direction (scaled) */
    389:           MatLMVMReset(nlsP->M, PETSC_FALSE);
    390:           MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);
    391:           MatSolve(nlsP->M, tao->gradient, nlsP->D);
    392:           VecScale(nlsP->D, -1.0);

    394:           bfgsUpdates = 1;
    395:           ++nlsP->grad;
    396:           stepType = NLS_GRADIENT;
    397:         } else {
    398:           MatLMVMGetUpdateCount(nlsP->M, &bfgsUpdates);
    399:           if (1 == bfgsUpdates) {
    400:             /* The first BFGS direction is always the scaled gradient */
    401:             ++nlsP->grad;
    402:             stepType = NLS_GRADIENT;
    403:           } else {
    404:             ++nlsP->bfgs;
    405:             stepType = NLS_BFGS;
    406:           }
    407:         }
    408:       }
    409:     } else {
    410:       /* Computed Newton step is descent */
    411:       switch (ksp_reason) {
    412:       case KSP_DIVERGED_NANORINF:
    413:       case KSP_DIVERGED_BREAKDOWN:
    414:       case KSP_DIVERGED_INDEFINITE_MAT:
    415:       case KSP_DIVERGED_INDEFINITE_PC:
    416:       case KSP_CONVERGED_CG_NEG_CURVE:
    417:         /* Matrix or preconditioner is indefinite; increase perturbation */
    418:         if (pert <= 0.0) {
    419:           /* Initialize the perturbation */
    420:           pert = PetscMin(nlsP->imax, PetscMax(nlsP->imin, nlsP->imfac * gnorm));
    421:           if (is_gltr) {
    422:             KSPGLTRGetMinEig(tao->ksp, &e_min);
    423:             pert = PetscMax(pert, -e_min);
    424:           }
    425:         } else {
    426:           /* Increase the perturbation */
    427:           pert = PetscMin(nlsP->pmax, PetscMax(nlsP->pgfac * pert, nlsP->pmgfac * gnorm));
    428:         }
    429:         break;

    431:       default:
    432:         /* Newton step computation is good; decrease perturbation */
    433:         pert = PetscMin(nlsP->psfac * pert, nlsP->pmsfac * gnorm);
    434:         if (pert < nlsP->pmin) {
    435:           pert = 0.0;
    436:         }
    437:         break;
    438:       }

    440:       ++nlsP->newt;
    441:       stepType = NLS_NEWTON;
    442:     }

    444:     /* Perform the linesearch */
    445:     fold = f;
    446:     VecCopy(tao->solution, nlsP->Xold);
    447:     VecCopy(tao->gradient, nlsP->Gold);

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

    452:     while (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER && stepType != NLS_GRADIENT) {      /* Linesearch failed */
    453:       f = fold;
    454:       VecCopy(nlsP->Xold, tao->solution);
    455:       VecCopy(nlsP->Gold, tao->gradient);

    457:       switch(stepType) {
    458:       case NLS_NEWTON:
    459:         /* Failed to obtain acceptable iterate with Newton 1step
    460:            Update the perturbation for next time */
    461:         if (pert <= 0.0) {
    462:           /* Initialize the perturbation */
    463:           pert = PetscMin(nlsP->imax, PetscMax(nlsP->imin, nlsP->imfac * gnorm));
    464:           if (is_gltr) {
    465:             KSPGLTRGetMinEig(tao->ksp,&e_min);
    466:             pert = PetscMax(pert, -e_min);
    467:           }
    468:         } else {
    469:           /* Increase the perturbation */
    470:           pert = PetscMin(nlsP->pmax, PetscMax(nlsP->pgfac * pert, nlsP->pmgfac * gnorm));
    471:         }

    473:         if (!nlsP->bfgs_pre) {
    474:           /* We don't have the bfgs matrix around and being updated
    475:              Must use gradient direction in this case */
    476:           VecCopy(tao->gradient, nlsP->D);
    477:           ++nlsP->grad;
    478:           stepType = NLS_GRADIENT;
    479:         } else {
    480:           /* Attempt to use the BFGS direction */
    481:           MatSolve(nlsP->M, tao->gradient, nlsP->D);
    482:           /* Check for success (descent direction) */
    483:           VecDot(tao->solution, nlsP->D, &gdx);
    484:           if ((gdx <= 0) || PetscIsInfOrNanReal(gdx)) {
    485:             /* BFGS direction is not descent or direction produced not a number
    486:                We can assert bfgsUpdates > 1 in this case
    487:                Use steepest descent direction (scaled) */
    488:             MatLMVMReset(nlsP->M, PETSC_FALSE);
    489:             MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);
    490:             MatSolve(nlsP->M, tao->gradient, nlsP->D);

    492:             bfgsUpdates = 1;
    493:             ++nlsP->grad;
    494:             stepType = NLS_GRADIENT;
    495:           } else {
    496:             if (1 == bfgsUpdates) {
    497:               /* The first BFGS direction is always the scaled gradient */
    498:               ++nlsP->grad;
    499:               stepType = NLS_GRADIENT;
    500:             } else {
    501:               ++nlsP->bfgs;
    502:               stepType = NLS_BFGS;
    503:             }
    504:           }
    505:         }
    506:         break;

    508:       case NLS_BFGS:
    509:         /* Can only enter if pc_type == NLS_PC_BFGS
    510:            Failed to obtain acceptable iterate with BFGS step
    511:            Attempt to use the scaled gradient direction */
    512:         MatLMVMReset(nlsP->M, PETSC_FALSE);
    513:         MatLMVMUpdate(nlsP->M, tao->solution, tao->gradient);
    514:         MatSolve(nlsP->M, tao->gradient, nlsP->D);

    516:         bfgsUpdates = 1;
    517:         ++nlsP->grad;
    518:         stepType = NLS_GRADIENT;
    519:         break;
    520:       }
    521:       VecScale(nlsP->D, -1.0);

    523:       TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, nlsP->D, &step, &ls_reason);
    524:       TaoLineSearchGetFullStepObjective(tao->linesearch, &f_full);
    525:       TaoAddLineSearchCounts(tao);
    526:     }

    528:     if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) {
    529:       /* Failed to find an improving point */
    530:       f = fold;
    531:       VecCopy(nlsP->Xold, tao->solution);
    532:       VecCopy(nlsP->Gold, tao->gradient);
    533:       step = 0.0;
    534:       tao->reason = TAO_DIVERGED_LS_FAILURE;
    535:       break;
    536:     }

    538:     /* Update trust region radius */
    539:     if (is_nash || is_stcg || is_gltr) {
    540:       switch(nlsP->update_type) {
    541:       case NLS_UPDATE_STEP:
    542:         if (stepType == NLS_NEWTON) {
    543:           if (step < nlsP->nu1) {
    544:             /* Very bad step taken; reduce radius */
    545:             tao->trust = nlsP->omega1 * PetscMin(norm_d, tao->trust);
    546:           } else if (step < nlsP->nu2) {
    547:             /* Reasonably bad step taken; reduce radius */
    548:             tao->trust = nlsP->omega2 * PetscMin(norm_d, tao->trust);
    549:           } else if (step < nlsP->nu3) {
    550:             /*  Reasonable step was taken; leave radius alone */
    551:             if (nlsP->omega3 < 1.0) {
    552:               tao->trust = nlsP->omega3 * PetscMin(norm_d, tao->trust);
    553:             } else if (nlsP->omega3 > 1.0) {
    554:               tao->trust = PetscMax(nlsP->omega3 * norm_d, tao->trust);
    555:             }
    556:           } else if (step < nlsP->nu4) {
    557:             /*  Full step taken; increase the radius */
    558:             tao->trust = PetscMax(nlsP->omega4 * norm_d, tao->trust);
    559:           } else {
    560:             /*  More than full step taken; increase the radius */
    561:             tao->trust = PetscMax(nlsP->omega5 * norm_d, tao->trust);
    562:           }
    563:         } else {
    564:           /*  Newton step was not good; reduce the radius */
    565:           tao->trust = nlsP->omega1 * PetscMin(norm_d, tao->trust);
    566:         }
    567:         break;

    569:       case NLS_UPDATE_REDUCTION:
    570:         if (stepType == NLS_NEWTON) {
    571:           /*  Get predicted reduction */

    573:           KSPCGGetObjFcn(tao->ksp,&prered);
    574:           if (prered >= 0.0) {
    575:             /*  The predicted reduction has the wrong sign.  This cannot */
    576:             /*  happen in infinite precision arithmetic.  Step should */
    577:             /*  be rejected! */
    578:             tao->trust = nlsP->alpha1 * PetscMin(tao->trust, norm_d);
    579:           } else {
    580:             if (PetscIsInfOrNanReal(f_full)) {
    581:               tao->trust = nlsP->alpha1 * PetscMin(tao->trust, norm_d);
    582:             } else {
    583:               /*  Compute and actual reduction */
    584:               actred = fold - f_full;
    585:               prered = -prered;
    586:               if ((PetscAbsScalar(actred) <= nlsP->epsilon) &&
    587:                   (PetscAbsScalar(prered) <= nlsP->epsilon)) {
    588:                 kappa = 1.0;
    589:               } else {
    590:                 kappa = actred / prered;
    591:               }

    593:               /*  Accept of reject the step and update radius */
    594:               if (kappa < nlsP->eta1) {
    595:                 /*  Very bad step */
    596:                 tao->trust = nlsP->alpha1 * PetscMin(tao->trust, norm_d);
    597:               } else if (kappa < nlsP->eta2) {
    598:                 /*  Marginal bad step */
    599:                 tao->trust = nlsP->alpha2 * PetscMin(tao->trust, norm_d);
    600:               } else if (kappa < nlsP->eta3) {
    601:                 /*  Reasonable step */
    602:                 if (nlsP->alpha3 < 1.0) {
    603:                   tao->trust = nlsP->alpha3 * PetscMin(norm_d, tao->trust);
    604:                 } else if (nlsP->alpha3 > 1.0) {
    605:                   tao->trust = PetscMax(nlsP->alpha3 * norm_d, tao->trust);
    606:                 }
    607:               } else if (kappa < nlsP->eta4) {
    608:                 /*  Good step */
    609:                 tao->trust = PetscMax(nlsP->alpha4 * norm_d, tao->trust);
    610:               } else {
    611:                 /*  Very good step */
    612:                 tao->trust = PetscMax(nlsP->alpha5 * norm_d, tao->trust);
    613:               }
    614:             }
    615:           }
    616:         } else {
    617:           /*  Newton step was not good; reduce the radius */
    618:           tao->trust = nlsP->alpha1 * PetscMin(norm_d, tao->trust);
    619:         }
    620:         break;

    622:       default:
    623:         if (stepType == NLS_NEWTON) {
    624:           KSPCGGetObjFcn(tao->ksp,&prered);
    625:           if (prered >= 0.0) {
    626:             /*  The predicted reduction has the wrong sign.  This cannot */
    627:             /*  happen in infinite precision arithmetic.  Step should */
    628:             /*  be rejected! */
    629:             tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
    630:           } else {
    631:             if (PetscIsInfOrNanReal(f_full)) {
    632:               tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
    633:             } else {
    634:               actred = fold - f_full;
    635:               prered = -prered;
    636:               if ((PetscAbsScalar(actred) <= nlsP->epsilon) && (PetscAbsScalar(prered) <= nlsP->epsilon)) {
    637:                 kappa = 1.0;
    638:               } else {
    639:                 kappa = actred / prered;
    640:               }

    642:               tau_1 = nlsP->theta * gdx / (nlsP->theta * gdx - (1.0 - nlsP->theta) * prered + actred);
    643:               tau_2 = nlsP->theta * gdx / (nlsP->theta * gdx + (1.0 + nlsP->theta) * prered - actred);
    644:               tau_min = PetscMin(tau_1, tau_2);
    645:               tau_max = PetscMax(tau_1, tau_2);

    647:               if (kappa >= 1.0 - nlsP->mu1) {
    648:                 /*  Great agreement */
    649:                 if (tau_max < 1.0) {
    650:                   tao->trust = PetscMax(tao->trust, nlsP->gamma3 * norm_d);
    651:                 } else if (tau_max > nlsP->gamma4) {
    652:                   tao->trust = PetscMax(tao->trust, nlsP->gamma4 * norm_d);
    653:                 } else {
    654:                   tao->trust = PetscMax(tao->trust, tau_max * norm_d);
    655:                 }
    656:               } else if (kappa >= 1.0 - nlsP->mu2) {
    657:                 /*  Good agreement */

    659:                 if (tau_max < nlsP->gamma2) {
    660:                   tao->trust = nlsP->gamma2 * PetscMin(tao->trust, norm_d);
    661:                 } else if (tau_max > nlsP->gamma3) {
    662:                   tao->trust = PetscMax(tao->trust, nlsP->gamma3 * norm_d);
    663:                 } else if (tau_max < 1.0) {
    664:                   tao->trust = tau_max * PetscMin(tao->trust, norm_d);
    665:                 } else {
    666:                   tao->trust = PetscMax(tao->trust, tau_max * norm_d);
    667:                 }
    668:               } else {
    669:                 /*  Not good agreement */
    670:                 if (tau_min > 1.0) {
    671:                   tao->trust = nlsP->gamma2 * PetscMin(tao->trust, norm_d);
    672:                 } else if (tau_max < nlsP->gamma1) {
    673:                   tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
    674:                 } else if ((tau_min < nlsP->gamma1) && (tau_max >= 1.0)) {
    675:                   tao->trust = nlsP->gamma1 * PetscMin(tao->trust, norm_d);
    676:                 } else if ((tau_1 >= nlsP->gamma1) && (tau_1 < 1.0) && ((tau_2 < nlsP->gamma1) || (tau_2 >= 1.0))) {
    677:                   tao->trust = tau_1 * PetscMin(tao->trust, norm_d);
    678:                 } else if ((tau_2 >= nlsP->gamma1) && (tau_2 < 1.0) && ((tau_1 < nlsP->gamma1) || (tau_2 >= 1.0))) {
    679:                   tao->trust = tau_2 * PetscMin(tao->trust, norm_d);
    680:                 } else {
    681:                   tao->trust = tau_max * PetscMin(tao->trust, norm_d);
    682:                 }
    683:               }
    684:             }
    685:           }
    686:         } else {
    687:           /*  Newton step was not good; reduce the radius */
    688:           tao->trust = nlsP->gamma1 * PetscMin(norm_d, tao->trust);
    689:         }
    690:         break;
    691:       }

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

    697:     /*  Check for termination */
    698:     TaoGradientNorm(tao, tao->gradient,NORM_2,&gnorm);
    699:     if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_USER,"User provided compute function generated Not-a-Number");
    700:     needH = 1;
    701:     TaoLogConvergenceHistory(tao,f,gnorm,0.0,tao->ksp_its);
    702:     TaoMonitor(tao,tao->niter,f,gnorm,0.0,step);
    703:     (*tao->ops->convergencetest)(tao,tao->cnvP);
    704:   }
    705:   return(0);
    706: }

    708: /* ---------------------------------------------------------- */
    709: static PetscErrorCode TaoSetUp_NLS(Tao tao)
    710: {
    711:   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;

    715:   if (!tao->gradient) {VecDuplicate(tao->solution,&tao->gradient);}
    716:   if (!tao->stepdirection) {VecDuplicate(tao->solution,&tao->stepdirection);}
    717:   if (!nlsP->W) {VecDuplicate(tao->solution,&nlsP->W);}
    718:   if (!nlsP->D) {VecDuplicate(tao->solution,&nlsP->D);}
    719:   if (!nlsP->Xold) {VecDuplicate(tao->solution,&nlsP->Xold);}
    720:   if (!nlsP->Gold) {VecDuplicate(tao->solution,&nlsP->Gold);}
    721:   nlsP->M = NULL;
    722:   nlsP->bfgs_pre = NULL;
    723:   return(0);
    724: }

    726: /*------------------------------------------------------------*/
    727: static PetscErrorCode TaoDestroy_NLS(Tao tao)
    728: {
    729:   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;

    733:   if (tao->setupcalled) {
    734:     VecDestroy(&nlsP->D);
    735:     VecDestroy(&nlsP->W);
    736:     VecDestroy(&nlsP->Xold);
    737:     VecDestroy(&nlsP->Gold);
    738:   }
    739:   PetscFree(tao->data);
    740:   return(0);
    741: }

    743: /*------------------------------------------------------------*/
    744: static PetscErrorCode TaoSetFromOptions_NLS(PetscOptionItems *PetscOptionsObject,Tao tao)
    745: {
    746:   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;

    750:   PetscOptionsHead(PetscOptionsObject,"Newton line search method for unconstrained optimization");
    751:   PetscOptionsEList("-tao_nls_init_type", "radius initialization type", "", NLS_INIT, NLS_INIT_TYPES, NLS_INIT[nlsP->init_type], &nlsP->init_type, NULL);
    752:   PetscOptionsEList("-tao_nls_update_type", "radius update type", "", NLS_UPDATE, NLS_UPDATE_TYPES, NLS_UPDATE[nlsP->update_type], &nlsP->update_type, NULL);
    753:   PetscOptionsReal("-tao_nls_sval", "perturbation starting value", "", nlsP->sval, &nlsP->sval,NULL);
    754:   PetscOptionsReal("-tao_nls_imin", "minimum initial perturbation", "", nlsP->imin, &nlsP->imin,NULL);
    755:   PetscOptionsReal("-tao_nls_imax", "maximum initial perturbation", "", nlsP->imax, &nlsP->imax,NULL);
    756:   PetscOptionsReal("-tao_nls_imfac", "initial merit factor", "", nlsP->imfac, &nlsP->imfac,NULL);
    757:   PetscOptionsReal("-tao_nls_pmin", "minimum perturbation", "", nlsP->pmin, &nlsP->pmin,NULL);
    758:   PetscOptionsReal("-tao_nls_pmax", "maximum perturbation", "", nlsP->pmax, &nlsP->pmax,NULL);
    759:   PetscOptionsReal("-tao_nls_pgfac", "growth factor", "", nlsP->pgfac, &nlsP->pgfac,NULL);
    760:   PetscOptionsReal("-tao_nls_psfac", "shrink factor", "", nlsP->psfac, &nlsP->psfac,NULL);
    761:   PetscOptionsReal("-tao_nls_pmgfac", "merit growth factor", "", nlsP->pmgfac, &nlsP->pmgfac,NULL);
    762:   PetscOptionsReal("-tao_nls_pmsfac", "merit shrink factor", "", nlsP->pmsfac, &nlsP->pmsfac,NULL);
    763:   PetscOptionsReal("-tao_nls_eta1", "poor steplength; reduce radius", "", nlsP->eta1, &nlsP->eta1,NULL);
    764:   PetscOptionsReal("-tao_nls_eta2", "reasonable steplength; leave radius alone", "", nlsP->eta2, &nlsP->eta2,NULL);
    765:   PetscOptionsReal("-tao_nls_eta3", "good steplength; increase radius", "", nlsP->eta3, &nlsP->eta3,NULL);
    766:   PetscOptionsReal("-tao_nls_eta4", "excellent steplength; greatly increase radius", "", nlsP->eta4, &nlsP->eta4,NULL);
    767:   PetscOptionsReal("-tao_nls_alpha1", "", "", nlsP->alpha1, &nlsP->alpha1,NULL);
    768:   PetscOptionsReal("-tao_nls_alpha2", "", "", nlsP->alpha2, &nlsP->alpha2,NULL);
    769:   PetscOptionsReal("-tao_nls_alpha3", "", "", nlsP->alpha3, &nlsP->alpha3,NULL);
    770:   PetscOptionsReal("-tao_nls_alpha4", "", "", nlsP->alpha4, &nlsP->alpha4,NULL);
    771:   PetscOptionsReal("-tao_nls_alpha5", "", "", nlsP->alpha5, &nlsP->alpha5,NULL);
    772:   PetscOptionsReal("-tao_nls_nu1", "poor steplength; reduce radius", "", nlsP->nu1, &nlsP->nu1,NULL);
    773:   PetscOptionsReal("-tao_nls_nu2", "reasonable steplength; leave radius alone", "", nlsP->nu2, &nlsP->nu2,NULL);
    774:   PetscOptionsReal("-tao_nls_nu3", "good steplength; increase radius", "", nlsP->nu3, &nlsP->nu3,NULL);
    775:   PetscOptionsReal("-tao_nls_nu4", "excellent steplength; greatly increase radius", "", nlsP->nu4, &nlsP->nu4,NULL);
    776:   PetscOptionsReal("-tao_nls_omega1", "", "", nlsP->omega1, &nlsP->omega1,NULL);
    777:   PetscOptionsReal("-tao_nls_omega2", "", "", nlsP->omega2, &nlsP->omega2,NULL);
    778:   PetscOptionsReal("-tao_nls_omega3", "", "", nlsP->omega3, &nlsP->omega3,NULL);
    779:   PetscOptionsReal("-tao_nls_omega4", "", "", nlsP->omega4, &nlsP->omega4,NULL);
    780:   PetscOptionsReal("-tao_nls_omega5", "", "", nlsP->omega5, &nlsP->omega5,NULL);
    781:   PetscOptionsReal("-tao_nls_mu1_i", "", "", nlsP->mu1_i, &nlsP->mu1_i,NULL);
    782:   PetscOptionsReal("-tao_nls_mu2_i", "", "", nlsP->mu2_i, &nlsP->mu2_i,NULL);
    783:   PetscOptionsReal("-tao_nls_gamma1_i", "", "", nlsP->gamma1_i, &nlsP->gamma1_i,NULL);
    784:   PetscOptionsReal("-tao_nls_gamma2_i", "", "", nlsP->gamma2_i, &nlsP->gamma2_i,NULL);
    785:   PetscOptionsReal("-tao_nls_gamma3_i", "", "", nlsP->gamma3_i, &nlsP->gamma3_i,NULL);
    786:   PetscOptionsReal("-tao_nls_gamma4_i", "", "", nlsP->gamma4_i, &nlsP->gamma4_i,NULL);
    787:   PetscOptionsReal("-tao_nls_theta_i", "", "", nlsP->theta_i, &nlsP->theta_i,NULL);
    788:   PetscOptionsReal("-tao_nls_mu1", "", "", nlsP->mu1, &nlsP->mu1,NULL);
    789:   PetscOptionsReal("-tao_nls_mu2", "", "", nlsP->mu2, &nlsP->mu2,NULL);
    790:   PetscOptionsReal("-tao_nls_gamma1", "", "", nlsP->gamma1, &nlsP->gamma1,NULL);
    791:   PetscOptionsReal("-tao_nls_gamma2", "", "", nlsP->gamma2, &nlsP->gamma2,NULL);
    792:   PetscOptionsReal("-tao_nls_gamma3", "", "", nlsP->gamma3, &nlsP->gamma3,NULL);
    793:   PetscOptionsReal("-tao_nls_gamma4", "", "", nlsP->gamma4, &nlsP->gamma4,NULL);
    794:   PetscOptionsReal("-tao_nls_theta", "", "", nlsP->theta, &nlsP->theta,NULL);
    795:   PetscOptionsReal("-tao_nls_min_radius", "lower bound on initial radius", "", nlsP->min_radius, &nlsP->min_radius,NULL);
    796:   PetscOptionsReal("-tao_nls_max_radius", "upper bound on radius", "", nlsP->max_radius, &nlsP->max_radius,NULL);
    797:   PetscOptionsReal("-tao_nls_epsilon", "tolerance used when computing actual and predicted reduction", "", nlsP->epsilon, &nlsP->epsilon,NULL);
    798:   PetscOptionsTail();
    799:   TaoLineSearchSetFromOptions(tao->linesearch);
    800:   KSPSetFromOptions(tao->ksp);
    801:   return(0);
    802: }

    804: /*------------------------------------------------------------*/
    805: static PetscErrorCode TaoView_NLS(Tao tao, PetscViewer viewer)
    806: {
    807:   TAO_NLS        *nlsP = (TAO_NLS *)tao->data;
    808:   PetscBool      isascii;

    812:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
    813:   if (isascii) {
    814:     PetscViewerASCIIPushTab(viewer);
    815:     PetscViewerASCIIPrintf(viewer, "Newton steps: %D\n", nlsP->newt);
    816:     PetscViewerASCIIPrintf(viewer, "BFGS steps: %D\n", nlsP->bfgs);
    817:     PetscViewerASCIIPrintf(viewer, "Gradient steps: %D\n", nlsP->grad);

    819:     PetscViewerASCIIPrintf(viewer, "nls ksp atol: %D\n", nlsP->ksp_atol);
    820:     PetscViewerASCIIPrintf(viewer, "nls ksp rtol: %D\n", nlsP->ksp_rtol);
    821:     PetscViewerASCIIPrintf(viewer, "nls ksp ctol: %D\n", nlsP->ksp_ctol);
    822:     PetscViewerASCIIPrintf(viewer, "nls ksp negc: %D\n", nlsP->ksp_negc);
    823:     PetscViewerASCIIPrintf(viewer, "nls ksp dtol: %D\n", nlsP->ksp_dtol);
    824:     PetscViewerASCIIPrintf(viewer, "nls ksp iter: %D\n", nlsP->ksp_iter);
    825:     PetscViewerASCIIPrintf(viewer, "nls ksp othr: %D\n", nlsP->ksp_othr);
    826:     PetscViewerASCIIPopTab(viewer);
    827:   }
    828:   return(0);
    829: }

    831: /* ---------------------------------------------------------- */
    832: /*MC
    833:   TAONLS - Newton's method with linesearch for unconstrained minimization.
    834:   At each iteration, the Newton line search method solves the symmetric
    835:   system of equations to obtain the step diretion dk:
    836:               Hk dk = -gk
    837:   a More-Thuente line search is applied on the direction dk to approximately
    838:   solve
    839:               min_t f(xk + t d_k)

    841:     Options Database Keys:
    842: + -tao_nls_init_type - "constant","direction","interpolation"
    843: . -tao_nls_update_type - "step","direction","interpolation"
    844: . -tao_nls_sval - perturbation starting value
    845: . -tao_nls_imin - minimum initial perturbation
    846: . -tao_nls_imax - maximum initial perturbation
    847: . -tao_nls_pmin - minimum perturbation
    848: . -tao_nls_pmax - maximum perturbation
    849: . -tao_nls_pgfac - growth factor
    850: . -tao_nls_psfac - shrink factor
    851: . -tao_nls_imfac - initial merit factor
    852: . -tao_nls_pmgfac - merit growth factor
    853: . -tao_nls_pmsfac - merit shrink factor
    854: . -tao_nls_eta1 - poor steplength; reduce radius
    855: . -tao_nls_eta2 - reasonable steplength; leave radius
    856: . -tao_nls_eta3 - good steplength; increase readius
    857: . -tao_nls_eta4 - excellent steplength; greatly increase radius
    858: . -tao_nls_alpha1 - alpha1 reduction
    859: . -tao_nls_alpha2 - alpha2 reduction
    860: . -tao_nls_alpha3 - alpha3 reduction
    861: . -tao_nls_alpha4 - alpha4 reduction
    862: . -tao_nls_alpha - alpha5 reduction
    863: . -tao_nls_mu1 - mu1 interpolation update
    864: . -tao_nls_mu2 - mu2 interpolation update
    865: . -tao_nls_gamma1 - gamma1 interpolation update
    866: . -tao_nls_gamma2 - gamma2 interpolation update
    867: . -tao_nls_gamma3 - gamma3 interpolation update
    868: . -tao_nls_gamma4 - gamma4 interpolation update
    869: . -tao_nls_theta - theta interpolation update
    870: . -tao_nls_omega1 - omega1 step update
    871: . -tao_nls_omega2 - omega2 step update
    872: . -tao_nls_omega3 - omega3 step update
    873: . -tao_nls_omega4 - omega4 step update
    874: . -tao_nls_omega5 - omega5 step update
    875: . -tao_nls_mu1_i -  mu1 interpolation init factor
    876: . -tao_nls_mu2_i -  mu2 interpolation init factor
    877: . -tao_nls_gamma1_i -  gamma1 interpolation init factor
    878: . -tao_nls_gamma2_i -  gamma2 interpolation init factor
    879: . -tao_nls_gamma3_i -  gamma3 interpolation init factor
    880: . -tao_nls_gamma4_i -  gamma4 interpolation init factor
    881: - -tao_nls_theta_i -  theta interpolation init factor

    883:   Level: beginner
    884: M*/

    886: PETSC_EXTERN PetscErrorCode TaoCreate_NLS(Tao tao)
    887: {
    888:   TAO_NLS        *nlsP;
    889:   const char     *morethuente_type = TAOLINESEARCHMT;

    893:   PetscNewLog(tao,&nlsP);

    895:   tao->ops->setup = TaoSetUp_NLS;
    896:   tao->ops->solve = TaoSolve_NLS;
    897:   tao->ops->view = TaoView_NLS;
    898:   tao->ops->setfromoptions = TaoSetFromOptions_NLS;
    899:   tao->ops->destroy = TaoDestroy_NLS;

    901:   /* Override default settings (unless already changed) */
    902:   if (!tao->max_it_changed) tao->max_it = 50;
    903:   if (!tao->trust0_changed) tao->trust0 = 100.0;

    905:   tao->data = (void*)nlsP;

    907:   nlsP->sval   = 0.0;
    908:   nlsP->imin   = 1.0e-4;
    909:   nlsP->imax   = 1.0e+2;
    910:   nlsP->imfac  = 1.0e-1;

    912:   nlsP->pmin   = 1.0e-12;
    913:   nlsP->pmax   = 1.0e+2;
    914:   nlsP->pgfac  = 1.0e+1;
    915:   nlsP->psfac  = 4.0e-1;
    916:   nlsP->pmgfac = 1.0e-1;
    917:   nlsP->pmsfac = 1.0e-1;

    919:   /*  Default values for trust-region radius update based on steplength */
    920:   nlsP->nu1 = 0.25;
    921:   nlsP->nu2 = 0.50;
    922:   nlsP->nu3 = 1.00;
    923:   nlsP->nu4 = 1.25;

    925:   nlsP->omega1 = 0.25;
    926:   nlsP->omega2 = 0.50;
    927:   nlsP->omega3 = 1.00;
    928:   nlsP->omega4 = 2.00;
    929:   nlsP->omega5 = 4.00;

    931:   /*  Default values for trust-region radius update based on reduction */
    932:   nlsP->eta1 = 1.0e-4;
    933:   nlsP->eta2 = 0.25;
    934:   nlsP->eta3 = 0.50;
    935:   nlsP->eta4 = 0.90;

    937:   nlsP->alpha1 = 0.25;
    938:   nlsP->alpha2 = 0.50;
    939:   nlsP->alpha3 = 1.00;
    940:   nlsP->alpha4 = 2.00;
    941:   nlsP->alpha5 = 4.00;

    943:   /*  Default values for trust-region radius update based on interpolation */
    944:   nlsP->mu1 = 0.10;
    945:   nlsP->mu2 = 0.50;

    947:   nlsP->gamma1 = 0.25;
    948:   nlsP->gamma2 = 0.50;
    949:   nlsP->gamma3 = 2.00;
    950:   nlsP->gamma4 = 4.00;

    952:   nlsP->theta = 0.05;

    954:   /*  Default values for trust region initialization based on interpolation */
    955:   nlsP->mu1_i = 0.35;
    956:   nlsP->mu2_i = 0.50;

    958:   nlsP->gamma1_i = 0.0625;
    959:   nlsP->gamma2_i = 0.5;
    960:   nlsP->gamma3_i = 2.0;
    961:   nlsP->gamma4_i = 5.0;

    963:   nlsP->theta_i = 0.25;

    965:   /*  Remaining parameters */
    966:   nlsP->min_radius = 1.0e-10;
    967:   nlsP->max_radius = 1.0e10;
    968:   nlsP->epsilon = 1.0e-6;

    970:   nlsP->init_type       = NLS_INIT_INTERPOLATION;
    971:   nlsP->update_type     = NLS_UPDATE_STEP;

    973:   TaoLineSearchCreate(((PetscObject)tao)->comm,&tao->linesearch);
    974:   PetscObjectIncrementTabLevel((PetscObject)tao->linesearch,(PetscObject)tao,1);
    975:   TaoLineSearchSetType(tao->linesearch,morethuente_type);
    976:   TaoLineSearchUseTaoRoutines(tao->linesearch,tao);
    977:   TaoLineSearchSetOptionsPrefix(tao->linesearch,tao->hdr.prefix);

    979:   /*  Set linear solver to default for symmetric matrices */
    980:   KSPCreate(((PetscObject)tao)->comm,&tao->ksp);
    981:   PetscObjectIncrementTabLevel((PetscObject)tao->ksp,(PetscObject)tao,1);
    982:   KSPSetOptionsPrefix(tao->ksp,tao->hdr.prefix);
    983:   KSPAppendOptionsPrefix(tao->ksp,"tao_nls_");
    984:   KSPSetType(tao->ksp,KSPSTCG);
    985:   return(0);
    986: }