Actual source code: cayley.c

  1: /*
  2:       Implements the Cayley spectral transform.
  3: */
 4:  #include src/st/stimpl.h

  6: typedef struct {
  7:   PetscScalar tau;
  8:   PetscTruth  tau_set;
  9:   Vec         w2;
 10: } ST_CAYLEY;

 14: PetscErrorCode STApply_Cayley(ST st,Vec x,Vec y)
 15: {
 17:   ST_CAYLEY      *ctx = (ST_CAYLEY *) st->data;
 18:   PetscScalar    tau = ctx->tau;
 19: 
 21:   if (st->shift_matrix == STMATMODE_INPLACE) { tau = tau + st->sigma; };

 23:   if (st->B) {
 24:     /* generalized eigenproblem: y = (A - sB)^-1 (A + tB)x */
 25:     MatMult(st->A,x,st->w);
 26:     MatMult(st->B,x,ctx->w2);
 27:     VecAXPY(st->w,tau,ctx->w2);
 28:     STAssociatedKSPSolve(st,st->w,y);
 29:   }
 30:   else {
 31:     /* standard eigenproblem: y = (A - sI)^-1 (A + tI)x */
 32:     MatMult(st->A,x,st->w);
 33:     VecAXPY(st->w,tau,x);
 34:     STAssociatedKSPSolve(st,st->w,y);
 35:   }
 36:   return(0);
 37: }

 41: PetscErrorCode STApplyTranspose_Cayley(ST st,Vec x,Vec y)
 42: {
 44:   ST_CAYLEY      *ctx = (ST_CAYLEY *) st->data;
 45:   PetscScalar    tau = ctx->tau;
 46: 
 48:   if (st->shift_matrix == STMATMODE_INPLACE) { tau = tau + st->sigma; };

 50:   if (st->B) {
 51:     /* generalized eigenproblem: y = (A + tB)^T (A - sB)^-T x */
 52:     STAssociatedKSPSolve(st,x,st->w);
 53:     MatMult(st->A,st->w,y);
 54:     MatMult(st->B,st->w,ctx->w2);
 55:     VecAXPY(y,tau,ctx->w2);
 56:   }
 57:   else {
 58:     /* standard eigenproblem: y =  (A + tI)^T (A - sI)^-T x */
 59:     STAssociatedKSPSolve(st,x,st->w);
 60:     MatMult(st->A,st->w,y);
 61:     VecAXPY(y,tau,st->w);
 62:   }
 63:   return(0);
 64: }

 68: PetscErrorCode STApplyNoB_Cayley(ST st,Vec x,Vec y)
 69: {

 73:   STAssociatedKSPSolve(st,x,y);
 74:   return(0);
 75: }

 79: PetscErrorCode STApplyB_Cayley(ST st,Vec x,Vec y)
 80: {
 82:   ST_CAYLEY      *ctx = (ST_CAYLEY *) st->data;
 83:   PetscScalar    tau = ctx->tau;
 84: 
 86:   if (st->shift_matrix == STMATMODE_INPLACE) { tau = tau + st->sigma; };

 88:   if (st->B) {
 89:     /* generalized eigenproblem: y = (A + tB)x */
 90:     MatMult(st->A,x,y);
 91:     MatMult(st->B,x,ctx->w2);
 92:     VecAXPY(y,tau,ctx->w2);
 93:   }
 94:   else {
 95:     /* standard eigenproblem: y = (A + tI)x */
 96:     MatMult(st->A,x,y);
 97:     VecAXPY(y,tau,x);
 98:   }
 99:   return(0);
100: }

104: PetscErrorCode STBackTransform_Cayley(ST st,PetscScalar *eigr,PetscScalar *eigi)
105: {
106:   ST_CAYLEY   *ctx = (ST_CAYLEY *) st->data;
107: #ifndef PETSC_USE_COMPLEX
108:   PetscScalar t,i,r;
112:   if (*eigi == 0.0) *eigr = (ctx->tau + *eigr * st->sigma) / (*eigr - 1.0);
113:   else {
114:     r = *eigr;
115:     i = *eigi;
116:     r = st->sigma * (r * r + i * i - r) + ctx->tau * (r - 1);
117:     i = - st->sigma * i - ctx->tau * i;
118:     t = i * i + r * (r - 2.0) + 1.0;
119:     *eigr = r / t;
120:     *eigi = i / t;
121:   }
122: #else
125:   *eigr = (ctx->tau + *eigr * st->sigma) / (*eigr - 1.0);
126: #endif
127:   return(0);
128: }

