Actual source code: cyclic.c
slepc-3.18.1 2022-11-02
1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
6: This file is part of SLEPc.
7: SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9: */
10: /*
11: SLEPc singular value solver: "cyclic"
13: Method: Uses a Hermitian eigensolver for H(A) = [ 0 A ; A^T 0 ]
14: */
16: #include <slepc/private/svdimpl.h>
17: #include "cyclic.h"
19: static PetscErrorCode MatMult_Cyclic(Mat B,Vec x,Vec y)
20: {
21: SVD_CYCLIC_SHELL *ctx;
22: const PetscScalar *px;
23: PetscScalar *py;
24: PetscInt m;
26: MatShellGetContext(B,&ctx);
27: MatGetLocalSize(ctx->A,&m,NULL);
28: VecGetArrayRead(x,&px);
29: VecGetArrayWrite(y,&py);
30: VecPlaceArray(ctx->x1,px);
31: VecPlaceArray(ctx->x2,px+m);
32: VecPlaceArray(ctx->y1,py);
33: VecPlaceArray(ctx->y2,py+m);
34: MatMult(ctx->A,ctx->x2,ctx->y1);
35: MatMult(ctx->AT,ctx->x1,ctx->y2);
36: VecResetArray(ctx->x1);
37: VecResetArray(ctx->x2);
38: VecResetArray(ctx->y1);
39: VecResetArray(ctx->y2);
40: VecRestoreArrayRead(x,&px);
41: VecRestoreArrayWrite(y,&py);
42: return 0;
43: }
45: static PetscErrorCode MatGetDiagonal_Cyclic(Mat B,Vec diag)
46: {
47: VecSet(diag,0.0);
48: return 0;
49: }
51: static PetscErrorCode MatDestroy_Cyclic(Mat B)
52: {
53: SVD_CYCLIC_SHELL *ctx;
55: MatShellGetContext(B,&ctx);
56: VecDestroy(&ctx->x1);
57: VecDestroy(&ctx->x2);
58: VecDestroy(&ctx->y1);
59: VecDestroy(&ctx->y2);
60: PetscFree(ctx);
61: return 0;
62: }
64: /*
65: Builds cyclic matrix C = | 0 A |
66: | AT 0 |
67: */
68: static PetscErrorCode SVDCyclicGetCyclicMat(SVD svd,Mat A,Mat AT,Mat *C)
69: {
70: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
71: SVD_CYCLIC_SHELL *ctx;
72: PetscInt i,M,N,m,n,Istart,Iend;
73: VecType vtype;
74: Mat Zm,Zn;
75: #if defined(PETSC_HAVE_CUDA)
76: PetscBool cuda;
77: #endif
79: MatGetSize(A,&M,&N);
80: MatGetLocalSize(A,&m,&n);
82: if (cyclic->explicitmatrix) {
84: MatCreate(PetscObjectComm((PetscObject)svd),&Zm);
85: MatSetSizes(Zm,m,m,M,M);
86: MatSetFromOptions(Zm);
87: MatSetUp(Zm);
88: MatGetOwnershipRange(Zm,&Istart,&Iend);
89: for (i=Istart;i<Iend;i++) MatSetValue(Zm,i,i,0.0,INSERT_VALUES);
90: MatAssemblyBegin(Zm,MAT_FINAL_ASSEMBLY);
91: MatAssemblyEnd(Zm,MAT_FINAL_ASSEMBLY);
92: MatCreate(PetscObjectComm((PetscObject)svd),&Zn);
93: MatSetSizes(Zn,n,n,N,N);
94: MatSetFromOptions(Zn);
95: MatSetUp(Zn);
96: MatGetOwnershipRange(Zn,&Istart,&Iend);
97: for (i=Istart;i<Iend;i++) MatSetValue(Zn,i,i,0.0,INSERT_VALUES);
98: MatAssemblyBegin(Zn,MAT_FINAL_ASSEMBLY);
99: MatAssemblyEnd(Zn,MAT_FINAL_ASSEMBLY);
100: MatCreateTile(1.0,Zm,1.0,A,1.0,AT,1.0,Zn,C);
101: MatDestroy(&Zm);
102: MatDestroy(&Zn);
103: } else {
104: PetscNew(&ctx);
105: ctx->A = A;
106: ctx->AT = AT;
107: ctx->swapped = svd->swapped;
108: MatCreateVecsEmpty(A,&ctx->x2,&ctx->x1);
109: MatCreateVecsEmpty(A,&ctx->y2,&ctx->y1);
110: MatCreateShell(PetscObjectComm((PetscObject)svd),m+n,m+n,M+N,M+N,ctx,C);
111: MatShellSetOperation(*C,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Cyclic);
112: MatShellSetOperation(*C,MATOP_DESTROY,(void(*)(void))MatDestroy_Cyclic);
113: #if defined(PETSC_HAVE_CUDA)
114: PetscObjectTypeCompareAny((PetscObject)(svd->swapped?AT:A),&cuda,MATSEQAIJCUSPARSE,MATMPIAIJCUSPARSE,"");
115: if (cuda) MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_Cyclic_CUDA);
116: else
117: #endif
118: MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_Cyclic);
119: MatGetVecType(A,&vtype);
120: MatSetVecType(*C,vtype);
121: }
122: return 0;
123: }
125: static PetscErrorCode MatMult_ECross(Mat B,Vec x,Vec y)
126: {
127: SVD_CYCLIC_SHELL *ctx;
128: const PetscScalar *px;
129: PetscScalar *py;
130: PetscInt mn,m,n;
132: MatShellGetContext(B,&ctx);
133: MatGetLocalSize(ctx->A,NULL,&n);
134: VecGetLocalSize(y,&mn);
135: m = mn-n;
136: VecGetArrayRead(x,&px);
137: VecGetArrayWrite(y,&py);
138: VecPlaceArray(ctx->x1,px);
139: VecPlaceArray(ctx->x2,px+m);
140: VecPlaceArray(ctx->y1,py);
141: VecPlaceArray(ctx->y2,py+m);
142: VecCopy(ctx->x1,ctx->y1);
143: MatMult(ctx->A,ctx->x2,ctx->w);
144: MatMult(ctx->AT,ctx->w,ctx->y2);
145: VecResetArray(ctx->x1);
146: VecResetArray(ctx->x2);
147: VecResetArray(ctx->y1);
148: VecResetArray(ctx->y2);
149: VecRestoreArrayRead(x,&px);
150: VecRestoreArrayWrite(y,&py);
151: return 0;
152: }
154: static PetscErrorCode MatGetDiagonal_ECross(Mat B,Vec d)
155: {
156: SVD_CYCLIC_SHELL *ctx;
157: PetscScalar *pd;
158: PetscMPIInt len;
159: PetscInt mn,m,n,N,i,j,start,end,ncols;
160: PetscScalar *work1,*work2,*diag;
161: const PetscInt *cols;
162: const PetscScalar *vals;
164: MatShellGetContext(B,&ctx);
165: MatGetLocalSize(ctx->A,NULL,&n);
166: VecGetLocalSize(d,&mn);
167: m = mn-n;
168: VecGetArrayWrite(d,&pd);
169: VecPlaceArray(ctx->y1,pd);
170: VecSet(ctx->y1,1.0);
171: VecResetArray(ctx->y1);
172: VecPlaceArray(ctx->y2,pd+m);
173: if (!ctx->diag) {
174: /* compute diagonal from rows and store in ctx->diag */
175: VecDuplicate(ctx->y2,&ctx->diag);
176: MatGetSize(ctx->A,NULL,&N);
177: PetscCalloc2(N,&work1,N,&work2);
178: if (ctx->swapped) {
179: MatGetOwnershipRange(ctx->AT,&start,&end);
180: for (i=start;i<end;i++) {
181: MatGetRow(ctx->AT,i,&ncols,NULL,&vals);
182: for (j=0;j<ncols;j++) work1[i] += vals[j]*vals[j];
183: MatRestoreRow(ctx->AT,i,&ncols,NULL,&vals);
184: }
185: } else {
186: MatGetOwnershipRange(ctx->A,&start,&end);
187: for (i=start;i<end;i++) {
188: MatGetRow(ctx->A,i,&ncols,&cols,&vals);
189: for (j=0;j<ncols;j++) work1[cols[j]] += vals[j]*vals[j];
190: MatRestoreRow(ctx->A,i,&ncols,&cols,&vals);
191: }
192: }
193: PetscMPIIntCast(N,&len);
194: MPIU_Allreduce(work1,work2,len,MPIU_SCALAR,MPIU_SUM,PetscObjectComm((PetscObject)B));
195: VecGetOwnershipRange(ctx->diag,&start,&end);
196: VecGetArrayWrite(ctx->diag,&diag);
197: for (i=start;i<end;i++) diag[i-start] = work2[i];
198: VecRestoreArrayWrite(ctx->diag,&diag);
199: PetscFree2(work1,work2);
200: }
201: VecCopy(ctx->diag,ctx->y2);
202: VecResetArray(ctx->y2);
203: VecRestoreArrayWrite(d,&pd);
204: return 0;
205: }
207: static PetscErrorCode MatDestroy_ECross(Mat B)
208: {
209: SVD_CYCLIC_SHELL *ctx;
211: MatShellGetContext(B,&ctx);
212: VecDestroy(&ctx->x1);
213: VecDestroy(&ctx->x2);
214: VecDestroy(&ctx->y1);
215: VecDestroy(&ctx->y2);
216: VecDestroy(&ctx->diag);
217: VecDestroy(&ctx->w);
218: PetscFree(ctx);
219: return 0;
220: }
222: /*
223: Builds extended cross product matrix C = | I_m 0 |
224: | 0 AT*A |
225: t is an auxiliary Vec used to take the dimensions of the upper block
226: */
227: static PetscErrorCode SVDCyclicGetECrossMat(SVD svd,Mat A,Mat AT,Mat *C,Vec t)
228: {
229: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
230: SVD_CYCLIC_SHELL *ctx;
231: PetscInt i,M,N,m,n,Istart,Iend;
232: VecType vtype;
233: Mat Id,Zm,Zn,ATA;
234: #if defined(PETSC_HAVE_CUDA)
235: PetscBool cuda;
236: #endif
238: MatGetSize(A,NULL,&N);
239: MatGetLocalSize(A,NULL,&n);
240: VecGetSize(t,&M);
241: VecGetLocalSize(t,&m);
243: if (cyclic->explicitmatrix) {
245: MatCreateConstantDiagonal(PetscObjectComm((PetscObject)svd),m,m,M,M,1.0,&Id);
246: MatCreate(PetscObjectComm((PetscObject)svd),&Zm);
247: MatSetSizes(Zm,m,n,M,N);
248: MatSetFromOptions(Zm);
249: MatSetUp(Zm);
250: MatGetOwnershipRange(Zm,&Istart,&Iend);
251: for (i=Istart;i<Iend;i++) {
252: if (i<N) MatSetValue(Zm,i,i,0.0,INSERT_VALUES);
253: }
254: MatAssemblyBegin(Zm,MAT_FINAL_ASSEMBLY);
255: MatAssemblyEnd(Zm,MAT_FINAL_ASSEMBLY);
256: MatCreate(PetscObjectComm((PetscObject)svd),&Zn);
257: MatSetSizes(Zn,n,m,N,M);
258: MatSetFromOptions(Zn);
259: MatSetUp(Zn);
260: MatGetOwnershipRange(Zn,&Istart,&Iend);
261: for (i=Istart;i<Iend;i++) {
262: if (i<m) MatSetValue(Zn,i,i,0.0,INSERT_VALUES);
263: }
264: MatAssemblyBegin(Zn,MAT_FINAL_ASSEMBLY);
265: MatAssemblyEnd(Zn,MAT_FINAL_ASSEMBLY);
266: MatProductCreate(AT,A,NULL,&ATA);
267: MatProductSetType(ATA,MATPRODUCT_AB);
268: MatProductSetFromOptions(ATA);
269: MatProductSymbolic(ATA);
270: MatProductNumeric(ATA);
271: MatCreateTile(1.0,Id,1.0,Zm,1.0,Zn,1.0,ATA,C);
272: MatDestroy(&Id);
273: MatDestroy(&Zm);
274: MatDestroy(&Zn);
275: MatDestroy(&ATA);
276: } else {
277: PetscNew(&ctx);
278: ctx->A = A;
279: ctx->AT = AT;
280: ctx->swapped = svd->swapped;
281: VecDuplicateEmpty(t,&ctx->x1);
282: VecDuplicateEmpty(t,&ctx->y1);
283: MatCreateVecsEmpty(A,&ctx->x2,NULL);
284: MatCreateVecsEmpty(A,&ctx->y2,NULL);
285: MatCreateVecs(A,NULL,&ctx->w);
286: MatCreateShell(PetscObjectComm((PetscObject)svd),m+n,m+n,M+N,M+N,ctx,C);
287: MatShellSetOperation(*C,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_ECross);
288: MatShellSetOperation(*C,MATOP_DESTROY,(void(*)(void))MatDestroy_ECross);
289: #if defined(PETSC_HAVE_CUDA)
290: PetscObjectTypeCompareAny((PetscObject)(svd->swapped?AT:A),&cuda,MATSEQAIJCUSPARSE,MATMPIAIJCUSPARSE,"");
291: if (cuda) MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_ECross_CUDA);
292: else
293: #endif
294: MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_ECross);
295: MatGetVecType(A,&vtype);
296: MatSetVecType(*C,vtype);
297: }
298: return 0;
299: }
301: /* Convergence test relative to the norm of R (used in GSVD only) */
302: static PetscErrorCode EPSConv_Cyclic(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
303: {
304: SVD svd = (SVD)ctx;
306: *errest = res/PetscMax(svd->nrma,svd->nrmb);
307: return 0;
308: }
310: PetscErrorCode SVDSetUp_Cyclic(SVD svd)
311: {
312: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
313: PetscInt M,N,m,n,p,k,i,isl,offset,nev,ncv,mpd,maxit;
314: PetscReal tol;
315: const PetscScalar *isa,*oa;
316: PetscScalar *va;
317: EPSProblemType ptype;
318: PetscBool trackall,issinv;
319: Vec v,t;
320: ST st;
321: Mat Omega;
322: MatType Atype;
324: MatGetSize(svd->A,&M,&N);
325: MatGetLocalSize(svd->A,&m,&n);
326: if (!cyclic->eps) SVDCyclicGetEPS(svd,&cyclic->eps);
327: MatDestroy(&cyclic->C);
328: MatDestroy(&cyclic->D);
329: if (svd->isgeneralized) {
330: if (svd->which==SVD_SMALLEST) { /* alternative pencil */
331: MatCreateVecs(svd->B,NULL,&t);
332: SVDCyclicGetCyclicMat(svd,svd->B,svd->BT,&cyclic->C);
333: SVDCyclicGetECrossMat(svd,svd->A,svd->AT,&cyclic->D,t);
334: } else {
335: MatCreateVecs(svd->A,NULL,&t);
336: SVDCyclicGetCyclicMat(svd,svd->A,svd->AT,&cyclic->C);
337: SVDCyclicGetECrossMat(svd,svd->B,svd->BT,&cyclic->D,t);
338: }
339: VecDestroy(&t);
340: EPSSetOperators(cyclic->eps,cyclic->C,cyclic->D);
341: EPSGetProblemType(cyclic->eps,&ptype);
342: if (!ptype) EPSSetProblemType(cyclic->eps,EPS_GHEP);
343: } else if (svd->ishyperbolic) {
344: SVDCyclicGetCyclicMat(svd,svd->A,svd->AT,&cyclic->C);
345: MatCreateVecs(cyclic->C,&v,NULL);
346: VecSet(v,1.0);
347: VecGetArrayRead(svd->omega,&oa);
348: VecGetArray(v,&va);
349: if (svd->swapped) PetscArraycpy(va+m,oa,n);
350: else PetscArraycpy(va,oa,m);
351: VecRestoreArrayRead(svd->omega,&oa);
352: VecRestoreArray(v,&va);
353: MatGetType(svd->OP,&Atype);
354: MatCreate(PetscObjectComm((PetscObject)svd),&Omega);
355: MatSetSizes(Omega,m+n,m+n,M+N,M+N);
356: MatSetType(Omega,Atype);
357: MatSetUp(Omega);
358: MatDiagonalSet(Omega,v,INSERT_VALUES);
359: EPSSetOperators(cyclic->eps,cyclic->C,Omega);
360: EPSSetProblemType(cyclic->eps,EPS_GHIEP);
361: MatDestroy(&Omega);
362: VecDestroy(&v);
363: } else {
364: SVDCyclicGetCyclicMat(svd,svd->A,svd->AT,&cyclic->C);
365: EPSSetOperators(cyclic->eps,cyclic->C,NULL);
366: EPSSetProblemType(cyclic->eps,EPS_HEP);
367: }
368: if (!cyclic->usereps) {
369: if (svd->which == SVD_LARGEST) {
370: EPSGetST(cyclic->eps,&st);
371: PetscObjectTypeCompare((PetscObject)st,STSINVERT,&issinv);
372: if (issinv) EPSSetWhichEigenpairs(cyclic->eps,EPS_TARGET_MAGNITUDE);
373: else if (svd->ishyperbolic) EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_MAGNITUDE);
374: else EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
375: } else {
376: if (svd->isgeneralized) { /* computes sigma^{-1} via alternative pencil */
377: EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
378: } else {
379: if (svd->ishyperbolic) EPSSetWhichEigenpairs(cyclic->eps,EPS_TARGET_MAGNITUDE);
380: else EPSSetEigenvalueComparison(cyclic->eps,SlepcCompareSmallestPosReal,NULL);
381: EPSSetTarget(cyclic->eps,0.0);
382: }
383: }
384: EPSGetDimensions(cyclic->eps,&nev,&ncv,&mpd);
386: nev = PetscMax(nev,2*svd->nsv);
387: if (ncv==PETSC_DEFAULT && svd->ncv!=PETSC_DEFAULT) ncv = PetscMax(3*svd->nsv,svd->ncv);
388: if (mpd==PETSC_DEFAULT && svd->mpd!=PETSC_DEFAULT) mpd = svd->mpd;
389: EPSSetDimensions(cyclic->eps,nev,ncv,mpd);
390: EPSGetTolerances(cyclic->eps,&tol,&maxit);
391: if (tol==PETSC_DEFAULT) tol = svd->tol==PETSC_DEFAULT? SLEPC_DEFAULT_TOL/10.0: svd->tol;
392: if (maxit==PETSC_DEFAULT && svd->max_it!=PETSC_DEFAULT) maxit = svd->max_it;
393: EPSSetTolerances(cyclic->eps,tol,maxit);
394: switch (svd->conv) {
395: case SVD_CONV_ABS:
396: EPSSetConvergenceTest(cyclic->eps,EPS_CONV_ABS);break;
397: case SVD_CONV_REL:
398: EPSSetConvergenceTest(cyclic->eps,EPS_CONV_REL);break;
399: case SVD_CONV_NORM:
400: if (svd->isgeneralized) {
401: if (!svd->nrma) MatNorm(svd->OP,NORM_INFINITY,&svd->nrma);
402: if (!svd->nrmb) MatNorm(svd->OPb,NORM_INFINITY,&svd->nrmb);
403: EPSSetConvergenceTestFunction(cyclic->eps,EPSConv_Cyclic,svd,NULL);
404: } else {
405: EPSSetConvergenceTest(cyclic->eps,EPS_CONV_NORM);break;
406: }
407: break;
408: case SVD_CONV_MAXIT:
409: SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Maxit convergence test not supported in this solver");
410: case SVD_CONV_USER:
411: SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"User-defined convergence test not supported in this solver");
412: }
413: }
414: SVDCheckUnsupported(svd,SVD_FEATURE_STOPPING);
415: /* Transfer the trackall option from svd to eps */
416: SVDGetTrackAll(svd,&trackall);
417: EPSSetTrackAll(cyclic->eps,trackall);
418: /* Transfer the initial subspace from svd to eps */
419: if (svd->nini<0 || svd->ninil<0) {
420: for (i=0;i<-PetscMin(svd->nini,svd->ninil);i++) {
421: MatCreateVecs(cyclic->C,&v,NULL);
422: VecGetArrayWrite(v,&va);
423: if (svd->isgeneralized) MatGetLocalSize(svd->B,&p,NULL);
424: k = (svd->isgeneralized && svd->which==SVD_SMALLEST)? p: m; /* size of upper block row */
425: if (i<-svd->ninil) {
426: VecGetArrayRead(svd->ISL[i],&isa);
427: if (svd->isgeneralized) {
428: VecGetLocalSize(svd->ISL[i],&isl);
430: offset = (svd->which==SVD_SMALLEST)? m: 0;
431: PetscArraycpy(va,isa+offset,k);
432: } else {
433: VecGetLocalSize(svd->ISL[i],&isl);
435: PetscArraycpy(va,isa,k);
436: }
437: VecRestoreArrayRead(svd->IS[i],&isa);
438: } else PetscArrayzero(&va,k);
439: if (i<-svd->nini) {
440: VecGetLocalSize(svd->IS[i],&isl);
442: VecGetArrayRead(svd->IS[i],&isa);
443: PetscArraycpy(va+k,isa,n);
444: VecRestoreArrayRead(svd->IS[i],&isa);
445: } else PetscArrayzero(va+k,n);
446: VecRestoreArrayWrite(v,&va);
447: VecDestroy(&svd->IS[i]);
448: svd->IS[i] = v;
449: }
450: svd->nini = PetscMin(svd->nini,svd->ninil);
451: EPSSetInitialSpace(cyclic->eps,-svd->nini,svd->IS);
452: SlepcBasisDestroy_Private(&svd->nini,&svd->IS);
453: SlepcBasisDestroy_Private(&svd->ninil,&svd->ISL);
454: }
455: EPSSetUp(cyclic->eps);
456: EPSGetDimensions(cyclic->eps,NULL,&svd->ncv,&svd->mpd);
457: svd->ncv = PetscMin(svd->ncv,PetscMin(M,N));
458: EPSGetTolerances(cyclic->eps,NULL,&svd->max_it);
459: if (svd->tol==PETSC_DEFAULT) svd->tol = SLEPC_DEFAULT_TOL;
461: svd->leftbasis = PETSC_TRUE;
462: SVDAllocateSolution(svd,0);
463: return 0;
464: }
466: PetscErrorCode SVDCyclicCheckEigenvalue(SVD svd,PetscScalar er,PetscScalar ei,PetscReal *sigma,PetscBool *isreal)
467: {
468: if (svd->ishyperbolic && PetscDefined(USE_COMPLEX) && PetscAbsReal(PetscImaginaryPart(er))>10*PetscAbsReal(PetscRealPart(er))) {
469: *sigma = PetscImaginaryPart(er);
470: if (isreal) *isreal = PETSC_FALSE;
471: } else if (svd->ishyperbolic && !PetscDefined(USE_COMPLEX) && PetscAbsScalar(ei)>10*PetscAbsScalar(er)) {
472: *sigma = PetscRealPart(ei);
473: if (isreal) *isreal = PETSC_FALSE;
474: } else {
475: *sigma = PetscRealPart(er);
476: if (isreal) *isreal = PETSC_TRUE;
477: }
478: return 0;
479: }
481: PetscErrorCode SVDSolve_Cyclic(SVD svd)
482: {
483: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
484: PetscInt i,j,nconv;
485: PetscScalar er,ei;
486: PetscReal sigma;
488: EPSSolve(cyclic->eps);
489: EPSGetConverged(cyclic->eps,&nconv);
490: EPSGetIterationNumber(cyclic->eps,&svd->its);
491: EPSGetConvergedReason(cyclic->eps,(EPSConvergedReason*)&svd->reason);
492: for (i=0,j=0;i<nconv;i++) {
493: EPSGetEigenvalue(cyclic->eps,i,&er,&ei);
494: SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL);
495: if (sigma>0.0) {
496: if (svd->isgeneralized && svd->which==SVD_SMALLEST) svd->sigma[j] = 1.0/sigma;
497: else svd->sigma[j] = sigma;
498: j++;
499: }
500: }
501: svd->nconv = j;
502: return 0;
503: }
505: static PetscErrorCode SVDComputeVectors_Cyclic_Standard(SVD svd)
506: {
507: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
508: PetscInt i,j,m,nconv;
509: PetscScalar er,ei;
510: PetscReal sigma;
511: const PetscScalar *px;
512: Vec x,x1,x2;
514: MatCreateVecs(cyclic->C,&x,NULL);
515: MatGetLocalSize(svd->A,&m,NULL);
516: MatCreateVecsEmpty(svd->A,&x2,&x1);
517: EPSGetConverged(cyclic->eps,&nconv);
518: for (i=0,j=0;i<nconv;i++) {
519: EPSGetEigenpair(cyclic->eps,i,&er,&ei,x,NULL);
520: SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL);
521: if (sigma<0.0) continue;
522: VecGetArrayRead(x,&px);
523: VecPlaceArray(x1,px);
524: VecPlaceArray(x2,px+m);
525: BVInsertVec(svd->U,j,x1);
526: BVScaleColumn(svd->U,j,PETSC_SQRT2);
527: BVInsertVec(svd->V,j,x2);
528: BVScaleColumn(svd->V,j,PETSC_SQRT2);
529: VecResetArray(x1);
530: VecResetArray(x2);
531: VecRestoreArrayRead(x,&px);
532: j++;
533: }
534: VecDestroy(&x);
535: VecDestroy(&x1);
536: VecDestroy(&x2);
537: return 0;
538: }
540: static PetscErrorCode SVDComputeVectors_Cyclic_Generalized(SVD svd)
541: {
542: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
543: PetscInt i,j,m,p,nconv;
544: PetscScalar *dst,er,ei;
545: PetscReal sigma;
546: const PetscScalar *src,*px;
547: Vec u,v,x,x1,x2,uv;
549: MatGetLocalSize(svd->A,&m,NULL);
550: MatGetLocalSize(svd->B,&p,NULL);
551: MatCreateVecs(cyclic->C,&x,NULL);
552: if (svd->which==SVD_SMALLEST) MatCreateVecsEmpty(svd->B,&x1,&x2);
553: else MatCreateVecsEmpty(svd->A,&x2,&x1);
554: MatCreateVecs(svd->A,NULL,&u);
555: MatCreateVecs(svd->B,NULL,&v);
556: EPSGetConverged(cyclic->eps,&nconv);
557: for (i=0,j=0;i<nconv;i++) {
558: EPSGetEigenpair(cyclic->eps,i,&er,&ei,x,NULL);
559: SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL);
560: if (sigma<0.0) continue;
561: if (svd->which==SVD_SMALLEST) {
562: /* evec_i = 1/sqrt(2)*[ v_i; w_i ], w_i = x_i/c_i */
563: VecGetArrayRead(x,&px);
564: VecPlaceArray(x2,px);
565: VecPlaceArray(x1,px+p);
566: VecCopy(x2,v);
567: VecScale(v,PETSC_SQRT2); /* v_i = sqrt(2)*evec_i_1 */
568: VecScale(x1,PETSC_SQRT2); /* w_i = sqrt(2)*evec_i_2 */
569: MatMult(svd->A,x1,u); /* A*w_i = u_i */
570: VecScale(x1,1.0/PetscSqrtScalar(1.0+sigma*sigma)); /* x_i = w_i*c_i */
571: BVInsertVec(svd->V,j,x1);
572: VecResetArray(x2);
573: VecResetArray(x1);
574: VecRestoreArrayRead(x,&px);
575: } else {
576: /* evec_i = 1/sqrt(2)*[ u_i; w_i ], w_i = x_i/s_i */
577: VecGetArrayRead(x,&px);
578: VecPlaceArray(x1,px);
579: VecPlaceArray(x2,px+m);
580: VecCopy(x1,u);
581: VecScale(u,PETSC_SQRT2); /* u_i = sqrt(2)*evec_i_1 */
582: VecScale(x2,PETSC_SQRT2); /* w_i = sqrt(2)*evec_i_2 */
583: MatMult(svd->B,x2,v); /* B*w_i = v_i */
584: VecScale(x2,1.0/PetscSqrtScalar(1.0+sigma*sigma)); /* x_i = w_i*s_i */
585: BVInsertVec(svd->V,j,x2);
586: VecResetArray(x1);
587: VecResetArray(x2);
588: VecRestoreArrayRead(x,&px);
589: }
590: /* copy [u;v] to U[j] */
591: BVGetColumn(svd->U,j,&uv);
592: VecGetArrayWrite(uv,&dst);
593: VecGetArrayRead(u,&src);
594: PetscArraycpy(dst,src,m);
595: VecRestoreArrayRead(u,&src);
596: VecGetArrayRead(v,&src);
597: PetscArraycpy(dst+m,src,p);
598: VecRestoreArrayRead(v,&src);
599: VecRestoreArrayWrite(uv,&dst);
600: BVRestoreColumn(svd->U,j,&uv);
601: j++;
602: }
603: VecDestroy(&x);
604: VecDestroy(&x1);
605: VecDestroy(&x2);
606: VecDestroy(&u);
607: VecDestroy(&v);
608: return 0;
609: }
611: #if defined(PETSC_USE_COMPLEX)
612: /* VecMaxAbs: returns the entry of x that has max(abs(x(i))), using w as a workspace vector */
613: static PetscErrorCode VecMaxAbs(Vec x,Vec w,PetscScalar *v)
614: {
615: PetscMPIInt size,rank,root;
616: const PetscScalar *xx;
617: const PetscInt *ranges;
618: PetscReal val;
619: PetscInt p;
621: VecCopy(x,w);
622: VecAbs(w);
623: VecMax(w,&p,&val);
624: MPI_Comm_size(PetscObjectComm((PetscObject)x),&size);
625: MPI_Comm_rank(PetscObjectComm((PetscObject)x),&rank);
626: VecGetOwnershipRanges(x,&ranges);
627: for (root=0;root<size;root++) if (p>=ranges[root] && p<ranges[root+1]) break;
628: if (rank==root) {
629: VecGetArrayRead(x,&xx);
630: *v = xx[p-ranges[root]];
631: VecRestoreArrayRead(x,&xx);
632: }
633: MPI_Bcast(v,1,MPIU_SCALAR,root,PetscObjectComm((PetscObject)x));
634: return 0;
635: }
636: #endif
638: static PetscErrorCode SVDComputeVectors_Cyclic_Hyperbolic(SVD svd)
639: {
640: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
641: PetscInt i,j,m,n,N,nconv;
642: PetscScalar er,ei;
643: PetscReal sigma,nrm;
644: PetscBool isreal;
645: const PetscScalar *px;
646: Vec u,x,xi=NULL,x1,x2,x1i=NULL,x2i;
647: Mat Omega;
648: MatType Atype;
649: BV U=NULL,V=NULL;
650: #if !defined(PETSC_USE_COMPLEX)
651: const PetscScalar *pxi;
652: PetscReal nrmr,nrmi;
653: #else
654: PetscScalar alpha;
655: #endif
657: MatCreateVecs(cyclic->C,&x,svd->ishyperbolic?&xi:NULL);
658: MatGetLocalSize(svd->A,&m,NULL);
659: MatCreateVecsEmpty(svd->OP,&x2,&x1);
660: #if defined(PETSC_USE_COMPLEX)
661: MatCreateVecs(svd->OP,&x2i,&x1i);
662: #else
663: MatCreateVecsEmpty(svd->OP,&x2i,&x1i);
664: #endif
665: /* set-up Omega-normalization of U */
666: U = svd->swapped? svd->V: svd->U;
667: V = svd->swapped? svd->U: svd->V;
668: MatGetType(svd->A,&Atype);
669: BVGetSizes(U,&n,&N,NULL);
670: MatCreate(PetscObjectComm((PetscObject)svd),&Omega);
671: MatSetSizes(Omega,n,n,N,N);
672: MatSetType(Omega,Atype);
673: MatSetUp(Omega);
674: MatDiagonalSet(Omega,svd->omega,INSERT_VALUES);
675: BVSetMatrix(U,Omega,PETSC_TRUE);
676: MatDestroy(&Omega);
678: EPSGetConverged(cyclic->eps,&nconv);
679: for (i=0,j=0;i<nconv;i++) {
680: EPSGetEigenpair(cyclic->eps,i,&er,&ei,x,xi);
681: SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,&isreal);
682: if (sigma<0.0) continue;
683: VecGetArrayRead(x,&px);
684: if (svd->swapped) {
685: VecPlaceArray(x2,px);
686: VecPlaceArray(x1,px+m);
687: } else {
688: VecPlaceArray(x1,px);
689: VecPlaceArray(x2,px+n);
690: }
691: #if defined(PETSC_USE_COMPLEX)
692: BVInsertVec(U,j,x1);
693: BVInsertVec(V,j,x2);
694: if (!isreal) {
695: VecMaxAbs(x1,x1i,&alpha);
696: BVScaleColumn(U,j,PetscAbsScalar(alpha)/alpha);
697: BVScaleColumn(V,j,PetscAbsScalar(alpha)/(alpha*PETSC_i));
698: }
699: #else
700: VecGetArrayRead(xi,&pxi);
701: if (svd->swapped) {
702: VecPlaceArray(x2i,pxi);
703: VecPlaceArray(x1i,pxi+m);
704: } else {
705: VecPlaceArray(x1i,pxi);
706: VecPlaceArray(x2i,pxi+n);
707: }
708: VecNorm(x2,NORM_2,&nrmr);
709: VecNorm(x2i,NORM_2,&nrmi);
710: if (nrmi>nrmr) {
711: if (isreal) {
712: BVInsertVec(U,j,x1i);
713: BVInsertVec(V,j,x2i);
714: } else {
715: BVInsertVec(U,j,x1);
716: BVInsertVec(V,j,x2i);
717: }
718: } else {
719: if (isreal) {
720: BVInsertVec(U,j,x1);
721: BVInsertVec(V,j,x2);
722: } else {
723: BVInsertVec(U,j,x1i);
724: BVScaleColumn(U,j,-1.0);
725: BVInsertVec(V,j,x2);
726: }
727: }
728: VecResetArray(x1i);
729: VecResetArray(x2i);
730: VecRestoreArrayRead(xi,&pxi);
731: #endif
732: VecResetArray(x1);
733: VecResetArray(x2);
734: VecRestoreArrayRead(x,&px);
735: BVGetColumn(U,j,&u);
736: VecPointwiseMult(u,u,svd->omega);
737: BVRestoreColumn(U,j,&u);
738: BVNormColumn(U,j,NORM_2,&nrm);
739: BVScaleColumn(U,j,1.0/PetscAbs(nrm));
740: svd->sign[j] = PetscSign(nrm);
741: BVNormColumn(V,j,NORM_2,&nrm);
742: BVScaleColumn(V,j,1.0/nrm);
743: j++;
744: }
745: VecDestroy(&x);
746: VecDestroy(&x1);
747: VecDestroy(&x2);
748: VecDestroy(&xi);
749: VecDestroy(&x1i);
750: VecDestroy(&x2i);
751: return 0;
752: }
754: PetscErrorCode SVDComputeVectors_Cyclic(SVD svd)
755: {
756: switch (svd->problem_type) {
757: case SVD_STANDARD:
758: SVDComputeVectors_Cyclic_Standard(svd);
759: break;
760: case SVD_GENERALIZED:
761: SVDComputeVectors_Cyclic_Generalized(svd);
762: break;
763: case SVD_HYPERBOLIC:
764: SVDComputeVectors_Cyclic_Hyperbolic(svd);
765: break;
766: default:
767: SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_WRONG,"Unknown singular value problem type");
768: }
769: return 0;
770: }
772: static PetscErrorCode EPSMonitor_Cyclic(EPS eps,PetscInt its,PetscInt nconv,PetscScalar *eigr,PetscScalar *eigi,PetscReal *errest,PetscInt nest,void *ctx)
773: {
774: PetscInt i,j;
775: SVD svd = (SVD)ctx;
776: PetscScalar er,ei;
777: PetscReal sigma;
778: ST st;
780: nconv = 0;
781: EPSGetST(eps,&st);
782: for (i=0,j=0;i<PetscMin(nest,svd->ncv);i++) {
783: er = eigr[i]; ei = eigi[i];
784: STBackTransform(st,1,&er,&ei);
785: SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL);
786: if (sigma>0.0) {
787: svd->sigma[j] = sigma;
788: svd->errest[j] = errest[i];
789: if (errest[i] && errest[i] < svd->tol) nconv++;
790: j++;
791: }
792: }
793: nest = j;
794: SVDMonitor(svd,its,nconv,svd->sigma,svd->errest,nest);
795: return 0;
796: }
798: PetscErrorCode SVDSetFromOptions_Cyclic(SVD svd,PetscOptionItems *PetscOptionsObject)
799: {
800: PetscBool set,val;
801: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
802: ST st;
804: PetscOptionsHeadBegin(PetscOptionsObject,"SVD Cyclic Options");
806: PetscOptionsBool("-svd_cyclic_explicitmatrix","Use cyclic explicit matrix","SVDCyclicSetExplicitMatrix",cyclic->explicitmatrix,&val,&set);
807: if (set) SVDCyclicSetExplicitMatrix(svd,val);
809: PetscOptionsHeadEnd();
811: if (!cyclic->eps) SVDCyclicGetEPS(svd,&cyclic->eps);
812: if (!cyclic->explicitmatrix && !cyclic->usereps) {
813: /* use as default an ST with shell matrix and Jacobi */
814: EPSGetST(cyclic->eps,&st);
815: STSetMatMode(st,ST_MATMODE_SHELL);
816: }
817: EPSSetFromOptions(cyclic->eps);
818: return 0;
819: }
821: static PetscErrorCode SVDCyclicSetExplicitMatrix_Cyclic(SVD svd,PetscBool explicitmat)
822: {
823: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
825: if (cyclic->explicitmatrix != explicitmat) {
826: cyclic->explicitmatrix = explicitmat;
827: svd->state = SVD_STATE_INITIAL;
828: }
829: return 0;
830: }
832: /*@
833: SVDCyclicSetExplicitMatrix - Indicate if the eigensolver operator
834: H(A) = [ 0 A ; A^T 0 ] must be computed explicitly.
836: Logically Collective on svd
838: Input Parameters:
839: + svd - singular value solver
840: - explicitmat - boolean flag indicating if H(A) is built explicitly
842: Options Database Key:
843: . -svd_cyclic_explicitmatrix <boolean> - Indicates the boolean flag
845: Level: advanced
847: .seealso: SVDCyclicGetExplicitMatrix()
848: @*/
849: PetscErrorCode SVDCyclicSetExplicitMatrix(SVD svd,PetscBool explicitmat)
850: {
853: PetscTryMethod(svd,"SVDCyclicSetExplicitMatrix_C",(SVD,PetscBool),(svd,explicitmat));
854: return 0;
855: }
857: static PetscErrorCode SVDCyclicGetExplicitMatrix_Cyclic(SVD svd,PetscBool *explicitmat)
858: {
859: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
861: *explicitmat = cyclic->explicitmatrix;
862: return 0;
863: }
865: /*@
866: SVDCyclicGetExplicitMatrix - Returns the flag indicating if H(A) is built explicitly.
868: Not Collective
870: Input Parameter:
871: . svd - singular value solver
873: Output Parameter:
874: . explicitmat - the mode flag
876: Level: advanced
878: .seealso: SVDCyclicSetExplicitMatrix()
879: @*/
880: PetscErrorCode SVDCyclicGetExplicitMatrix(SVD svd,PetscBool *explicitmat)
881: {
884: PetscUseMethod(svd,"SVDCyclicGetExplicitMatrix_C",(SVD,PetscBool*),(svd,explicitmat));
885: return 0;
886: }
888: static PetscErrorCode SVDCyclicSetEPS_Cyclic(SVD svd,EPS eps)
889: {
890: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
892: PetscObjectReference((PetscObject)eps);
893: EPSDestroy(&cyclic->eps);
894: cyclic->eps = eps;
895: cyclic->usereps = PETSC_TRUE;
896: svd->state = SVD_STATE_INITIAL;
897: return 0;
898: }
900: /*@
901: SVDCyclicSetEPS - Associate an eigensolver object (EPS) to the
902: singular value solver.
904: Collective on svd
906: Input Parameters:
907: + svd - singular value solver
908: - eps - the eigensolver object
910: Level: advanced
912: .seealso: SVDCyclicGetEPS()
913: @*/
914: PetscErrorCode SVDCyclicSetEPS(SVD svd,EPS eps)
915: {
919: PetscTryMethod(svd,"SVDCyclicSetEPS_C",(SVD,EPS),(svd,eps));
920: return 0;
921: }
923: static PetscErrorCode SVDCyclicGetEPS_Cyclic(SVD svd,EPS *eps)
924: {
925: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
927: if (!cyclic->eps) {
928: EPSCreate(PetscObjectComm((PetscObject)svd),&cyclic->eps);
929: PetscObjectIncrementTabLevel((PetscObject)cyclic->eps,(PetscObject)svd,1);
930: EPSSetOptionsPrefix(cyclic->eps,((PetscObject)svd)->prefix);
931: EPSAppendOptionsPrefix(cyclic->eps,"svd_cyclic_");
932: PetscObjectSetOptions((PetscObject)cyclic->eps,((PetscObject)svd)->options);
933: EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
934: EPSMonitorSet(cyclic->eps,EPSMonitor_Cyclic,svd,NULL);
935: }
936: *eps = cyclic->eps;
937: return 0;
938: }
940: /*@
941: SVDCyclicGetEPS - Retrieve the eigensolver object (EPS) associated
942: to the singular value solver.
944: Not Collective
946: Input Parameter:
947: . svd - singular value solver
949: Output Parameter:
950: . eps - the eigensolver object
952: Level: advanced
954: .seealso: SVDCyclicSetEPS()
955: @*/
956: PetscErrorCode SVDCyclicGetEPS(SVD svd,EPS *eps)
957: {
960: PetscUseMethod(svd,"SVDCyclicGetEPS_C",(SVD,EPS*),(svd,eps));
961: return 0;
962: }
964: PetscErrorCode SVDView_Cyclic(SVD svd,PetscViewer viewer)
965: {
966: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
967: PetscBool isascii;
969: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
970: if (isascii) {
971: if (!cyclic->eps) SVDCyclicGetEPS(svd,&cyclic->eps);
972: PetscViewerASCIIPrintf(viewer," %s matrix\n",cyclic->explicitmatrix?"explicit":"implicit");
973: PetscViewerASCIIPushTab(viewer);
974: EPSView(cyclic->eps,viewer);
975: PetscViewerASCIIPopTab(viewer);
976: }
977: return 0;
978: }
980: PetscErrorCode SVDReset_Cyclic(SVD svd)
981: {
982: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
984: EPSReset(cyclic->eps);
985: MatDestroy(&cyclic->C);
986: MatDestroy(&cyclic->D);
987: return 0;
988: }
990: PetscErrorCode SVDDestroy_Cyclic(SVD svd)
991: {
992: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
994: EPSDestroy(&cyclic->eps);
995: PetscFree(svd->data);
996: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",NULL);
997: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",NULL);
998: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",NULL);
999: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",NULL);
1000: return 0;
1001: }
1003: SLEPC_EXTERN PetscErrorCode SVDCreate_Cyclic(SVD svd)
1004: {
1005: SVD_CYCLIC *cyclic;
1007: PetscNew(&cyclic);
1008: svd->data = (void*)cyclic;
1009: svd->ops->solve = SVDSolve_Cyclic;
1010: svd->ops->solveg = SVDSolve_Cyclic;
1011: svd->ops->solveh = SVDSolve_Cyclic;
1012: svd->ops->setup = SVDSetUp_Cyclic;
1013: svd->ops->setfromoptions = SVDSetFromOptions_Cyclic;
1014: svd->ops->destroy = SVDDestroy_Cyclic;
1015: svd->ops->reset = SVDReset_Cyclic;
1016: svd->ops->view = SVDView_Cyclic;
1017: svd->ops->computevectors = SVDComputeVectors_Cyclic;
1018: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",SVDCyclicSetEPS_Cyclic);
1019: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",SVDCyclicGetEPS_Cyclic);
1020: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",SVDCyclicSetExplicitMatrix_Cyclic);
1021: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",SVDCyclicGetExplicitMatrix_Cyclic);
1022: return 0;
1023: }