Actual source code: lmvmmat.c
petsc-3.7.7 2017-09-25
1: #include <../src/tao/matrix/lmvmmat.h> /*I "lmvmmat.h" */
2: #include <petsctao.h> /*I "petsctao.h" */
3: #include <petscksp.h>
5: /* This is a vile hack */
6: #if defined(PETSC_USE_COMPLEX)
7: #define VecDot VecDotRealPart
8: #endif
10: #define TaoMid(a,b,c) (((a) < (b)) ? \
11: (((b) < (c)) ? (b) : \
12: (((a) < (c)) ? (c) : (a))) : \
13: (((a) < (c)) ? (a) : \
14: (((b) < (c)) ? (c) : (b))))
16: /* These lists are used for setting options */
17: static const char *Scale_Table[64] = {"none","scalar","broyden"};
19: static const char *Rescale_Table[64] = {"none","scalar","gl"};
21: static const char *Limit_Table[64] = {"none","average","relative","absolute"};
25: /*@C
26: MatCreateLMVM - Creates a limited memory matrix for lmvm algorithms.
28: Collective on A
30: Input Parameters:
31: + comm - MPI Communicator
32: . n - local size of vectors
33: - N - global size of vectors
35: Output Parameters:
36: . A - New LMVM matrix
38: Level: developer
40: @*/
41: extern PetscErrorCode MatCreateLMVM(MPI_Comm comm, PetscInt n, PetscInt N, Mat *A)
42: {
43: MatLMVMCtx *ctx;
45: PetscInt nhistory;
48: /* create data structure and populate with default values */
49: PetscNew(&ctx);
50: ctx->lm=5;
51: ctx->eps=0.0;
52: ctx->limitType=MatLMVM_Limit_None;
53: ctx->scaleType=MatLMVM_Scale_Broyden;
54: ctx->rScaleType = MatLMVM_Rescale_Scalar;
55: ctx->s_alpha = 1.0;
56: ctx->r_alpha = 1.0;
57: ctx->r_beta = 0.5;
58: ctx->mu = 1.0;
59: ctx->nu = 100.0;
60:
61: ctx->phi = 0.125;
62:
63: ctx->scalar_history = 1;
64: ctx->rescale_history = 1;
65:
66: ctx->delta_min = 1e-7;
67: ctx->delta_max = 100.0;
69: /* Begin configuration */
70: PetscOptionsBegin(comm,NULL,NULL,NULL);
71: PetscOptionsInt("-tao_lmm_vectors", "vectors to use for approximation", "", ctx->lm, &ctx->lm,NULL);
72: PetscOptionsReal("-tao_lmm_limit_mu", "mu limiting factor", "", ctx->mu, &ctx->mu,NULL);
73: PetscOptionsReal("-tao_lmm_limit_nu", "nu limiting factor", "", ctx->nu, &ctx->nu,NULL);
74: PetscOptionsReal("-tao_lmm_broyden_phi", "phi factor for Broyden scaling", "", ctx->phi, &ctx->phi,NULL);
75: PetscOptionsReal("-tao_lmm_scalar_alpha", "alpha factor for scalar scaling", "",ctx->s_alpha, &ctx->s_alpha,NULL);
76: PetscOptionsReal("-tao_lmm_rescale_alpha", "alpha factor for rescaling diagonal", "", ctx->r_alpha, &ctx->r_alpha,NULL);
77: PetscOptionsReal("-tao_lmm_rescale_beta", "beta factor for rescaling diagonal", "", ctx->r_beta, &ctx->r_beta,NULL);
78: PetscOptionsInt("-tao_lmm_scalar_history", "amount of history for scalar scaling", "", ctx->scalar_history, &ctx->scalar_history,NULL);
79: PetscOptionsInt("-tao_lmm_rescale_history", "amount of history for rescaling diagonal", "", ctx->rescale_history, &ctx->rescale_history,NULL);
80: PetscOptionsReal("-tao_lmm_eps", "rejection tolerance", "", ctx->eps, &ctx->eps,NULL);
81: PetscOptionsEList("-tao_lmm_scale_type", "scale type", "", Scale_Table, MatLMVM_Scale_Types, Scale_Table[ctx->scaleType], &ctx->scaleType,NULL);
82: PetscOptionsEList("-tao_lmm_rescale_type", "rescale type", "", Rescale_Table, MatLMVM_Rescale_Types, Rescale_Table[ctx->rScaleType], &ctx->rScaleType,NULL);
83: PetscOptionsEList("-tao_lmm_limit_type", "limit type", "", Limit_Table, MatLMVM_Limit_Types, Limit_Table[ctx->limitType], &ctx->limitType,NULL);
84: PetscOptionsReal("-tao_lmm_delta_min", "minimum delta value", "", ctx->delta_min, &ctx->delta_min,NULL);
85: PetscOptionsReal("-tao_lmm_delta_max", "maximum delta value", "", ctx->delta_max, &ctx->delta_max,NULL);
86: PetscOptionsEnd();
88: /* Complete configuration */
89: ctx->rescale_history = PetscMin(ctx->rescale_history, ctx->lm);
90: PetscMalloc1(ctx->lm+1,&ctx->rho);
91: PetscMalloc1(ctx->lm+1,&ctx->beta);
93: nhistory = PetscMax(ctx->scalar_history,1);
94: PetscMalloc1(nhistory,&ctx->yy_history);
95: PetscMalloc1(nhistory,&ctx->ys_history);
96: PetscMalloc1(nhistory,&ctx->ss_history);
98: nhistory = PetscMax(ctx->rescale_history,1);
99: PetscMalloc1(nhistory,&ctx->yy_rhistory);
100: PetscMalloc1(nhistory,&ctx->ys_rhistory);
101: PetscMalloc1(nhistory,&ctx->ss_rhistory);
103: /* Finish initializations */
104: ctx->lmnow = 0;
105: ctx->iter = 0;
106: ctx->nupdates = 0;
107: ctx->nrejects = 0;
108: ctx->delta = 1.0;
110: ctx->Gprev = 0;
111: ctx->Xprev = 0;
113: ctx->scale = 0;
114: ctx->useScale = PETSC_FALSE;
116: ctx->H0_mat = 0;
117: ctx->H0_ksp = 0;
118: ctx->H0_norm = 0;
119: ctx->useDefaultH0 = PETSC_TRUE;
121: MatCreateShell(comm, n, n, N, N, ctx, A);
122: MatShellSetOperation(*A,MATOP_DESTROY,(void(*)(void))MatDestroy_LMVM);
123: MatShellSetOperation(*A,MATOP_VIEW,(void(*)(void))MatView_LMVM);
124: return(0);
125: }
129: extern PetscErrorCode MatLMVMSolve(Mat A, Vec b, Vec x)
130: {
131: PetscReal sq, yq, dd;
132: PetscInt ll;
133: PetscBool scaled;
134: MatLMVMCtx *shell;
141: MatShellGetContext(A,(void**)&shell);
142: if (shell->lmnow < 1) {
143: shell->rho[0] = 1.0;
144: shell->theta = 1.0;
145: }
147: VecCopy(b,x);
148: for (ll = 0; ll < shell->lmnow; ++ll) {
149: VecDot(x,shell->S[ll],&sq);
150: shell->beta[ll] = sq * shell->rho[ll];
151: VecAXPY(x,-shell->beta[ll],shell->Y[ll]);
152: }
154: scaled = PETSC_FALSE;
155: if (!scaled && !shell->useDefaultH0 && shell->H0_mat) {
156: KSPSolve(shell->H0_ksp,x,shell->U);
157: VecScale(shell->U, shell->theta);
158: VecDot(x,shell->U,&dd);
159: if ((dd > 0.0) && !PetscIsInfOrNanReal(dd)) {
160: /* Accept Hessian solve */
161: VecCopy(shell->U,x);
162: scaled = PETSC_TRUE;
163: }
164: }
166: if (!scaled && shell->useScale) {
167: VecPointwiseMult(shell->U,x,shell->scale);
168: VecDot(x,shell->U,&dd);
169: if ((dd > 0.0) && !PetscIsInfOrNanReal(dd)) {
170: /* Accept scaling */
171: VecCopy(shell->U,x);
172: scaled = PETSC_TRUE;
173: }
174: }
176: if (!scaled) {
177: switch(shell->scaleType) {
178: case MatLMVM_Scale_None:
179: break;
181: case MatLMVM_Scale_Scalar:
182: VecScale(x,shell->sigma);
183: break;
185: case MatLMVM_Scale_Broyden:
186: VecPointwiseMult(x,x,shell->D);
187: break;
188: }
189: }
190: for (ll = shell->lmnow-1; ll >= 0; --ll) {
191: VecDot(x,shell->Y[ll],&yq);
192: VecAXPY(x,shell->beta[ll]-yq*shell->rho[ll],shell->S[ll]);
193: }
194: return(0);
195: }
199: extern PetscErrorCode MatView_LMVM(Mat A, PetscViewer pv)
200: {
201: PetscBool isascii;
203: MatLMVMCtx *lmP;
206: MatShellGetContext(A,(void**)&lmP);
207: PetscObjectTypeCompare((PetscObject)pv,PETSCVIEWERASCII,&isascii);
208: if (isascii) {
209: PetscViewerASCIIPrintf(pv,"LMVM Matrix\n");
210: PetscViewerASCIIPrintf(pv," Number of vectors: %D\n",lmP->lm);
211: PetscViewerASCIIPrintf(pv," scale type: %s\n",Scale_Table[lmP->scaleType]);
212: PetscViewerASCIIPrintf(pv," rescale type: %s\n",Rescale_Table[lmP->rScaleType]);
213: PetscViewerASCIIPrintf(pv," limit type: %s\n",Limit_Table[lmP->limitType]);
214: PetscViewerASCIIPrintf(pv," updates: %D\n",lmP->nupdates);
215: PetscViewerASCIIPrintf(pv," rejects: %D\n",lmP->nrejects);
216: }
217: return(0);
218: }
222: extern PetscErrorCode MatDestroy_LMVM(Mat M)
223: {
224: MatLMVMCtx *ctx;
228: MatShellGetContext(M,(void**)&ctx);
229: if (ctx->allocated) {
230: if (ctx->Xprev) {
231: PetscObjectDereference((PetscObject)ctx->Xprev);
232: }
233: if (ctx->Gprev) {
234: PetscObjectDereference((PetscObject)ctx->Gprev);
235: }
237: VecDestroyVecs(ctx->lm+1,&ctx->S);
238: VecDestroyVecs(ctx->lm+1,&ctx->Y);
239: VecDestroy(&ctx->D);
240: VecDestroy(&ctx->U);
241: VecDestroy(&ctx->V);
242: VecDestroy(&ctx->W);
243: VecDestroy(&ctx->P);
244: VecDestroy(&ctx->Q);
245: VecDestroy(&ctx->H0_norm);
246: if (ctx->scale) {
247: VecDestroy(&ctx->scale);
248: }
249: }
250: if (ctx->H0_mat) {
251: PetscObjectDereference((PetscObject)ctx->H0_mat);
252: KSPDestroy(&ctx->H0_ksp);
253: }
254: PetscFree(ctx->rho);
255: PetscFree(ctx->beta);
256: PetscFree(ctx->yy_history);
257: PetscFree(ctx->ys_history);
258: PetscFree(ctx->ss_history);
259: PetscFree(ctx->yy_rhistory);
260: PetscFree(ctx->ys_rhistory);
261: PetscFree(ctx->ss_rhistory);
262: PetscFree(ctx);
263: return(0);
264: }
268: extern PetscErrorCode MatLMVMReset(Mat M)
269: {
271: MatLMVMCtx *ctx;
272: PetscInt i;
275: MatShellGetContext(M,(void**)&ctx);
276: if (ctx->Gprev) {
277: PetscObjectDereference((PetscObject)ctx->Gprev);
278: }
279: if (ctx->Xprev) {
280: PetscObjectDereference((PetscObject)ctx->Xprev);
281: }
282: ctx->Gprev = ctx->Y[ctx->lm];
283: ctx->Xprev = ctx->S[ctx->lm];
284: PetscObjectReference((PetscObject)ctx->Gprev);
285: PetscObjectReference((PetscObject)ctx->Xprev);
286: for (i=0; i<ctx->lm; ++i) {
287: ctx->rho[i] = 0.0;
288: }
289: ctx->rho[0] = 1.0;
291: /* Set the scaling and diagonal scaling matrix */
292: switch(ctx->scaleType) {
293: case MatLMVM_Scale_None:
294: ctx->sigma = 1.0;
295: break;
296: case MatLMVM_Scale_Scalar:
297: ctx->sigma = ctx->delta;
298: break;
299: case MatLMVM_Scale_Broyden:
300: VecSet(ctx->D,ctx->delta);
301: break;
302: }
304: ctx->iter=0;
305: ctx->nupdates=0;
306: ctx->lmnow=0;
307: return(0);
308: }
312: extern PetscErrorCode MatLMVMUpdate(Mat M, Vec x, Vec g)
313: {
314: MatLMVMCtx *ctx;
315: PetscReal rhotemp, rhotol;
316: PetscReal y0temp, s0temp;
317: PetscReal yDy, yDs, sDs;
318: PetscReal sigmanew, denom;
320: PetscInt i;
321: PetscBool same;
322: PetscReal yy_sum=0.0, ys_sum=0.0, ss_sum=0.0;
327: PetscObjectTypeCompare((PetscObject)M,MATSHELL,&same);
328: if (!same) SETERRQ(PETSC_COMM_SELF,1,"Matrix M is not type MatLMVM");
329: MatShellGetContext(M,(void**)&ctx);
330: if (!ctx->allocated) {
331: MatLMVMAllocateVectors(M, x);
332: }
334: if (0 == ctx->iter) {
335: MatLMVMReset(M);
336: } else {
337: VecAYPX(ctx->Gprev,-1.0,g);
338: VecAYPX(ctx->Xprev,-1.0,x);
340: VecDot(ctx->Gprev,ctx->Xprev,&rhotemp);
341: VecDot(ctx->Gprev,ctx->Gprev,&y0temp);
343: rhotol = ctx->eps * y0temp;
344: if (rhotemp > rhotol) {
345: ++ctx->nupdates;
347: ctx->lmnow = PetscMin(ctx->lmnow+1, ctx->lm);
348: ierr=PetscObjectDereference((PetscObject)ctx->S[ctx->lm]);
349: ierr=PetscObjectDereference((PetscObject)ctx->Y[ctx->lm]);
350: for (i = ctx->lm-1; i >= 0; --i) {
351: ctx->S[i+1] = ctx->S[i];
352: ctx->Y[i+1] = ctx->Y[i];
353: ctx->rho[i+1] = ctx->rho[i];
354: }
355: ctx->S[0] = ctx->Xprev;
356: ctx->Y[0] = ctx->Gprev;
357: PetscObjectReference((PetscObject)ctx->S[0]);
358: PetscObjectReference((PetscObject)ctx->Y[0]);
359: ctx->rho[0] = 1.0 / rhotemp;
361: /* Compute the scaling */
362: switch(ctx->scaleType) {
363: case MatLMVM_Scale_None:
364: break;
366: case MatLMVM_Scale_Scalar:
367: /* Compute s^T s */
368: VecDot(ctx->Xprev,ctx->Xprev,&s0temp);
370: /* Scalar is positive; safeguards are not required. */
372: /* Save information for scalar scaling */
373: ctx->yy_history[(ctx->nupdates - 1) % ctx->scalar_history] = y0temp;
374: ctx->ys_history[(ctx->nupdates - 1) % ctx->scalar_history] = rhotemp;
375: ctx->ss_history[(ctx->nupdates - 1) % ctx->scalar_history] = s0temp;
377: /* Compute summations for scalar scaling */
378: yy_sum = 0; /* No safeguard required; y^T y > 0 */
379: ys_sum = 0; /* No safeguard required; y^T s > 0 */
380: ss_sum = 0; /* No safeguard required; s^T s > 0 */
381: for (i = 0; i < PetscMin(ctx->nupdates, ctx->scalar_history); ++i) {
382: yy_sum += ctx->yy_history[i];
383: ys_sum += ctx->ys_history[i];
384: ss_sum += ctx->ss_history[i];
385: }
387: if (0.0 == ctx->s_alpha) {
388: /* Safeguard ys_sum */
389: if (0.0 == ys_sum) {
390: ys_sum = TAO_ZERO_SAFEGUARD;
391: }
393: sigmanew = ss_sum / ys_sum;
394: } else if (1.0 == ctx->s_alpha) {
395: /* Safeguard yy_sum */
396: if (0.0 == yy_sum) {
397: yy_sum = TAO_ZERO_SAFEGUARD;
398: }
400: sigmanew = ys_sum / yy_sum;
401: } else {
402: denom = 2*ctx->s_alpha*yy_sum;
404: /* Safeguard denom */
405: if (0.0 == denom) {
406: denom = TAO_ZERO_SAFEGUARD;
407: }
409: sigmanew = ((2*ctx->s_alpha-1)*ys_sum + PetscSqrtReal((2*ctx->s_alpha-1)*(2*ctx->s_alpha-1)*ys_sum*ys_sum - 4*(ctx->s_alpha)*(ctx->s_alpha-1)*yy_sum*ss_sum)) / denom;
410: }
412: switch(ctx->limitType) {
413: case MatLMVM_Limit_Average:
414: if (1.0 == ctx->mu) {
415: ctx->sigma = sigmanew;
416: } else if (ctx->mu) {
417: ctx->sigma = ctx->mu * sigmanew + (1.0 - ctx->mu) * ctx->sigma;
418: }
419: break;
421: case MatLMVM_Limit_Relative:
422: if (ctx->mu) {
423: ctx->sigma = TaoMid((1.0 - ctx->mu) * ctx->sigma, sigmanew, (1.0 + ctx->mu) * ctx->sigma);
424: }
425: break;
427: case MatLMVM_Limit_Absolute:
428: if (ctx->nu) {
429: ctx->sigma = TaoMid(ctx->sigma - ctx->nu, sigmanew, ctx->sigma + ctx->nu);
430: }
431: break;
433: default:
434: ctx->sigma = sigmanew;
435: break;
436: }
437: break;
439: case MatLMVM_Scale_Broyden:
440: /* Original version */
441: /* Combine DFP and BFGS */
443: /* This code appears to be numerically unstable. We use the */
444: /* original version because this was used to generate all of */
445: /* the data and because it may be the least unstable of the */
446: /* bunch. */
448: /* P = Q = inv(D); */
449: VecCopy(ctx->D,ctx->P);
450: VecReciprocal(ctx->P);
451: VecCopy(ctx->P,ctx->Q);
453: /* V = y*y */
454: VecPointwiseMult(ctx->V,ctx->Gprev,ctx->Gprev);
456: /* W = inv(D)*s */
457: VecPointwiseMult(ctx->W,ctx->Xprev,ctx->P);
458: VecDot(ctx->W,ctx->Xprev,&sDs);
460: /* Safeguard rhotemp and sDs */
461: if (0.0 == rhotemp) {
462: rhotemp = TAO_ZERO_SAFEGUARD;
463: }
465: if (0.0 == sDs) {
466: sDs = TAO_ZERO_SAFEGUARD;
467: }
469: if (1.0 != ctx->phi) {
470: /* BFGS portion of the update */
471: /* U = (inv(D)*s)*(inv(D)*s) */
472: VecPointwiseMult(ctx->U,ctx->W,ctx->W);
474: /* Assemble */
475: VecAXPY(ctx->P,1.0/rhotemp,ctx->V);
476: VecAXPY(ctx->P,-1.0/sDs,ctx->U);
477: }
479: if (0.0 != ctx->phi) {
480: /* DFP portion of the update */
481: /* U = inv(D)*s*y */
482: VecPointwiseMult(ctx->U, ctx->W, ctx->Gprev);
484: /* Assemble */
485: VecAXPY(ctx->Q,1.0/rhotemp + sDs/(rhotemp*rhotemp), ctx->V);
486: VecAXPY(ctx->Q,-2.0/rhotemp,ctx->U);
487: }
489: if (0.0 == ctx->phi) {
490: VecCopy(ctx->P,ctx->U);
491: } else if (1.0 == ctx->phi) {
492: VecCopy(ctx->Q,ctx->U);
493: } else {
494: /* Broyden update U=(1-phi)*P + phi*Q */
495: VecCopy(ctx->Q,ctx->U);
496: VecAXPBY(ctx->U,1.0-ctx->phi, ctx->phi, ctx->P);
497: }
499: /* Obtain inverse and ensure positive definite */
500: VecReciprocal(ctx->U);
501: VecAbs(ctx->U);
503: switch(ctx->rScaleType) {
504: case MatLMVM_Rescale_None:
505: break;
507: case MatLMVM_Rescale_Scalar:
508: case MatLMVM_Rescale_GL:
509: if (ctx->rScaleType == MatLMVM_Rescale_GL) {
510: /* Gilbert and Lemarachal use the old diagonal */
511: VecCopy(ctx->D,ctx->P);
512: } else {
513: /* The default version uses the current diagonal */
514: VecCopy(ctx->U,ctx->P);
515: }
517: /* Compute s^T s */
518: VecDot(ctx->Xprev,ctx->Xprev,&s0temp);
520: /* Save information for special cases of scalar rescaling */
521: ctx->yy_rhistory[(ctx->nupdates - 1) % ctx->rescale_history] = y0temp;
522: ctx->ys_rhistory[(ctx->nupdates - 1) % ctx->rescale_history] = rhotemp;
523: ctx->ss_rhistory[(ctx->nupdates - 1) % ctx->rescale_history] = s0temp;
525: if (0.5 == ctx->r_beta) {
526: if (1 == PetscMin(ctx->nupdates, ctx->rescale_history)) {
527: VecPointwiseMult(ctx->V,ctx->Y[0],ctx->P);
528: VecDot(ctx->V,ctx->Y[0],&yy_sum);
530: VecPointwiseDivide(ctx->W,ctx->S[0],ctx->P);
531: VecDot(ctx->W,ctx->S[0],&ss_sum);
533: ys_sum = ctx->ys_rhistory[0];
534: } else {
535: VecCopy(ctx->P,ctx->Q);
536: VecReciprocal(ctx->Q);
538: /* Compute summations for scalar scaling */
539: yy_sum = 0; /* No safeguard required */
540: ys_sum = 0; /* No safeguard required */
541: ss_sum = 0; /* No safeguard required */
542: for (i = 0; i < PetscMin(ctx->nupdates, ctx->rescale_history); ++i) {
543: VecPointwiseMult(ctx->V,ctx->Y[i],ctx->P);
544: VecDot(ctx->V,ctx->Y[i],&yDy);
545: yy_sum += yDy;
547: VecPointwiseMult(ctx->W,ctx->S[i],ctx->Q);
548: VecDot(ctx->W,ctx->S[i],&sDs);
549: ss_sum += sDs;
550: ys_sum += ctx->ys_rhistory[i];
551: }
552: }
553: } else if (0.0 == ctx->r_beta) {
554: if (1 == PetscMin(ctx->nupdates, ctx->rescale_history)) {
555: /* Compute summations for scalar scaling */
556: VecPointwiseDivide(ctx->W,ctx->S[0],ctx->P);
558: VecDot(ctx->W, ctx->Y[0], &ys_sum);
559: VecDot(ctx->W, ctx->W, &ss_sum);
560: yy_sum += ctx->yy_rhistory[0];
561: } else {
562: VecCopy(ctx->Q, ctx->P);
563: VecReciprocal(ctx->Q);
565: /* Compute summations for scalar scaling */
566: yy_sum = 0; /* No safeguard required */
567: ys_sum = 0; /* No safeguard required */
568: ss_sum = 0; /* No safeguard required */
569: for (i = 0; i < PetscMin(ctx->nupdates, ctx->rescale_history); ++i) {
570: VecPointwiseMult(ctx->W, ctx->S[i], ctx->Q);
571: VecDot(ctx->W, ctx->Y[i], &yDs);
572: ys_sum += yDs;
574: VecDot(ctx->W, ctx->W, &sDs);
575: ss_sum += sDs;
577: yy_sum += ctx->yy_rhistory[i];
578: }
579: }
580: } else if (1.0 == ctx->r_beta) {
581: /* Compute summations for scalar scaling */
582: yy_sum = 0; /* No safeguard required */
583: ys_sum = 0; /* No safeguard required */
584: ss_sum = 0; /* No safeguard required */
585: for (i = 0; i < PetscMin(ctx->nupdates, ctx->rescale_history); ++i) {
586: VecPointwiseMult(ctx->V, ctx->Y[i], ctx->P);
587: VecDot(ctx->V, ctx->S[i], &yDs);
588: ys_sum += yDs;
590: VecDot(ctx->V, ctx->V, &yDy);
591: yy_sum += yDy;
593: ss_sum += ctx->ss_rhistory[i];
594: }
595: } else {
596: VecCopy(ctx->Q, ctx->P);
598: VecPow(ctx->P, ctx->r_beta);
599: VecPointwiseDivide(ctx->Q, ctx->P, ctx->Q);
601: /* Compute summations for scalar scaling */
602: yy_sum = 0; /* No safeguard required */
603: ys_sum = 0; /* No safeguard required */
604: ss_sum = 0; /* No safeguard required */
605: for (i = 0; i < PetscMin(ctx->nupdates, ctx->rescale_history); ++i) {
606: VecPointwiseMult(ctx->V, ctx->P, ctx->Y[i]);
607: VecPointwiseMult(ctx->W, ctx->Q, ctx->S[i]);
609: VecDot(ctx->V, ctx->V, &yDy);
610: VecDot(ctx->V, ctx->W, &yDs);
611: VecDot(ctx->W, ctx->W, &sDs);
613: yy_sum += yDy;
614: ys_sum += yDs;
615: ss_sum += sDs;
616: }
617: }
619: if (0.0 == ctx->r_alpha) {
620: /* Safeguard ys_sum */
621: if (0.0 == ys_sum) {
622: ys_sum = TAO_ZERO_SAFEGUARD;
623: }
625: sigmanew = ss_sum / ys_sum;
626: } else if (1.0 == ctx->r_alpha) {
627: /* Safeguard yy_sum */
628: if (0.0 == yy_sum) {
629: ys_sum = TAO_ZERO_SAFEGUARD;
630: }
632: sigmanew = ys_sum / yy_sum;
633: } else {
634: denom = 2*ctx->r_alpha*yy_sum;
636: /* Safeguard denom */
637: if (0.0 == denom) {
638: denom = TAO_ZERO_SAFEGUARD;
639: }
641: sigmanew = ((2*ctx->r_alpha-1)*ys_sum + PetscSqrtReal((2*ctx->r_alpha-1)*(2*ctx->r_alpha-1)*ys_sum*ys_sum - 4*ctx->r_alpha*(ctx->r_alpha-1)*yy_sum*ss_sum)) / denom;
642: }
644: /* If Q has small values, then Q^(r_beta - 1) */
645: /* can have very large values. Hence, ys_sum */
646: /* and ss_sum can be infinity. In this case, */
647: /* sigmanew can either be not-a-number or infinity. */
649: if (PetscIsInfOrNanReal(sigmanew)) {
650: /* sigmanew is not-a-number; skip rescaling */
651: } else if (!sigmanew) {
652: /* sigmanew is zero; this is a bad case; skip rescaling */
653: } else {
654: /* sigmanew is positive */
655: VecScale(ctx->U, sigmanew);
656: }
657: break;
658: }
660: /* Modify for previous information */
661: switch(ctx->limitType) {
662: case MatLMVM_Limit_Average:
663: if (1.0 == ctx->mu) {
664: VecCopy(ctx->D, ctx->U);
665: } else if (ctx->mu) {
666: VecAXPBY(ctx->D,ctx->mu, 1.0-ctx->mu,ctx->U);
667: }
668: break;
670: case MatLMVM_Limit_Relative:
671: if (ctx->mu) {
672: /* P = (1-mu) * D */
673: VecAXPBY(ctx->P, 1.0-ctx->mu, 0.0, ctx->D);
674: /* Q = (1+mu) * D */
675: VecAXPBY(ctx->Q, 1.0+ctx->mu, 0.0, ctx->D);
676: VecMedian(ctx->P, ctx->U, ctx->Q, ctx->D);
677: }
678: break;
680: case MatLMVM_Limit_Absolute:
681: if (ctx->nu) {
682: VecCopy(ctx->P, ctx->D);
683: VecShift(ctx->P, -ctx->nu);
684: VecCopy(ctx->D, ctx->Q);
685: VecShift(ctx->Q, ctx->nu);
686: VecMedian(ctx->P, ctx->U, ctx->Q, ctx->P);
687: }
688: break;
690: default:
691: VecCopy(ctx->U, ctx->D);
692: break;
693: }
694: break;
695: }
696: PetscObjectDereference((PetscObject)ctx->Xprev);
697: PetscObjectDereference((PetscObject)ctx->Gprev);
698: ctx->Xprev = ctx->S[ctx->lm];
699: ctx->Gprev = ctx->Y[ctx->lm];
700: PetscObjectReference((PetscObject)ctx->S[ctx->lm]);
701: PetscObjectReference((PetscObject)ctx->Y[ctx->lm]);
703: } else {
704: ++ctx->nrejects;
705: }
706: }
708: ++ctx->iter;
709: VecCopy(x, ctx->Xprev);
710: VecCopy(g, ctx->Gprev);
711: return(0);
712: }
716: extern PetscErrorCode MatLMVMSetDelta(Mat m, PetscReal d)
717: {
718: MatLMVMCtx *ctx;
720: PetscBool same;
724: PetscObjectTypeCompare((PetscObject)m,MATSHELL,&same);
725: if (!same) SETERRQ(PETSC_COMM_SELF,1,"Matrix m is not type MatLMVM");
726: MatShellGetContext(m,(void**)&ctx);
727: ctx->delta = PetscAbsReal(d);
728: ctx->delta = PetscMax(ctx->delta_min, ctx->delta);
729: ctx->delta = PetscMin(ctx->delta_max, ctx->delta);
730: return(0);
731: }
735: extern PetscErrorCode MatLMVMSetScale(Mat m, Vec s)
736: {
737: MatLMVMCtx *ctx;
739: PetscBool same;
743: PetscObjectTypeCompare((PetscObject)m,MATSHELL,&same);
744: if (!same) SETERRQ(PETSC_COMM_SELF,1,"Matrix m is not type MatLMVM");
745: MatShellGetContext(m,(void**)&ctx);
747: VecDestroy(&ctx->scale);
748: if (s) {
749: VecDuplicate(s,&ctx->scale);
750: }
751: return(0);
752: }
756: extern PetscErrorCode MatLMVMGetRejects(Mat m, PetscInt *nrejects)
757: {
758: MatLMVMCtx *ctx;
760: PetscBool same;
764: PetscObjectTypeCompare((PetscObject)m,MATSHELL,&same);
765: if (!same) SETERRQ(PETSC_COMM_SELF,1,"Matrix m is not type MatLMVM");
766: MatShellGetContext(m,(void**)&ctx);
767: *nrejects = ctx->nrejects;
768: return(0);
769: }
773: extern PetscErrorCode MatLMVMSetH0(Mat m, Mat H0)
774: {
775: MatLMVMCtx *ctx;
777: PetscBool same;
781: PetscObjectTypeCompare((PetscObject)m,MATSHELL,&same);
782: if (!same) SETERRQ(PETSC_COMM_SELF,1,"Matrix m is not type MatLMVM");
783: MatShellGetContext(m,(void**)&ctx);
785: ctx->H0_mat = H0;
786: PetscObjectReference((PetscObject)ctx->H0_mat);
788: ctx->useDefaultH0 = PETSC_FALSE;
790: KSPCreate(PetscObjectComm((PetscObject)H0), &ctx->H0_ksp);
791: KSPSetOperators(ctx->H0_ksp, H0, H0);
792: /* its options prefix and setup is handled in TaoSolve_LMVM/TaoSolve_BLMVM */
793: return(0);
794: }
798: extern PetscErrorCode MatLMVMGetH0(Mat m, Mat *H0)
799: {
800: MatLMVMCtx *ctx;
802: PetscBool same;
806: PetscObjectTypeCompare((PetscObject)m,MATSHELL,&same);
807: if (!same) SETERRQ(PETSC_COMM_SELF,1,"Matrix m is not type MatLMVM");
809: MatShellGetContext(m,(void**)&ctx);
810: *H0 = ctx->H0_mat;
811: return(0);
812: }
816: extern PetscErrorCode MatLMVMGetH0KSP(Mat m, KSP *H0ksp)
817: {
818: MatLMVMCtx *ctx;
820: PetscBool same;
824: PetscObjectTypeCompare((PetscObject)m,MATSHELL,&same);
825: if (!same) SETERRQ(PETSC_COMM_SELF,1,"Matrix m is not type MatLMVM");
827: MatShellGetContext(m,(void**)&ctx);
828: *H0ksp = ctx->H0_ksp;
829: return(0);
830: }
834: extern PetscErrorCode MatLMVMGetX0(Mat m, Vec x)
835: {
837: return(0);
838: }
842: extern PetscErrorCode MatLMVMSetPrev(Mat M, Vec x, Vec g)
843: {
844: MatLMVMCtx *ctx;
846: PetscBool same;
851: PetscObjectTypeCompare((PetscObject)M,MATSHELL,&same);
852: if (!same) SETERRQ(PETSC_COMM_SELF,1,"Matrix M is not type MatLMVM");
853: MatShellGetContext(M,(void**)&ctx);
854: if (ctx->nupdates == 0) {
855: MatLMVMUpdate(M,x,g);
856: } else {
857: VecCopy(x,ctx->Xprev);
858: VecCopy(g,ctx->Gprev);
859: /* TODO scaling specific terms */
860: }
861: return(0);
862: }
866: extern PetscErrorCode MatLMVMRefine(Mat coarse, Mat op, Vec fineX, Vec fineG)
867: {
869: PetscBool same;
876: PetscObjectTypeCompare((PetscObject)coarse,MATSHELL,&same);
877: if (!same) SETERRQ(PETSC_COMM_SELF,1,"Matrix m is not type MatLMVM");
878: PetscObjectTypeCompare((PetscObject)op,MATSHELL,&same);
879: if (!same) SETERRQ(PETSC_COMM_SELF,1,"Matrix m is not type MatLMVM");
880: return(0);
881: }
885: extern PetscErrorCode MatLMVMAllocateVectors(Mat m, Vec v)
886: {
888: MatLMVMCtx *ctx;
889: PetscBool same;
894: PetscObjectTypeCompare((PetscObject)m,MATSHELL,&same);
895: if (!same) SETERRQ(PETSC_COMM_SELF,1,"Matrix m is not type MatLMVM");
896: MatShellGetContext(m,(void**)&ctx);
898: /* Perform allocations */
899: VecDuplicateVecs(v,ctx->lm+1,&ctx->S);
900: VecDuplicateVecs(v,ctx->lm+1,&ctx->Y);
901: VecDuplicate(v,&ctx->D);
902: VecDuplicate(v,&ctx->U);
903: VecDuplicate(v,&ctx->V);
904: VecDuplicate(v,&ctx->W);
905: VecDuplicate(v,&ctx->P);
906: VecDuplicate(v,&ctx->Q);
907: VecDuplicate(v,&ctx->H0_norm);
908: ctx->allocated = PETSC_TRUE;
909: return(0);
910: }