132: PetscErrorCode STPostSolve_Cayley(ST st)
133: {

137:   if (st->shift_matrix == STMATMODE_INPLACE) {
138:     if (st->B) {
139:       MatAXPY(st->A,st->sigma,st->B,st->str);
140:     } else {
141:       MatShift(st->A,st->sigma);
142:     }
143:     st->setupcalled = 0;
144:   }
145:   return(0);
146: }

150: PetscErrorCode STSetUp_Cayley(ST st)
151: {
153:   ST_CAYLEY      *ctx = (ST_CAYLEY *) st->data;


157:   if (st->mat) { MatDestroy(st->mat); }
158:   if (!ctx->tau_set) { ctx->tau = st->sigma; }
159:   if (ctx->tau == 0.0 &&  st->sigma == 0.0) {
160:     SETERRQ(1,"Values of shift and antishift cannot be zero simultaneously");
161:   }

163:   switch (st->shift_matrix) {
164:   case STMATMODE_INPLACE:
165:     st->mat = PETSC_NULL;
166:     if (st->sigma != 0.0) {
167:       if (st->B) {
168:         MatAXPY(st->A,-st->sigma,st->B,st->str);
169:       } else {
170:         MatShift(st->A,-st->sigma);
171:       }
172:     }
173:     /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
174:      * improve performance when solving a number of related eigenproblems */
175:     KSPSetOperators(st->ksp,st->A,st->A,SAME_NONZERO_PATTERN);
176:     break;
177:   case STMATMODE_SHELL:
178:     STMatShellCreate(st,&st->mat);
179:     KSPSetOperators(st->ksp,st->mat,st->mat,DIFFERENT_NONZERO_PATTERN);
180:     break;
181:   default:
182:     MatDuplicate(st->A,MAT_COPY_VALUES,&st->mat);
183:     if (st->sigma != 0.0) {
184:       if (st->B) {
185:         MatAXPY(st->mat,-st->sigma,st->B,st->str);
186:       } else {
187:         MatShift(st->mat,-st->sigma);
188:       }
189:     }
190:     /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
191:      * improve performance when solving a number of related eigenproblems */
192:     KSPSetOperators(st->ksp,st->mat,st->mat,SAME_NONZERO_PATTERN);
193:   }
194:   if (st->B) {
195:    if (ctx->w2) { VecDestroy(ctx->w2); }
196:    MatGetVecs(st->B,&ctx->w2,PETSC_NULL);
197:   }
198:   KSPSetUp(st->ksp);
199:   return(0);
200: }

204: PetscErrorCode STSetShift_Cayley(ST st,PetscScalar newshift)
205: {
207:   ST_CAYLEY      *ctx = (ST_CAYLEY *) st->data;


211:   /* Nothing to be done if STSetUp has not been called yet */
212:   if (!st->setupcalled) return(0);

214:   switch (st->shift_matrix) {
215:   case STMATMODE_INPLACE:
216:     /* Undo previous operations */
217:     if (st->sigma != 0.0) {
218:       if (st->B) {
219:         MatAXPY(st->A,st->sigma,st->B,st->str);
220:       } else {
221:         MatShift(st->A,st->sigma);
222:       }
223:     }
224:     /* Apply new shift */
225:     if (newshift != 0.0) {
226:       if (st->B) {
227:         MatAXPY(st->A,-newshift,st->B,st->str);
228:       } else {
229:         MatShift(st->A,-newshift);
230:       }
231:     }
232:     KSPSetOperators(st->ksp,st->A,st->A,SAME_NONZERO_PATTERN);
233:     break;
234:   case STMATMODE_SHELL:
235:     KSPSetOperators(st->ksp,st->mat,st->mat,SAME_NONZERO_PATTERN);
236:     break;
237:   default:
238:     MatCopy(st->A, st->mat,SUBSET_NONZERO_PATTERN);
239:     if (newshift != 0.0) {
240:       if (st->B) { MatAXPY(st->mat,-newshift,st->B,st->str); }
241:       else { MatShift(st->mat,-newshift); }
242:     }
243:     /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
244:      * improve performance when solving a number of related eigenproblems */
245:     KSPSetOperators(st->ksp,st->mat,st->mat,SAME_NONZERO_PATTERN);
246:   }
247:   st->sigma = newshift;
248:   if (!ctx->tau_set) { ctx->tau = newshift; }
249:   KSPSetUp(st->ksp);
250:   return(0);
251: }

