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: }