Actual source code: nls.c
petsc-dev 2014-02-02
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: }