255: PetscErrorCode STSetFromOptions_Cayley(ST st)
256: {
258:   PetscScalar    tau;
259:   PetscTruth     flg;
260:   ST_CAYLEY      *ctx = (ST_CAYLEY *) st->data;

263:   PetscOptionsHead("ST Cayley Options");
264:   PetscOptionsScalar("-st_antishift","Value of the antishift","STSetAntishift",ctx->tau,&tau,&flg);
265:   if (flg) {
266:     STCayleySetAntishift(st,tau);
267:   }
268:   PetscOptionsTail();
269:   return(0);
270: }

275: PetscErrorCode STCayleySetAntishift_Cayley(ST st,PetscScalar newshift)
276: {
277:   ST_CAYLEY *ctx = (ST_CAYLEY *) st->data;

280:   ctx->tau = newshift;
281:   ctx->tau_set = PETSC_TRUE;
282:   return(0);
283: }

288: /*@
289:    STCayleySetAntishift - Sets the value of the anti-shift for the Cayley
290:    spectral transformation.

292:    Collective on ST

294:    Input Parameters:
295: +  st  - the spectral transformation context
296: -  tau - the anti-shift

298:    Options Database Key:
299: .  -st_antishift - Sets the value of the anti-shift

301:    Level: intermediate

303:    Note:
304:    In the generalized Cayley transform, the operator can be expressed as
305:    OP = inv(A - sigma B)*(A + tau B). This function sets the value of tau.
306:    Use STSetShift() for setting sigma.

308: .seealso: STSetShift()
309: @*/
310: PetscErrorCode STCayleySetAntishift(ST st,PetscScalar tau)
311: {
312:   PetscErrorCode ierr, (*f)(ST,PetscScalar);

316:   PetscObjectQueryFunction((PetscObject)st,"STCayleySetAntishift_C",(void (**)(void))&f);
317:   if (f) {
318:     (*f)(st,tau);
319:   }
320:   return(0);
321: }

325: PetscErrorCode STView_Cayley(ST st,PetscViewer viewer)
326: {
328:   ST_CAYLEY      *ctx = (ST_CAYLEY *) st->data;

331: #if !defined(PETSC_USE_COMPLEX)
332:   PetscViewerASCIIPrintf(viewer,"  antishift: %g\n",ctx->tau);
333: #else
334:   PetscViewerASCIIPrintf(viewer,"  antishift: %g+%g i\n",PetscRealPart(ctx->tau),PetscImaginaryPart(ctx->tau));
335: #endif
336:   STView_Default(st,viewer);
337:   return(0);
338: }

342: PetscErrorCode STDestroy_Cayley(ST st)
343: {
345:   ST_CAYLEY      *ctx = (ST_CAYLEY *) st->data;

348:   if (ctx->w2) { VecDestroy(ctx->w2); }
349:   PetscFree(ctx);
350:   return(0);
351: }

356: PetscErrorCode STCreate_Cayley(ST st)
357: {
359:   ST_CAYLEY      *ctx;

362:   PetscNew(ST_CAYLEY,&ctx);
363:   PetscLogObjectMemory(st,sizeof(ST_CAYLEY));
364:   st->data                = (void *) ctx;

366:   st->ops->apply          = STApply_Cayley;
367:   st->ops->applyB         = STApplyB_Cayley;
368:   st->ops->applynoB       = STApplyNoB_Cayley;
369:   st->ops->applytrans     = STApplyTranspose_Cayley;
370:   st->ops->postsolve      = STPostSolve_Cayley;
371:   st->ops->backtr         = STBackTransform_Cayley;
372:   st->ops->setfromoptions = STSetFromOptions_Cayley;
373:   st->ops->setup          = STSetUp_Cayley;
374:   st->ops->setshift       = STSetShift_Cayley;
375:   st->ops->destroy        = STDestroy_Cayley;
376:   st->ops->view           = STView_Cayley;
377: 
378:   st->checknullspace      = STCheckNullSpace_Default;

380:   ctx->tau                = 0.0;
381:   ctx->tau_set            = PETSC_FALSE;

383:   PetscObjectComposeFunctionDynamic((PetscObject)st,"STCayleySetAntishift_C","STCayleySetAntishift_Cayley",
384:                     STCayleySetAntishift_Cayley);

386:   return(0);
387: }